v5.1.0 release

-----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl8ywicZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3s51D/sHWQ1lB6Gvqy0yTlmF8N6f
 PtdWBIO/4/X7ciNzszPiGQrfS3w/yDw4MPDm1Z9bVDqZnjdlXjr+AS7iEZ1pR6OP
 PYXha5f08nhMka+W+HLRSeVqcKLO2+CjUXz14Er4EJKnZ2sXk8dNfbU+ACG/lkKQ
 3fG6B6hVvElPyjeGLC08tarcmPZl4KPKOueQrZHahTJ77R+zNNfejK5qWCxGTTWg
 vDkWtzgGdAJOwOcBblwM7ZqGEZz0kIiCiwCzVNxidDjFKtUTzBamZ33ZDjEG7LJp
 TmxWHbtXOUGofL3ikvzJ335H2sOdePv+cubV8zgSYV0Anudm0KpHJnAofefpdw85
 CsucebO+PVqysNKLg5uXWUGfxRkwcT0f//ILFR0J9H9Ng6Oh4Pzqn8IhLKIUkFF6
 Id015V4fScNaZqhrNZBosL48zGbngpaiMw7tqsRa26SPwqnzXVLXureaMPEeaPoR
 X4eang2lDwKd7RslgigPWxzOST9abej/33moCgwLPT/Ivc8stNL94bVVrNJiglvM
 zOep6BIjaLgblHjMhDOuY+zx5n95CkBdSYynIy3IwWiuvh+abZVurjHR6YRu4Z8C
 7yRfnJKev/1rWO0DoXcXumgC4CFFQXBuI/ABm8LLpdcoJUYs+fF4pwZyUq8mb9LF
 RPoM6TLkV3HN4mityFZpEQ==
 =dBGu
 -----END PGP SIGNATURE-----

Merge tag 'v5.1.0' into merge-qemu-v5.1.0

v5.1.0 release
This commit is contained in:
Matt Borgerson 2020-08-25 12:11:26 -07:00
commit ed6d5e3e6d
2176 changed files with 109858 additions and 35294 deletions

View File

@ -3,40 +3,40 @@ env:
freebsd_12_task:
freebsd_instance:
image: freebsd-12-0-release-amd64
image_family: freebsd-12-1
cpu: 8
memory: 8G
install_script: pkg install -y
bash bison curl cyrus-sasl git glib gmake gnutls gsed
install_script: ASSUME_ALWAYS_YES=yes pkg bootstrap -f ; pkg install -y
bash curl cyrus-sasl git glib gmake gnutls gsed
nettle perl5 pixman pkgconf png usbredir
script:
- mkdir build
- cd build
- ../configure || { cat config.log; exit 1; }
- gmake -j8
- gmake -j8 V=1 check
- gmake V=1 check
macos_task:
osx_instance:
image: mojave-base
install_script:
- brew install pkg-config python gnu-sed glib pixman make sdl2
- brew install pkg-config python gnu-sed glib pixman make sdl2 bash
script:
- mkdir build
- cd build
- ../configure --python=/usr/local/bin/python3 || { cat config.log; exit 1; }
- gmake -j$(sysctl -n hw.ncpu)
- gmake check -j$(sysctl -n hw.ncpu)
- gmake check
macos_xcode_task:
osx_instance:
# this is an alias for the latest Xcode
image: mojave-xcode
install_script:
- brew install pkg-config gnu-sed glib pixman make sdl2
- brew install pkg-config gnu-sed glib pixman make sdl2 bash
script:
- mkdir build
- cd build
- ../configure --cc=clang || { cat config.log; exit 1; }
- gmake -j$(sysctl -n hw.ncpu)
- gmake check -j$(sysctl -n hw.ncpu)
- gmake check

18
.gitignore vendored
View File

@ -34,18 +34,18 @@
/qapi/qapi-builtin-types.[ch]
/qapi/qapi-builtin-visit.[ch]
/qapi/qapi-commands-*.[ch]
/qapi/qapi-commands.[ch]
/qapi/qapi-emit-events.[ch]
**/qapi/qapi-commands.[ch]
**/qapi/qapi-emit-events.[ch]
/qapi/qapi-events-*.[ch]
/qapi/qapi-events.[ch]
/qapi/qapi-init-commands.[ch]
/qapi/qapi-introspect.[ch]
**/qapi/qapi-events.[ch]
**/qapi/qapi-init-commands.[ch]
**/qapi/qapi-introspect.[ch]
/qapi/qapi-types-*.[ch]
/qapi/qapi-types.[ch]
**/qapi/qapi-types.[ch]
/qapi/qapi-visit-*.[ch]
!/qapi/qapi-visit-core.c
/qapi/qapi-visit.[ch]
/qapi/qapi-doc.texi
**/qapi/qapi-visit.[ch]
**/qapi/qapi-doc.texi
/qemu-edid
/qemu-img
/qemu-nbd
@ -59,6 +59,7 @@
/qemu-keymap
/qemu-monitor.texi
/qemu-monitor-info.texi
/qemu-storage-daemon
/qemu-version.h
/qemu-version.h.tmp
/module_block.h
@ -92,6 +93,7 @@
*.tp
*.vr
*.d
!/.gitlab-ci.d
!/scripts/qemu-guest-agent/fsfreeze-hook.d
*.o
.sdk

264
.gitlab-ci.d/containers.yml Normal file
View File

@ -0,0 +1,264 @@
.container_job_template: &container_job_definition
image: docker:stable
stage: containers
services:
- docker:dind
before_script:
- export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest"
- export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/$NAME:latest"
- apk add python3
- docker info
- docker login registry.gitlab.com -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
script:
- echo "TAG:$TAG"
- echo "COMMON_TAG:$COMMON_TAG"
- docker pull "$TAG" || docker pull "$COMMON_TAG" || true
- ./tests/docker/docker.py --engine docker build
-t "qemu/$NAME" -f "tests/docker/dockerfiles/$NAME.docker"
-r $CI_REGISTRY_IMAGE
- docker tag "qemu/$NAME" "$TAG"
- docker push "$TAG"
after_script:
- docker logout
rules:
- changes:
- .gitlab-ci.d/containers.yml
- tests/docker/*
- tests/docker/dockerfiles/*
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
- if: '$CI_COMMIT_REF_NAME == "testing/next"'
amd64-centos7-container:
<<: *container_job_definition
variables:
NAME: centos7
amd64-centos8-container:
<<: *container_job_definition
variables:
NAME: centos8
amd64-debian10-container:
<<: *container_job_definition
variables:
NAME: debian10
amd64-debian11-container:
<<: *container_job_definition
variables:
NAME: debian11
amd64-debian9-container:
<<: *container_job_definition
variables:
NAME: debian9
amd64-debian9-mxe-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian9-container']
variables:
NAME: debian9-mxe
alpha-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-alpha-cross
amd64-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-amd64-cross
amd64-debian-user-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-all-test-cross
amd64-debian-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-amd64
arm64-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-arm64-cross
arm64-test-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian11-container']
variables:
NAME: debian-arm64-test-cross
armel-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-armel-cross
armhf-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-armhf-cross
hppa-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-hppa-cross
m68k-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-m68k-cross
mips64-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-mips64-cross
mips64el-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-mips64el-cross
mips-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-mips-cross
mipsel-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-mipsel-cross
powerpc-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-powerpc-cross
ppc64-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-ppc64-cross
ppc64el-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-ppc64el-cross
riscv64-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-riscv64-cross
s390x-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-s390x-cross
sh4-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-sh4-cross
sparc64-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-sparc64-cross
tricore-debian-cross-container:
<<: *container_job_definition
stage: containers-layer2
needs: ['amd64-debian9-container']
variables:
NAME: debian-tricore-cross
win32-debian-cross-container:
<<: *container_job_definition
stage: containers-layer3
needs: ['amd64-debian9-mxe-container']
variables:
NAME: debian-win32-cross
win64-debian-cross-container:
<<: *container_job_definition
stage: containers-layer3
needs: ['amd64-debian9-mxe-container']
variables:
NAME: debian-win64-cross
xtensa-debian-cross-container:
<<: *container_job_definition
variables:
NAME: debian-xtensa-cross
cris-fedora-cross-container:
<<: *container_job_definition
variables:
NAME: fedora-cris-cross
amd64-fedora-container:
<<: *container_job_definition
variables:
NAME: fedora
i386-fedora-cross-container:
<<: *container_job_definition
variables:
NAME: fedora-i386-cross
amd64-ubuntu1804-container:
<<: *container_job_definition
variables:
NAME: ubuntu1804
amd64-ubuntu2004-container:
<<: *container_job_definition
variables:
NAME: ubuntu2004
amd64-ubuntu-container:
<<: *container_job_definition
variables:
NAME: ubuntu

View File

@ -1,8 +1,8 @@
docker-edk2:
stage: build
stage: containers
rules: # Only run this job when the Dockerfile is modified
- changes:
- .gitlab-ci-edk2.yml
- .gitlab-ci.d/edk2.yml
- .gitlab-ci.d/edk2/Dockerfile
when: always
image: docker:19.03.1
@ -24,6 +24,7 @@ docker-edk2:
- docker push $IMAGE_TAG
build-edk2:
stage: build
rules: # Only run this job when ...
- changes: # ... roms/edk2/ is modified (submodule updated)
- roms/edk2/*

View File

@ -1,8 +1,8 @@
docker-opensbi:
stage: build
stage: containers
rules: # Only run this job when the Dockerfile is modified
- changes:
- .gitlab-ci-opensbi.yml
- .gitlab-ci.d/opensbi.yml
- .gitlab-ci.d/opensbi/Dockerfile
when: always
image: docker:19.03.1
@ -24,6 +24,7 @@ docker-opensbi:
- docker push $IMAGE_TAG
build-opensbi:
stage: build
rules: # Only run this job when ...
- changes: # ... roms/opensbi/ is modified (submodule updated)
- roms/opensbi/*

View File

@ -1,104 +1,273 @@
# Currently we have two build stages after our containers are built:
# - build (for traditional build and test or first stage build)
# - test (for test stages, using build artefacts from a build stage)
stages:
- containers
- containers-layer2
- containers-layer3
- build
- test
# We assume GitLab has it's own caching set up for RPM/APT repositories so we
# just take care of avocado assets here.
cache:
paths:
- $HOME/avocado/data/cache
include:
- local: '/.gitlab-ci-edk2.yml'
- local: '/.gitlab-ci-opensbi.yml'
- local: '/.gitlab-ci.d/edk2.yml'
- local: '/.gitlab-ci.d/opensbi.yml'
- local: '/.gitlab-ci.d/containers.yml'
before_script:
- apt-get update -qq
- apt-get install -y -qq flex bison libglib2.0-dev libpixman-1-dev genisoimage
.native_build_job_template: &native_build_job_definition
stage: build
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
before_script:
- JOBS=$(expr $(nproc) + 1)
script:
- mkdir build
- cd build
- if test -n "$TARGETS";
then
../configure --enable-werror $CONFIGURE_ARGS --target-list="$TARGETS" ;
else
../configure --enable-werror $CONFIGURE_ARGS ;
fi
- make -j"$JOBS"
- if test -n "$MAKE_CHECK_ARGS";
then
make -j"$JOBS" $MAKE_CHECK_ARGS ;
fi
build-system1:
script:
- apt-get install -y -qq libgtk-3-dev libvte-dev nettle-dev libcacard-dev
libusb-dev libvde-dev libspice-protocol-dev libgl1-mesa-dev libvdeplug-dev
- mkdir build
- cd build
- ../configure --enable-werror --target-list="aarch64-softmmu alpha-softmmu
cris-softmmu hppa-softmmu lm32-softmmu moxie-softmmu microblazeel-softmmu
mips64el-softmmu m68k-softmmu ppc-softmmu riscv64-softmmu sparc-softmmu"
- make -j2
- make -j2 check
.native_test_job_template: &native_test_job_definition
stage: test
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
script:
- cd build
- find . -type f -exec touch {} +
- make $MAKE_CHECK_ARGS
build-system2:
script:
- apt-get install -y -qq libsdl2-dev libgcrypt-dev libbrlapi-dev libaio-dev
libfdt-dev liblzo2-dev librdmacm-dev libibverbs-dev libibumad-dev
libzstd-dev
- mkdir build
- cd build
- ../configure --enable-werror --target-list="tricore-softmmu unicore32-softmmu
microblaze-softmmu mips-softmmu riscv32-softmmu s390x-softmmu sh4-softmmu
sparc64-softmmu x86_64-softmmu xtensa-softmmu nios2-softmmu or1k-softmmu"
- make -j2
- make -j2 check
.acceptance_template: &acceptance_definition
cache:
key: "${CI_JOB_NAME}-cache"
paths:
- ${CI_PROJECT_DIR}/avocado-cache
policy: pull-push
before_script:
- mkdir -p ~/.config/avocado
- echo "[datadir.paths]" > ~/.config/avocado/avocado.conf
- echo "cache_dirs = ['${CI_PROJECT_DIR}/avocado-cache']"
>> ~/.config/avocado/avocado.conf
- if [ -d ${CI_PROJECT_DIR}/avocado-cache ]; then
du -chs ${CI_PROJECT_DIR}/avocado-cache ;
fi
after_script:
- cd build
- python3 -c 'import json; r = json.load(open("tests/results/latest/results.json")); [print(t["logfile"]) for t in r["tests"] if t["status"] not in ("PASS", "SKIP")]' | xargs cat
- du -chs ${CI_PROJECT_DIR}/avocado-cache
build-system-ubuntu:
<<: *native_build_job_definition
variables:
IMAGE: ubuntu2004
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
moxie-softmmu microblazeel-softmmu mips64el-softmmu
MAKE_CHECK_ARGS: check-build
artifacts:
paths:
- build
check-system-ubuntu:
<<: *native_test_job_definition
needs:
- job: build-system-ubuntu
artifacts: true
variables:
IMAGE: ubuntu2004
MAKE_CHECK_ARGS: check
acceptance-system-ubuntu:
<<: *native_test_job_definition
needs:
- job: build-system-ubuntu
artifacts: true
variables:
IMAGE: ubuntu2004
MAKE_CHECK_ARGS: check-acceptance
<<: *acceptance_definition
build-system-debian:
<<: *native_build_job_definition
variables:
IMAGE: debian-amd64
TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu
riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu
MAKE_CHECK_ARGS: check-build
artifacts:
paths:
- build
check-system-debian:
<<: *native_test_job_definition
needs:
- job: build-system-debian
artifacts: true
variables:
IMAGE: debian-amd64
MAKE_CHECK_ARGS: check
acceptance-system-debian:
<<: *native_test_job_definition
needs:
- job: build-system-debian
artifacts: true
variables:
IMAGE: debian-amd64
MAKE_CHECK_ARGS: check-acceptance
<<: *acceptance_definition
build-system-fedora:
<<: *native_build_job_definition
variables:
IMAGE: fedora
TARGETS: tricore-softmmu unicore32-softmmu microblaze-softmmu mips-softmmu
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
MAKE_CHECK_ARGS: check-build
artifacts:
paths:
- build
check-system-fedora:
<<: *native_test_job_definition
needs:
- job: build-system-fedora
artifacts: true
variables:
IMAGE: fedora
MAKE_CHECK_ARGS: check
acceptance-system-fedora:
<<: *native_test_job_definition
needs:
- job: build-system-fedora
artifacts: true
variables:
IMAGE: fedora
MAKE_CHECK_ARGS: check-acceptance
<<: *acceptance_definition
build-system-centos:
<<: *native_build_job_definition
variables:
IMAGE: centos8
TARGETS: ppc64-softmmu lm32-softmmu or1k-softmmu s390x-softmmu
x86_64-softmmu rx-softmmu sh4-softmmu nios2-softmmu
MAKE_CHECK_ARGS: check-build
artifacts:
paths:
- build
check-system-centos:
<<: *native_test_job_definition
needs:
- job: build-system-centos
artifacts: true
variables:
IMAGE: centos8
MAKE_CHECK_ARGS: check
acceptance-system-centos:
<<: *native_test_job_definition
needs:
- job: build-system-centos
artifacts: true
variables:
IMAGE: centos8
MAKE_CHECK_ARGS: check-acceptance
<<: *acceptance_definition
build-disabled:
script:
- mkdir build
- cd build
- ../configure --enable-werror --disable-rdma --disable-slirp --disable-curl
<<: *native_build_job_definition
variables:
IMAGE: fedora
CONFIGURE_ARGS: --disable-rdma --disable-slirp --disable-curl
--disable-capstone --disable-live-block-migration --disable-glusterfs
--disable-replication --disable-coroutine-pool --disable-smartcard
--disable-guest-agent --disable-curses --disable-libxml2 --disable-tpm
--disable-qom-cast-debug --disable-spice --disable-vhost-vsock
--disable-vhost-net --disable-vhost-crypto --disable-vhost-user
--target-list="i386-softmmu ppc64-softmmu mips64-softmmu i386-linux-user"
- make -j2
- make -j2 check-qtest SPEED=slow
TARGETS: i386-softmmu ppc64-softmmu mips64-softmmu i386-linux-user
MAKE_CHECK_ARGS: check-qtest SPEED=slow
build-tcg-disabled:
script:
- apt-get install -y -qq clang libgtk-3-dev libusb-dev
- mkdir build
- cd build
- ../configure --cc=clang --enable-werror --disable-tcg --audio-drv-list=""
- make -j2
- make check-unit
- make check-qapi-schema
- cd tests/qemu-iotests/
- ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048
<<: *native_build_job_definition
variables:
IMAGE: centos8
script:
- mkdir build
- cd build
- ../configure --disable-tcg --audio-drv-list=""
- make -j"$JOBS"
- make check-unit
- make check-qapi-schema
- cd tests/qemu-iotests/
- ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048
052 063 077 086 101 104 106 113 148 150 151 152 157 159 160 163
170 171 183 184 192 194 197 208 215 221 222 226 227 236 253 277
- ./check -qcow2 028 051 056 057 058 065 067 068 082 085 091 095 096 102 122
- ./check -qcow2 028 051 056 057 058 065 067 068 082 085 091 095 096 102 122
124 132 139 142 144 145 151 152 155 157 165 194 196 197 200 202
208 209 215 216 218 222 227 234 246 247 248 250 254 255 257 258
260 261 262 263 264 270 272 273 277 279
build-user:
script:
- mkdir build
- cd build
- ../configure --enable-werror --disable-system --disable-guest-agent
--disable-capstone --disable-slirp --disable-fdt
- make -j2
- make run-tcg-tests-i386-linux-user run-tcg-tests-x86_64-linux-user
<<: *native_build_job_definition
variables:
IMAGE: debian-all-test-cross
CONFIGURE_ARGS: --disable-tools --disable-system
MAKE_CHECK_ARGS: check-tcg
build-clang:
script:
- apt-get install -y -qq clang libsdl2-dev libattr1-dev libcap-ng-dev
xfslibs-dev libiscsi-dev libnfs-dev libseccomp-dev gnutls-dev librbd-dev
- mkdir build
- cd build
- ../configure --cc=clang --cxx=clang++ --enable-werror
--target-list="alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu
ppc-softmmu s390x-softmmu x86_64-softmmu arm-linux-user"
- make -j2
- make -j2 check
<<: *native_build_job_definition
variables:
IMAGE: fedora
CONFIGURE_ARGS: --cc=clang --cxx=clang++
TARGETS: alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu
ppc-softmmu s390x-softmmu arm-linux-user
MAKE_CHECK_ARGS: check
build-oss-fuzz:
<<: *native_build_job_definition
variables:
IMAGE: fedora
script:
- mkdir build-oss-fuzz
- CC="clang" CXX="clang++" CFLAGS="-fsanitize=address"
./scripts/oss-fuzz/build.sh
- for fuzzer in $(find ./build-oss-fuzz/DEST_DIR/ -executable -type f
| grep -v slirp); do
grep "LLVMFuzzerTestOneInput" ${fuzzer} > /dev/null 2>&1 || continue ;
echo Testing ${fuzzer} ... ;
ASAN_OPTIONS="fast_unwind_on_malloc=0"
"${fuzzer}" -runs=1000 -seed=1 || exit 1 ;
done
build-tci:
script:
- TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64"
- mkdir build
- cd build
- ../configure --enable-tcg-interpreter
--target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)"
- make -j2
- make run-tcg-tests-x86_64-softmmu
- make tests/qtest/boot-serial-test tests/qtest/cdrom-test tests/qtest/pxe-test
- for tg in $TARGETS ; do
export QTEST_QEMU_BINARY="${tg}-softmmu/qemu-system-${tg}" ;
./tests/qtest/boot-serial-test || exit 1 ;
./tests/qtest/cdrom-test || exit 1 ;
done
- QTEST_QEMU_BINARY="x86_64-softmmu/qemu-system-x86_64" ./tests/qtest/pxe-test
- QTEST_QEMU_BINARY="s390x-softmmu/qemu-system-s390x"
./tests/qtest/pxe-test -m slow
<<: *native_build_job_definition
variables:
IMAGE: fedora
script:
- TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64"
- mkdir build
- cd build
- ../configure --enable-tcg-interpreter
--target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)"
- make -j"$JOBS"
- make run-tcg-tests-x86_64-softmmu
- make tests/qtest/boot-serial-test tests/qtest/cdrom-test tests/qtest/pxe-test
- for tg in $TARGETS ; do
export QTEST_QEMU_BINARY="${tg}-softmmu/qemu-system-${tg}" ;
./tests/qtest/boot-serial-test || exit 1 ;
./tests/qtest/cdrom-test || exit 1 ;
done
- QTEST_QEMU_BINARY="x86_64-softmmu/qemu-system-x86_64" ./tests/qtest/pxe-test
- QTEST_QEMU_BINARY="s390x-softmmu/qemu-system-s390x" ./tests/qtest/pxe-test -m slow

View File

@ -42,14 +42,20 @@ Justin Terry (VM) <juterry@microsoft.com> Justin Terry (VM) via Qemu-devel <qemu
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <aleksandar.markovic@mips.com>
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <aleksandar.markovic@imgtec.com>
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <amarkovic@wavecomp.com>
Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com> <arikalo@wavecomp.com>
Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <arikalo@wavecomp.com>
Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <aleksandar.rikalo@rt-rk.com>
Alexander Graf <agraf@csgraf.de> <agraf@suse.de>
Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com>
Filip Bozuta <filip.bozuta@syrmia.com> <filip.bozuta@rt-rk.com.com>
Frederic Konrad <konrad@adacore.com> <fred.konrad@greensocs.com>
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
Leif Lindholm <leif@nuviainc.com> <leif.lindholm@linaro.org>
Radoslaw Biernacki <rad@semihalf.com> <radoslaw.biernacki@linaro.org>
Paul Burton <pburton@wavecomp.com> <paul.burton@mips.com>
Paul Burton <pburton@wavecomp.com> <paul.burton@imgtec.com>
Paul Burton <pburton@wavecomp.com> <paul@archlinuxmips.org>
Philippe Mathieu-Daudé <philmd@redhat.com> <f4bug@amsat.org>
Stefan Brankovic <stefan.brankovic@syrmia.com> <stefan.brankovic@rt-rk.com.com>
Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
# Also list preferred name forms where people have changed their

View File

@ -26,12 +26,10 @@ env:
- IMAGE=debian-ppc64el-cross
TARGET_LIST=ppc64-softmmu,ppc64-linux-user,ppc64abi32-linux-user
build:
pre_ci:
- make docker-image-${IMAGE} V=1
pre_ci_boot:
image_name: qemu
image_tag: ${IMAGE}
pull: false
image_name: registry.gitlab.com/qemu-project/qemu/qemu/${IMAGE}
image_tag: latest
pull: true
options: "-e HOME=/root"
ci:
- unset CC

View File

@ -9,9 +9,8 @@ compiler:
cache:
# There is one cache per branch and compiler version.
# characteristics of each job are used to identify the cache:
# - OS name (currently, linux, osx, or windows)
# - OS name (currently only linux)
# - OS distribution (for Linux, xenial, trusty, or precise)
# - macOS image name (e.g., xcode7.2)
# - Names and values of visible environment variables set in .travis.yml or Settings panel
timeout: 1200
ccache: true
@ -113,6 +112,7 @@ script:
$(exit $BUILD_RC);
fi
after_script:
- df -h
- if command -v ccache ; then ccache --show-stats ; fi
@ -205,14 +205,15 @@ jobs:
# Test with Clang for compile portability (Travis uses clang-5.0)
- name: "Clang (user)"
env:
- CONFIG="--disable-system"
- CONFIG="--disable-system --host-cc=clang --cxx=clang++"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
compiler: clang
- name: "Clang (main-softmmu)"
env:
- CONFIG="--target-list=${MAIN_SOFTMMU_TARGETS} "
- CONFIG="--target-list=${MAIN_SOFTMMU_TARGETS}
--host-cc=clang --cxx=clang++"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-sanitize"
compiler: clang
before_script:
@ -222,7 +223,8 @@ jobs:
- name: "Clang (other-softmmu)"
env:
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}
--host-cc=clang --cxx=clang++"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
compiler: clang
@ -270,31 +272,6 @@ jobs:
- TEST_CMD=""
# MacOSX builds - cirrus.yml also tests some MacOS builds including latest Xcode
- name: "OSX Xcode 10.3"
env:
- BASE_CONFIG="--disable-docs --enable-tools"
- CONFIG="--target-list=i386-softmmu,ppc-softmmu,ppc64-softmmu,m68k-softmmu,x86_64-softmmu"
os: osx
osx_image: xcode10.3
compiler: clang
addons:
homebrew:
packages:
- ccache
- glib
- pixman
- gnu-sed
- python
update: true
before_script:
- brew link --overwrite python
- export PATH="/usr/local/opt/ccache/libexec:$PATH"
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
- ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
# Python builds
- name: "GCC Python 3.5 (x86_64-softmmu)"
env:
@ -312,29 +289,6 @@ jobs:
python: 3.6
# Acceptance (Functional) tests
- name: "GCC check-acceptance"
dist: bionic
env:
- CONFIG="--enable-tools --target-list=aarch64-softmmu,alpha-softmmu,arm-softmmu,m68k-softmmu,microblaze-softmmu,mips-softmmu,mips64el-softmmu,nios2-softmmu,or1k-softmmu,ppc-softmmu,ppc64-softmmu,s390x-softmmu,sparc-softmmu,x86_64-softmmu,xtensa-softmmu"
- TEST_CMD="make check-acceptance"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-acceptance"
after_script:
- python3 -c 'import json; r = json.load(open("tests/results/latest/results.json")); [print(t["logfile"]) for t in r["tests"] if t["status"] not in ("PASS", "SKIP")]' | xargs cat
- du -chs $HOME/avocado/data/cache
addons:
apt:
packages:
- python3-pil
- python3-pip
- python3-numpy
- python3-opencv
- python3-venv
- rpm2cpio
- tesseract-ocr
- tesseract-ocr-eng
# Using newer GCC with sanitizers
- name: "GCC9 with sanitizers (softmmu)"
addons:
@ -396,9 +350,10 @@ jobs:
# Run check-tcg against linux-user (with plugins)
# we skip sparc64-linux-user until it has been fixed somewhat
# we skip cris-linux-user as it doesn't use the common run loop
# we skip ppc64abi32-linux-user as it seems to have a broken libc
- name: "GCC plugins check-tcg (user)"
env:
- CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user"
- CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user,ppc64abi32-linux-user"
- TEST_BUILD_CMD="make build-tcg"
- TEST_CMD="make check-tcg"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
@ -452,6 +407,7 @@ jobs:
env:
- TEST_CMD="make check check-tcg V=1"
- CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS}"
- UNRELIABLE=true
- name: "[ppc64] GCC check-tcg"
arch: ppc64le
@ -483,7 +439,7 @@ jobs:
- genisoimage
env:
- TEST_CMD="make check check-tcg V=1"
- CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},ppc64le-linux-user"
- CONFIG="--disable-containers --target-list=ppc64-softmmu,ppc64le-linux-user"
- name: "[s390x] GCC check-tcg"
arch: s390x
@ -516,8 +472,8 @@ jobs:
env:
- TEST_CMD="make check check-tcg V=1"
- CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user"
- UNRELIABLE=true
script:
- ( cd ${SRC_DIR} ; git submodule update --init roms/SLOF )
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
- |
if [ "$BUILD_RC" -eq 0 ] ; then
@ -527,9 +483,49 @@ jobs:
$(exit $BUILD_RC);
fi
- name: "[s390x] GCC check (KVM)"
- name: "[s390x] GCC (other-softmmu)"
arch: s390x
dist: bionic
addons:
apt_packages:
- libaio-dev
- libattr1-dev
- libcap-ng-dev
- libgnutls28-dev
- libiscsi-dev
- liblttng-ust-dev
- liblzo2-dev
- libncurses-dev
- libnfs-dev
- libnss3-dev
- libpixman-1-dev
- libsdl2-dev
- libsdl2-image-dev
- libseccomp-dev
- libsnappy-dev
- libzstd-dev
- nettle-dev
- xfslibs-dev
# Tests dependencies
- genisoimage
env:
- CONFIG="--disable-containers --audio-drv-list=sdl --disable-user
--target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
- name: "[s390x] GCC (user)"
arch: s390x
dist: bionic
addons:
apt_packages:
- libgcrypt20-dev
- libgnutls28-dev
env:
- CONFIG="--disable-containers --disable-system"
- name: "[s390x] Clang (disable-tcg)"
arch: s390x
dist: bionic
compiler: clang
addons:
apt_packages:
- libaio-dev
@ -553,21 +549,11 @@ jobs:
- libusb-1.0-0-dev
- libvdeplug-dev
- libvte-2.91-dev
# Tests dependencies
- genisoimage
env:
- TEST_CMD="make check-unit"
- CONFIG="--disable-containers --disable-tcg --enable-kvm --disable-tools"
script:
- ( cd ${SRC_DIR} ; git submodule update --init roms/SLOF )
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
- |
if [ "$BUILD_RC" -eq 0 ] ; then
mv pc-bios/s390-ccw/*.img pc-bios/ ;
${TEST_CMD} ;
else
$(exit $BUILD_RC);
fi
- CONFIG="--disable-containers --disable-tcg --enable-kvm
--disable-tools --host-cc=clang --cxx=clang++"
- UNRELIABLE=true
# Release builds
# The make-release script expect a QEMU version, so our tag must start with a 'v'.
@ -589,3 +575,5 @@ jobs:
- mkdir -p release-build && cd release-build
- ../configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
- make install
allow_failures:
- env: UNRELIABLE=true

4
Kconfig Normal file
View File

@ -0,0 +1,4 @@
source Kconfig.host
source backends/Kconfig
source accel/Kconfig
source hw/Kconfig

View File

@ -2,9 +2,6 @@
# down to Kconfig. See also MINIKCONF_ARGS in the Makefile:
# these two need to be kept in sync.
config KVM
bool
config LINUX
bool
@ -31,10 +28,6 @@ config VHOST_KERNEL
bool
select VHOST
config XEN
bool
select FSDEV_9P if VIRTFS
config VIRTFS
bool

View File

@ -85,6 +85,7 @@ Architecture support
--------------------
S390 general architecture support
M: Cornelia Huck <cohuck@redhat.com>
M: Thomas Huth <thuth@redhat.com>
S: Supported
F: default-configs/s390x-softmmu.mak
F: gdb-xml/s390*.xml
@ -114,7 +115,8 @@ Overall TCG CPUs
M: Richard Henderson <rth@twiddle.net>
R: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained
F: cpus.c
F: softmmu/cpus.c
F: cpus-common.c
F: exec.c
F: accel/tcg/
F: accel/stubs/tcg-stub.c
@ -165,6 +167,14 @@ S: Maintained
F: hw/arm/smmu*
F: include/hw/arm/smmu*
AVR TCG CPUs
M: Michael Rolnik <mrolnik@gmail.com>
R: Sarah Harris <S.E.Harris@kent.ac.uk>
S: Maintained
F: gdb-xml/avr-cpu.xml
F: target/avr/
F: tests/acceptance/machine_avr6.py
CRIS TCG CPUs
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained
@ -184,8 +194,8 @@ F: hw/net/*i82596*
F: include/hw/net/lasi_82596.h
LM32 TCG CPUs
M: Michael Walle <michael@walle.cc>
S: Maintained
R: Michael Walle <michael@walle.cc>
S: Orphan
F: target/lm32/
F: disas/lm32.c
F: hw/lm32/
@ -212,7 +222,8 @@ F: disas/microblaze.c
MIPS TCG CPUs
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
R: Aurelien Jarno <aurelien@aurel32.net>
R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Maintained
F: target/mips/
F: default-configs/*mips*
@ -294,7 +305,7 @@ F: tests/tcg/s390x/
L: qemu-s390x@nongnu.org
SH4 TCG CPUs
M: Aurelien Jarno <aurelien@aurel32.net>
M: Yoshinori Sato <ysato@users.sourceforge.jp>
S: Odd Fixes
F: target/sh4/
F: hw/sh4/
@ -360,7 +371,7 @@ Overall KVM CPUs
M: Paolo Bonzini <pbonzini@redhat.com>
L: kvm@vger.kernel.org
S: Supported
F: */kvm.*
F: */*/kvm*
F: accel/kvm/
F: accel/stubs/kvm-stub.c
F: include/hw/kvm/
@ -374,6 +385,7 @@ S: Maintained
F: target/arm/kvm.c
MIPS KVM CPUs
M: Huacai Chen <chenhc@lemote.com>
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
S: Odd Fixes
F: target/mips/kvm.c
@ -396,6 +408,8 @@ F: target/s390x/machine.c
F: target/s390x/sigp.c
F: target/s390x/cpu_features*.[ch]
F: target/s390x/cpu_models.[ch]
F: hw/s390x/pv.c
F: include/hw/s390x/pv.h
F: hw/intc/s390_flic.c
F: hw/intc/s390_flic_kvm.c
F: include/hw/s390x/s390_flic.h
@ -412,8 +426,21 @@ S: Supported
F: target/i386/kvm.c
F: scripts/kvm/vmxcap
Guest CPU Cores (other accelerators)
------------------------------------
Overall
M: Richard Henderson <rth@twiddle.net>
R: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained
F: include/sysemu/accel.h
F: accel/accel.c
F: accel/Makefile.objs
F: accel/stubs/Makefile.objs
X86 HVF CPUs
M: Cameron Esfahani <dirty@apple.com>
M: Roman Bolshakov <r.bolshakov@yadro.com>
W: https://wiki.qemu.org/Features/HVF
S: Maintained
F: accel/stubs/hvf-stub.c
F: target/i386/hvf/
@ -436,6 +463,7 @@ M: Paul Durrant <paul@xen.org>
L: xen-devel@lists.xenproject.org
S: Supported
F: */xen*
F: accel/xen/*
F: hw/9pfs/xen-9p*
F: hw/char/xen_console.c
F: hw/display/xenfb.c
@ -449,6 +477,7 @@ F: hw/i386/xen/
F: hw/pci-host/xen_igd_pt.c
F: include/hw/block/dataplane/xen*
F: include/hw/xen/
F: include/sysemu/xen.h
F: include/sysemu/xen-mapcache.h
Guest CPU Cores (HAXM)
@ -459,6 +488,7 @@ M: Colin Xu <colin.xu@intel.com>
L: haxm-team@intel.com
W: https://github.com/intel/haxm/issues
S: Maintained
F: accel/stubs/hax-stub.c
F: include/sysemu/hax.h
F: target/i386/hax-*
@ -605,6 +635,8 @@ S: Odd Fixes
F: include/hw/arm/digic.h
F: hw/*/digic*
F: include/hw/*/digic*
F: tests/acceptance/machine_arm_canona1100.py
F: docs/system/arm/digic.rst
Goldfish RTC
M: Anup Patel <anup.patel@wdc.com>
@ -620,6 +652,7 @@ R: Philippe Mathieu-Daudé <f4bug@amsat.org>
L: qemu-arm@nongnu.org
S: Odd Fixes
F: hw/arm/gumstix.c
F: docs/system/arm/gumstix.rst
i.MX25 PDK
M: Peter Maydell <peter.maydell@linaro.org>
@ -629,8 +662,10 @@ S: Odd Fixes
F: hw/arm/fsl-imx25.c
F: hw/arm/imx25_pdk.c
F: hw/misc/imx25_ccm.c
F: hw/watchdog/wdt_imx2.c
F: include/hw/arm/fsl-imx25.h
F: include/hw/misc/imx25_ccm.h
F: include/hw/watchdog/wdt_imx2.h
i.MX31 (kzm)
M: Peter Chubb <peter.chubb@nicta.com.au>
@ -697,12 +732,14 @@ F: hw/misc/armsse-cpuid.c
F: include/hw/misc/armsse-cpuid.h
F: hw/misc/armsse-mhu.c
F: include/hw/misc/armsse-mhu.h
F: docs/system/arm/mps2.rst
Musca
M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/musca.c
F: docs/system/arm/musca.rst
Musicpal
M: Jan Kiszka <jan.kiszka@web.de>
@ -776,6 +813,7 @@ F: hw/gpio/max7310.c
F: hw/gpio/zaurus.c
F: hw/misc/mst_fpga.c
F: hw/misc/max111x.c
F: include/hw/misc/max111x.h
F: include/hw/arm/pxa.h
F: include/hw/arm/sharpsl.h
F: include/hw/display/tc6393xb.h
@ -797,7 +835,7 @@ F: include/hw/misc/imx6_*.h
F: include/hw/ssi/imx_spi.h
SBSA-REF
M: Radoslaw Biernacki <radoslaw.biernacki@linaro.org>
M: Radoslaw Biernacki <rad@semihalf.com>
M: Peter Maydell <peter.maydell@linaro.org>
R: Leif Lindholm <leif@nuviainc.com>
L: qemu-arm@nongnu.org
@ -810,6 +848,7 @@ L: qemu-arm@nongnu.org
S: Odd Fixes
F: hw/arm/collie.c
F: hw/arm/strongarm*
F: docs/system/arm/collie.rst
Stellaris
M: Peter Maydell <peter.maydell@linaro.org>
@ -824,12 +863,14 @@ M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/vexpress.c
F: docs/system/arm/vexpress.rst
Versatile PB
M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org
S: Maintained
F: hw/*/versatile*
F: include/hw/i2c/arm_sbcon_i2c.h
F: hw/misc/arm_sysctl.c
F: docs/system/arm/versatile.rst
@ -839,6 +880,7 @@ L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/virt*
F: include/hw/arm/virt.h
F: docs/system/arm/virt.rst
Xilinx Zynq
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
@ -919,6 +961,8 @@ F: include/hw/arm/msf2-soc.h
F: include/hw/misc/msf2-sysreg.h
F: include/hw/timer/mss-timer.h
F: include/hw/ssi/mss-spi.h
F: hw/net/msf2-emac.c
F: include/hw/net/msf2-emac.h
Emcraft M2S-FG484
M: Subbaraya Sundeep <sundeep.lkml@gmail.com>
@ -952,6 +996,28 @@ F: include/hw/*/nrf51*.h
F: include/hw/*/microbit*.h
F: tests/qtest/microbit-test.c
AVR Machines
-------------
AVR MCUs
M: Michael Rolnik <mrolnik@gmail.com>
R: Sarah Harris <S.E.Harris@kent.ac.uk>
S: Maintained
F: default-configs/avr-softmmu.mak
F: hw/avr/
F: include/hw/char/avr_usart.h
F: hw/char/avr_usart.c
F: include/hw/timer/avr_timer16.h
F: hw/timer/avr_timer16.c
F: include/hw/misc/avr_power.h
F: hw/misc/avr_power.c
Arduino
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
R: Sarah Harris <S.E.Harris@kent.ac.uk>
S: Maintained
F: hw/avr/arduino.c
CRIS Machines
-------------
Axis Dev88
@ -973,13 +1039,13 @@ F: pc-bios/hppa-firmware.img
LM32 Machines
-------------
EVR32 and uclinux BSP
M: Michael Walle <michael@walle.cc>
S: Maintained
R: Michael Walle <michael@walle.cc>
S: Orphan
F: hw/lm32/lm32_boards.c
milkymist
M: Michael Walle <michael@walle.cc>
S: Maintained
R: Michael Walle <michael@walle.cc>
S: Orphan
F: hw/lm32/milkymist.c
M68K Machines
@ -1037,9 +1103,9 @@ MIPS Machines
-------------
Jazz
M: Hervé Poussineau <hpoussin@reactos.org>
R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Maintained
F: hw/mips/mips_jazz.c
F: hw/mips/jazz.c
F: hw/display/jazz_led.c
F: hw/dma/rc4030.c
@ -1050,7 +1116,7 @@ R: Aurelien Jarno <aurelien@aurel32.net>
S: Maintained
F: hw/isa/piix4.c
F: hw/acpi/piix4.c
F: hw/mips/mips_malta.c
F: hw/mips/malta.c
F: hw/mips/gt64xxx_pci.c
F: include/hw/southbridge/piix.h
F: tests/acceptance/linux_ssh_mips_malta.py
@ -1058,30 +1124,38 @@ F: tests/acceptance/machine_mips_malta.py
Mipssim
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Odd Fixes
F: hw/mips/mips_mipssim.c
F: hw/mips/mipssim.c
F: hw/net/mipsnet.c
R4000
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
R: Aurelien Jarno <aurelien@aurel32.net>
R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Obsolete
F: hw/mips/mips_r4k.c
F: hw/mips/r4k.c
Fulong 2E
Fuloong 2E
M: Huacai Chen <chenhc@lemote.com>
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
S: Odd Fixes
F: hw/mips/mips_fulong2e.c
F: hw/mips/fuloong2e.c
F: hw/isa/vt82c686.c
F: hw/pci-host/bonito.c
F: include/hw/isa/vt82c686.h
Loongson-3 virtual platforms
M: Huacai Chen <chenhc@lemote.com>
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
S: Maintained
F: hw/intc/loongson_liointc.c
Boston
M: Paul Burton <pburton@wavecomp.com>
R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Maintained
F: hw/core/loader-fit.c
F: hw/mips/boston.c
@ -1202,7 +1276,9 @@ S: Maintained
F: hw/ppc/pnv*
F: hw/intc/pnv*
F: hw/intc/xics_pnv.c
F: hw/pci-host/pnv*
F: include/hw/ppc/pnv*
F: include/hw/pci-host/pnv*
F: pc-bios/skiboot.lid
F: tests/qtest/pnv*
@ -1225,19 +1301,45 @@ F: pc-bios/canyonlands.dt[sb]
F: pc-bios/u-boot-sam460ex-20100605.bin
F: roms/u-boot-sam460ex
RISC-V Machines
---------------
OpenTitan
M: Alistair Francis <Alistair.Francis@wdc.com>
L: qemu-riscv@nongnu.org
S: Supported
F: hw/riscv/opentitan.c
F: hw/char/ibex_uart.c
F: hw/intc/ibex_plic.c
F: include/hw/riscv/opentitan.h
F: include/hw/char/ibex_uart.h
F: include/hw/intc/ibex_plic.h
RX Machines
-----------
rx-gdbsim
M: Yoshinori Sato <ysato@users.sourceforge.jp>
S: Maintained
F: docs/system/target-rx.rst
F: hw/rx/rx-gdbsim.c
F: tests/acceptance/machine_rx_gdbsim.py
SH4 Machines
------------
R2D
M: Magnus Damm <magnus.damm@gmail.com>
M: Yoshinori Sato <ysato@users.sourceforge.jp>
R: Magnus Damm <magnus.damm@gmail.com>
S: Maintained
F: hw/sh4/r2d.c
F: hw/intc/sh_intc.c
F: hw/timer/sh_timer.c
F: include/hw/sh4/sh_intc.h
Shix
M: Magnus Damm <magnus.damm@gmail.com>
M: Yoshinori Sato <ysato@users.sourceforge.jp>
R: Magnus Damm <magnus.damm@gmail.com>
S: Odd Fixes
F: hw/sh4/shix.c
F: hw/intc/sh_intc.c
F: include/hw/sh4/sh_intc.h
SPARC Machines
--------------
@ -1267,6 +1369,7 @@ F: include/hw/pci-host/sabre.h
F: hw/pci-bridge/simba.c
F: include/hw/pci-bridge/simba.h
F: pc-bios/openbios-sparc64
F: tests/acceptance/machine_sparc64_sun4u.py
Sun4v
M: Artyom Tarasenko <atar4qemu@gmail.com>
@ -1508,10 +1611,19 @@ F: hw/acpi/*
F: hw/smbios/*
F: hw/i386/acpi-build.[hc]
F: hw/arm/virt-acpi-build.c
F: tests/qtest/bios-tables-test.c
F: tests/qtest/bios-tables-test*
F: tests/qtest/acpi-utils.[hc]
F: tests/data/acpi/
ACPI/HEST/GHES
R: Dongjiu Geng <gengdongjiu@huawei.com>
R: Xiang Zheng <zhengxiang9@huawei.com>
L: qemu-arm@nongnu.org
S: Maintained
F: hw/acpi/ghes.c
F: include/hw/acpi/ghes.h
F: docs/specs/acpi_hest_ghes.rst
ppc4xx
M: David Gibson <david@gibson.dropbear.id.au>
L: qemu-ppc@nongnu.org
@ -1568,6 +1680,7 @@ F: hw/ssi/xilinx_*
SD (Secure Card)
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
L: qemu-block@nongnu.org
S: Odd Fixes
F: include/hw/sd/sd*
F: hw/sd/core.c
@ -1648,12 +1761,12 @@ M: David Hildenbrand <david@redhat.com>
S: Maintained
F: hw/virtio/virtio-balloon*.c
F: include/hw/virtio/virtio-balloon.h
F: balloon.c
F: softmmu/balloon.c
F: include/sysemu/balloon.h
virtio-9p
M: Greg Kurz <groug@kaod.org>
R: Christian Schoenebeck <qemu_oss@crudebyte.com>
M: Christian Schoenebeck <qemu_oss@crudebyte.com>
S: Odd Fixes
F: hw/9pfs/
X: hw/9pfs/xen-9p*
@ -1730,8 +1843,17 @@ F: hw/virtio/virtio-crypto.c
F: hw/virtio/virtio-crypto-pci.c
F: include/hw/virtio/virtio-crypto.h
virtio-mem
M: David Hildenbrand <david@redhat.com>
S: Supported
W: https://virtio-mem.gitlab.io/
F: hw/virtio/virtio-mem.c
F: hw/virtio/virtio-mem-pci.h
F: hw/virtio/virtio-mem-pci.c
F: include/hw/virtio/virtio-mem.h
nvme
M: Keith Busch <keith.busch@intel.com>
M: Keith Busch <kbusch@kernel.org>
L: qemu-block@nongnu.org
S: Supported
F: hw/block/nvme*
@ -1832,6 +1954,13 @@ S: Maintained
F: include/hw/misc/unimp.h
F: hw/misc/unimp.c
Empty slot
M: Artyom Tarasenko <atar4qemu@gmail.com>
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
S: Maintained
F: include/hw/misc/empty_slot.h
F: hw/misc/empty_slot.c
Standard VGA
M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained
@ -1916,6 +2045,26 @@ F: hw/*/*xive*
F: include/hw/*/*xive*
F: docs/*/*xive*
Renesas peripherals
M: Yoshinori Sato <ysato@users.sourceforge.jp>
R: Magnus Damm <magnus.damm@gmail.com>
S: Maintained
F: hw/char/renesas_sci.c
F: hw/char/sh_serial.c
F: hw/timer/renesas_*.c
F: hw/timer/sh_timer.c
F: include/hw/char/renesas_sci.h
F: include/hw/sh4/sh.h
F: include/hw/timer/renesas_*.h
Renesas RX peripherals
M: Yoshinori Sato <ysato@users.sourceforge.jp>
S: Maintained
F: hw/intc/rx_icu.c
F: hw/rx/
F: include/hw/intc/rx_icu.h
F: include/hw/rx/
Subsystems
----------
Audio
@ -1997,19 +2146,21 @@ F: qapi/transaction.json
T: git https://repo.or.cz/qemu/armbru.git block-next
Dirty Bitmaps
M: John Snow <jsnow@redhat.com>
R: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
M: Eric Blake <eblake@redhat.com>
M: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
R: John Snow <jsnow@redhat.com>
L: qemu-block@nongnu.org
S: Supported
F: include/qemu/hbitmap.h
F: include/block/dirty-bitmap.h
F: block/monitor/bitmap-qmp-cmds.c
F: block/dirty-bitmap.c
F: block/qcow2-bitmap.c
F: migration/block-dirty-bitmap.c
F: util/hbitmap.c
F: tests/test-hbitmap.c
F: docs/interop/bitmaps.rst
T: git https://github.com/jnsnow/qemu.git bitmaps
T: git https://repo.or.cz/qemu/ericb.git bitmaps
Character device backends
M: Marc-André Lureau <marcandre.lureau@redhat.com>
@ -2076,6 +2227,7 @@ F: scripts/coccinelle/error-use-after-free.cocci
F: scripts/coccinelle/error_propagate_null.cocci
F: scripts/coccinelle/remove_local_err.cocci
F: scripts/coccinelle/use-error_fatal.cocci
F: scripts/coccinelle/errp-guard.cocci
GDB stub
M: Alex Bennée <alex.bennee@linaro.org>
@ -2088,12 +2240,12 @@ Memory API
M: Paolo Bonzini <pbonzini@redhat.com>
S: Supported
F: include/exec/ioport.h
F: ioport.c
F: include/exec/memop.h
F: include/exec/memory.h
F: include/exec/ram_addr.h
F: include/exec/ramblock.h
F: memory.c
F: softmmu/ioport.c
F: softmmu/memory.c
F: include/exec/memory-internal.h
F: exec.c
F: scripts/coccinelle/memory-region-housekeeping.cocci
@ -2125,13 +2277,14 @@ F: ui/cocoa.m
Main loop
M: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained
F: cpus.c
F: include/qemu/main-loop.h
F: include/sysemu/runstate.h
F: util/main-loop.c
F: util/qemu-timer.c
F: softmmu/vl.c
F: softmmu/main.c
F: softmmu/cpus.c
F: softmmu/cpu-throttle.c
F: qapi/run-state.json
Human Monitor (HMP)
@ -2253,6 +2406,8 @@ R: Eduardo Habkost <ehabkost@redhat.com>
S: Supported
F: docs/qdev-device-use.txt
F: hw/core/qdev*
F: hw/core/bus.c
F: hw/core/sysbus.c
F: include/hw/qdev*
F: include/monitor/qdev.h
F: include/qom/
@ -2284,17 +2439,21 @@ M: Thomas Huth <thuth@redhat.com>
M: Laurent Vivier <lvivier@redhat.com>
R: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained
F: qtest.c
F: softmmu/qtest.c
F: accel/qtest.c
F: tests/qtest/
X: tests/qtest/bios-tables-test-allowed-diff.h
Device Fuzzing
M: Alexander Bulekov <alxndr@bu.edu>
R: Paolo Bonzini <pbonzini@redhat.com>
R: Bandan Das <bsd@redhat.com>
R: Stefan Hajnoczi <stefanha@redhat.com>
R: Thomas Huth <thuth@redhat.com>
S: Maintained
F: tests/qtest/fuzz/
F: scripts/oss-fuzz/
F: docs/devel/fuzzing.txt
Register API
M: Alistair Francis <alistair@alistair23.me>
@ -2311,6 +2470,12 @@ F: net/slirp.c
F: include/net/slirp.h
T: git https://people.debian.org/~sthibault/qemu.git slirp
Streams
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained
F: hw/core/stream.c
F: include/hw/stream.h
Stubs
M: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained
@ -2338,7 +2503,7 @@ F: hw/tpm/*
F: include/hw/acpi/tpm.h
F: include/sysemu/tpm*
F: qapi/tpm.json
F: backends/tpm.c
F: backends/tpm/
F: tests/qtest/*tpm*
T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
@ -2477,6 +2642,7 @@ F: net/filter-replay.c
F: include/sysemu/replay.h
F: docs/replay.txt
F: stubs/replay.c
F: tests/acceptance/replay_kernel.py
IOVA Tree
M: Peter Xu <peterx@redhat.com>
@ -2501,6 +2667,14 @@ F: include/hw/i2c/smbus_master.h
F: include/hw/i2c/smbus_slave.h
F: include/hw/i2c/smbus_eeprom.h
Firmware schema specifications
M: Laszlo Ersek <lersek@redhat.com>
M: Philippe Mathieu-Daudé <philmd@redhat.com>
R: Daniel P. Berrange <berrange@redhat.com>
R: Kashyap Chamarthy <kchamart@redhat.com>
S: Maintained
F: docs/interop/firmware.json
EDK2 Firmware
M: Laszlo Ersek <lersek@redhat.com>
M: Philippe Mathieu-Daudé <philmd@redhat.com>
@ -2512,9 +2686,25 @@ F: roms/edk2
F: roms/edk2-*
F: tests/data/uefi-boot-images/
F: tests/uefi-test-tools/
F: .gitlab-ci-edk2.yml
F: .gitlab-ci.d/edk2.yml
F: .gitlab-ci.d/edk2/
VT-d Emulation
M: Michael S. Tsirkin <mst@redhat.com>
M: Peter Xu <peterx@redhat.com>
R: Jason Wang <jasowang@redhat.com>
S: Supported
F: hw/i386/intel_iommu.c
F: hw/i386/intel_iommu_internal.h
F: include/hw/i386/intel_iommu.h
OpenSBI Firmware
M: Bin Meng <bmeng.cn@gmail.com>
S: Supported
F: pc-bios/opensbi-*
F: .gitlab-ci.d/opensbi.yml
F: .gitlab-ci.d/opensbi/
Usermode Emulation
------------------
Overall usermode emulation
@ -2529,8 +2719,7 @@ F: bsd-user/
F: default-configs/*-bsd-user.mak
Linux user
M: Riku Voipio <riku.voipio@iki.fi>
R: Laurent Vivier <laurent@vivier.eu>
M: Laurent Vivier <laurent@vivier.eu>
S: Maintained
F: linux-user/
F: default-configs/*-linux-user.mak
@ -2578,7 +2767,9 @@ F: disas/i386.c
MIPS TCG target
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
R: Aurelien Jarno <aurelien@aurel32.net>
R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
R: Huacai Chen <chenhc@lemote.com>
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Maintained
F: tcg/mips/
@ -2810,7 +3001,7 @@ F: block/vpc.c
vvfat
M: Kevin Wolf <kwolf@redhat.com>
L: qemu-block@nongnu.org
S: Supported
S: Odd Fixes
F: block/vvfat.c
Image format fuzzer
@ -2871,6 +3062,9 @@ W: https://cirrus-ci.com/github/qemu/qemu
GitLab Continuous Integration
M: Thomas Huth <thuth@redhat.com>
M: Philippe Mathieu-Daudé <philmd@redhat.com>
M: Alex Bennée <alex.bennee@linaro.org>
R: Wainer dos Santos Moschetta <wainersm@redhat.com>
S: Maintained
F: .gitlab-ci.yml
@ -2881,6 +3075,14 @@ S: Maintained
F: tests/tcg/Makefile
F: tests/tcg/Makefile.include
Acceptance (Integration) Testing with the Avocado framework
W: https://trello.com/b/6Qi1pxVn/avocado-qemu
R: Cleber Rosa <crosa@redhat.com>
R: Philippe Mathieu-Daudé <philmd@redhat.com>
R: Wainer dos Santos Moschetta <wainersm@redhat.com>
S: Odd Fixes
F: tests/acceptance/
Documentation
-------------
Build system architecture
@ -2914,3 +3116,10 @@ M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
F: docs/conf.py
F: docs/*/conf.py
Miscellaneous
-------------
Performance Tools and Tests
M: Ahmed Karaman <ahmedkhaledkaraman@gmail.com>
S: Maintained
F: scripts/performance/

View File

@ -339,16 +339,16 @@ $(call set-vpath, $(SRC_PATH))
LIBS+=-lz $(LIBS_TOOLS)
vhost-user-json-y =
HELPERS-y =
HELPERS-y = $(HELPERS)
HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) = qemu-bridge-helper$(EXESUF)
HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) += qemu-bridge-helper$(EXESUF)
ifeq ($(CONFIG_LINUX)$(CONFIG_VIRGL)$(CONFIG_GBM)$(CONFIG_TOOLS),yyyy)
HELPERS-y += vhost-user-gpu$(EXESUF)
vhost-user-json-y += contrib/vhost-user-gpu/50-qemu-gpu.json
endif
ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy)
ifeq ($(CONFIG_SOFTMMU)$(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyyy)
HELPERS-y += virtiofsd$(EXESUF)
vhost-user-json-y += tools/virtiofsd/50-qemu-virtiofsd.json
endif
@ -407,7 +407,8 @@ endif
# This has to be kept in sync with Kconfig.host.
MINIKCONF_ARGS = \
$(CONFIG_MINIKCONF_MODE) \
$@ $*/config-devices.mak.d $< $(MINIKCONF_INPUTS) \
$@ $*/config-devices.mak.d $< $(SRC_PATH)/Kconfig \
CONFIG_TCG=$(CONFIG_TCG) \
CONFIG_KVM=$(CONFIG_KVM) \
CONFIG_SPICE=$(CONFIG_SPICE) \
CONFIG_IVSHMEM=$(CONFIG_IVSHMEM) \
@ -421,12 +422,11 @@ MINIKCONF_ARGS = \
CONFIG_LINUX=$(CONFIG_LINUX) \
CONFIG_PVRDMA=$(CONFIG_PVRDMA)
MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/hw/Kconfig
MINIKCONF_DEPS = $(MINIKCONF_INPUTS) $(wildcard $(SRC_PATH)/hw/*/Kconfig)
MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py \
MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py
$(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(MINIKCONF_DEPS) $(BUILD_DIR)/config-host.mak
$(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) > $@.tmp, "GEN", "$@.tmp")
$(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(SRC_PATH)/Kconfig $(BUILD_DIR)/config-host.mak
$(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) \
> $@.tmp, "GEN", "$@.tmp")
$(call quiet-command, if test -f $@; then \
if cmp -s $@.old $@; then \
mv $@.tmp $@; \
@ -568,13 +568,14 @@ $(SOFTMMU_FUZZ_RULES): $(edk2-decompressed)
$(TARGET_DIRS_RULES):
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" TARGET_DIR="$(dir $@)" $(notdir $@),)
DTC_MAKE_ARGS=-I$(SRC_PATH)/dtc VPATH=$(SRC_PATH)/dtc -C dtc V="$(V)" LIBFDT_srcdir=$(SRC_PATH)/dtc/libfdt
# LIBFDT_lib="": avoid breaking existing trees with objects requiring -fPIC
DTC_MAKE_ARGS=-I$(SRC_PATH)/dtc VPATH=$(SRC_PATH)/dtc -C dtc V="$(V)" LIBFDT_lib=""
DTC_CFLAGS=$(CFLAGS) $(QEMU_CFLAGS)
DTC_CPPFLAGS=-I$(BUILD_DIR)/dtc -I$(SRC_PATH)/dtc -I$(SRC_PATH)/dtc/libfdt
DTC_CPPFLAGS=-I$(SRC_PATH)/dtc/libfdt
.PHONY: dtc/all
dtc/all: .git-submodule-status dtc/libfdt dtc/tests
$(call quiet-command,$(MAKE) $(DTC_MAKE_ARGS) CPPFLAGS="$(DTC_CPPFLAGS)" CFLAGS="$(DTC_CFLAGS)" LDFLAGS="$(QEMU_LDFLAGS)" ARFLAGS="$(ARFLAGS)" CC="$(CC)" AR="$(AR)" LD="$(LD)" $(SUBDIR_MAKEFLAGS) libfdt/libfdt.a,)
dtc/all: .git-submodule-status dtc/libfdt
$(call quiet-command,$(MAKE) $(DTC_MAKE_ARGS) CPPFLAGS="$(DTC_CPPFLAGS)" CFLAGS="$(DTC_CFLAGS)" LDFLAGS="$(QEMU_LDFLAGS)" ARFLAGS="$(ARFLAGS)" CC="$(CC)" AR="$(AR)" LD="$(LD)" $(SUBDIR_MAKEFLAGS) libfdt,)
dtc/%: .git-submodule-status
@mkdir -p $@
@ -603,12 +604,6 @@ slirp/all: .git-submodule-status
CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" \
CFLAGS="$(QEMU_CFLAGS) $(CFLAGS)" LDFLAGS="$(QEMU_LDFLAGS)")
# Compatibility gunk to keep make working across the rename of targets
# for recursion, to be removed some time after 4.1.
subdir-dtc: dtc/all
subdir-capstone: capstone/all
subdir-slirp: slirp/all
$(filter %/all, $(TARGET_DIRS_RULES)): libqemuutil.a $(common-obj-y) \
$(qom-obj-y)
@ -624,7 +619,6 @@ $(ROM_DIRS_RULES):
.PHONY: recurse-all recurse-clean recurse-install
recurse-all: $(addsuffix /all, $(TARGET_DIRS) $(ROM_DIRS))
recurse-fuzz: $(addsuffix /fuzz, $(TARGET_DIRS) $(ROM_DIRS))
recurse-clean: $(addsuffix /clean, $(TARGET_DIRS) $(ROM_DIRS))
recurse-install: $(addsuffix /install, $(TARGET_DIRS))
$(addsuffix /install, $(TARGET_DIRS)): all
@ -774,7 +768,7 @@ virtiofsd$(EXESUF): $(virtiofsd-obj-y) libvhost-user.a $(COMMON_LDADDS)
$(call LINK, $^)
endif
vhost-user-gpu$(EXESUF): $(vhost-user-gpu-obj-y) $(libvhost-user-obj-y) libqemuutil.a libqemustub.a
vhost-user-gpu$(EXESUF): $(vhost-user-gpu-obj-y) $(libvhost-user-obj-y) libqemuutil.a
$(call LINK, $^)
ifdef CONFIG_VHOST_USER_INPUT
@ -823,6 +817,7 @@ clean: recurse-clean
rm -f storage-daemon/qapi/qapi-gen-timestamp
rm -rf qga/qapi-generated
rm -f config-all-devices.mak
rm -f $(SUBDIR_DEVICES_MAK)
VERSION ?= $(shell cat VERSION)
@ -863,7 +858,6 @@ distclean: clean
rm -rf $$d || exit 1 ; \
done
rm -Rf .sdk
if test -f dtc/version_gen.h; then $(MAKE) $(DTC_MAKE_ARGS) clean; fi
KEYMAPS=da en-gb et fr fr-ch is lt no pt-br sv \
ar de en-us fi fr-be hr it lv nl pl ru th \
@ -922,8 +916,9 @@ install-sphinxdocs: sphinxdocs
install-doc: $(DOCS) install-sphinxdocs
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/index.html "$(DESTDIR)$(qemu_docdir)"
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.html "$(DESTDIR)$(qemu_docdir)"
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.txt "$(DESTDIR)$(qemu_docdir)"
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)/interop"
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.html "$(DESTDIR)$(qemu_docdir)/interop"
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.txt "$(DESTDIR)$(qemu_docdir)/interop"
ifdef CONFIG_POSIX
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/system/qemu.1 "$(DESTDIR)$(mandir)/man1"
@ -941,8 +936,9 @@ ifdef CONFIG_TRACE_SYSTEMTAP
endif
ifneq (,$(findstring qemu-ga,$(TOOLS)))
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/interop/qemu-ga.8 "$(DESTDIR)$(mandir)/man8"
$(INSTALL_DATA) docs/interop/qemu-ga-ref.html "$(DESTDIR)$(qemu_docdir)"
$(INSTALL_DATA) docs/interop/qemu-ga-ref.txt "$(DESTDIR)$(qemu_docdir)"
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)/interop"
$(INSTALL_DATA) docs/interop/qemu-ga-ref.html "$(DESTDIR)$(qemu_docdir)/interop"
$(INSTALL_DATA) docs/interop/qemu-ga-ref.txt "$(DESTDIR)$(qemu_docdir)/interop"
$(INSTALL_DATA) docs/interop/qemu-ga-ref.7 "$(DESTDIR)$(mandir)/man7"
endif
endif
@ -1295,7 +1291,16 @@ endif
@$(if $(TARGET_DIRS), \
echo 'Architecture specific targets:'; \
$(foreach t, $(TARGET_DIRS), \
$(call print-help-run,$(t)/all,Build for $(t));) \
$(call print-help-run,$(t)/all,Build for $(t)); \
$(if $(CONFIG_FUZZ), \
$(if $(findstring softmmu,$(t)), \
$(call print-help-run,$(t)/fuzz,Build fuzzer for $(t)); \
))) \
echo '')
@$(if $(HELPERS-y), \
echo 'Helper targets:'; \
$(foreach t, $(HELPERS-y), \
$(call print-help-run,$(t),Build $(shell basename $(t)));) \
echo '')
@$(if $(TOOLS), \
echo 'Tools targets:'; \

View File

@ -13,9 +13,8 @@ chardev-obj-y = chardev/
authz-obj-y = authz/
block-obj-y = nbd/
block-obj-y = block/ nbd/ scsi/
block-obj-y += block.o blockjob.o job.o
block-obj-y += block/ scsi/
block-obj-y += qemu-io-cmds.o
block-obj-$(CONFIG_REPLICATION) += replication.o
@ -60,6 +59,7 @@ common-obj-y += migration/
common-obj-y += audio/
common-obj-m += audio/
common-obj-y += hw/
common-obj-m += hw/
common-obj-y += replay/
@ -71,6 +71,7 @@ common-obj-$(CONFIG_TPM) += tpm.o
common-obj-y += backends/
common-obj-y += chardev/
common-obj-m += chardev/
common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o
qemu-seccomp.o-cflags := $(SECCOMP_CFLAGS)
@ -128,6 +129,7 @@ trace-events-subdirs =
trace-events-subdirs += accel/kvm
trace-events-subdirs += accel/tcg
trace-events-subdirs += backends
trace-events-subdirs += backends/tpm
trace-events-subdirs += crypto
trace-events-subdirs += monitor
ifeq ($(CONFIG_USER_ONLY),y)
@ -153,6 +155,7 @@ trace-events-subdirs += hw/block/dataplane
trace-events-subdirs += hw/char
trace-events-subdirs += hw/dma
trace-events-subdirs += hw/hppa
trace-events-subdirs += hw/hyperv
trace-events-subdirs += hw/i2c
trace-events-subdirs += hw/i386
trace-events-subdirs += hw/i386/xen

View File

@ -156,16 +156,13 @@ endif #CONFIG_BSD_USER
#########################################################
# System emulator target
ifdef CONFIG_SOFTMMU
obj-y += arch_init.o cpus.o gdbstub.o balloon.o ioport.o
obj-y += qtest.o
obj-y += softmmu/
obj-y += gdbstub.o
obj-y += dump/
obj-y += hw/
obj-y += monitor/
obj-y += qapi/
obj-y += memory.o
obj-y += memory_mapping.o
obj-y += migration/ram.o
obj-y += softmmu/
LIBS := $(libs_softmmu) $(LIBS)
# Hardware support
@ -183,6 +180,20 @@ endif # CONFIG_SOFTMMU
dummy := $(call unnest-vars,,obj-y)
all-obj-y := $(obj-y)
#
# common-obj-m has some crap here, probably as side effect from
# unnest-vars recursing into target directories to fill obj-y and not
# properly handling the -m case.
#
# Clear common-obj-m as workaround. Fixes suspious dependency errors
# when building devices as modules. A bit hackish, but should be ok
# as long as we do not have any target-specific modules.
#
# The meson-based build system currently in development doesn't need
# unnest-vars and will obsolete this workaround.
#
common-obj-m :=
include $(SRC_PATH)/Makefile.objs
dummy := $(call unnest-vars,.., \
authz-obj-y \

View File

@ -1 +1 @@
5.0.0
5.1.0

9
accel/Kconfig Normal file
View File

@ -0,0 +1,9 @@
config TCG
bool
config KVM
bool
config XEN
bool
select FSDEV_9P if VIRTFS

View File

@ -2,4 +2,5 @@ common-obj-$(CONFIG_SOFTMMU) += accel.o
obj-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_POSIX)) += qtest.o
obj-$(CONFIG_KVM) += kvm/
obj-$(CONFIG_TCG) += tcg/
obj-$(CONFIG_XEN) += xen/
obj-y += stubs/

View File

@ -40,10 +40,10 @@
#include "trace.h"
#include "hw/irq.h"
#include "sysemu/sev.h"
#include "sysemu/balloon.h"
#include "qapi/visitor.h"
#include "qapi/qapi-types-common.h"
#include "qapi/qapi-visit-common.h"
#include "sysemu/reset.h"
#include "hw/boards.h"
@ -100,7 +100,7 @@ struct KVMState
bool kernel_irqchip_required;
OnOffAuto kernel_irqchip_split;
bool sync_mmu;
bool manual_dirty_log_protect;
uint64_t manual_dirty_log_protect;
/* The man page (and posix) say ioctl numbers are signed int, but
* they're not. Linux, glibc and *BSD all treat ioctl numbers as
* unsigned, and treating them as signed here can break things */
@ -159,9 +159,59 @@ static const KVMCapabilityInfo kvm_required_capabilites[] = {
static NotifierList kvm_irqchip_change_notifiers =
NOTIFIER_LIST_INITIALIZER(kvm_irqchip_change_notifiers);
struct KVMResampleFd {
int gsi;
EventNotifier *resample_event;
QLIST_ENTRY(KVMResampleFd) node;
};
typedef struct KVMResampleFd KVMResampleFd;
/*
* Only used with split irqchip where we need to do the resample fd
* kick for the kernel from userspace.
*/
static QLIST_HEAD(, KVMResampleFd) kvm_resample_fd_list =
QLIST_HEAD_INITIALIZER(kvm_resample_fd_list);
#define kvm_slots_lock(kml) qemu_mutex_lock(&(kml)->slots_lock)
#define kvm_slots_unlock(kml) qemu_mutex_unlock(&(kml)->slots_lock)
static inline void kvm_resample_fd_remove(int gsi)
{
KVMResampleFd *rfd;
QLIST_FOREACH(rfd, &kvm_resample_fd_list, node) {
if (rfd->gsi == gsi) {
QLIST_REMOVE(rfd, node);
g_free(rfd);
break;
}
}
}
static inline void kvm_resample_fd_insert(int gsi, EventNotifier *event)
{
KVMResampleFd *rfd = g_new0(KVMResampleFd, 1);
rfd->gsi = gsi;
rfd->resample_event = event;
QLIST_INSERT_HEAD(&kvm_resample_fd_list, rfd, node);
}
void kvm_resample_fd_notify(int gsi)
{
KVMResampleFd *rfd;
QLIST_FOREACH(rfd, &kvm_resample_fd_list, node) {
if (rfd->gsi == gsi) {
event_notifier_set(rfd->resample_event);
trace_kvm_resample_fd_notify(gsi);
return;
}
}
}
int kvm_get_max_memslots(void)
{
KVMState *s = KVM_STATE(current_accel());
@ -883,6 +933,39 @@ int kvm_vm_check_extension(KVMState *s, unsigned int extension)
return ret;
}
typedef struct HWPoisonPage {
ram_addr_t ram_addr;
QLIST_ENTRY(HWPoisonPage) list;
} HWPoisonPage;
static QLIST_HEAD(, HWPoisonPage) hwpoison_page_list =
QLIST_HEAD_INITIALIZER(hwpoison_page_list);
static void kvm_unpoison_all(void *param)
{
HWPoisonPage *page, *next_page;
QLIST_FOREACH_SAFE(page, &hwpoison_page_list, list, next_page) {
QLIST_REMOVE(page, list);
qemu_ram_remap(page->ram_addr, TARGET_PAGE_SIZE);
g_free(page);
}
}
void kvm_hwpoison_page_add(ram_addr_t ram_addr)
{
HWPoisonPage *page;
QLIST_FOREACH(page, &hwpoison_page_list, list) {
if (page->ram_addr == ram_addr) {
return;
}
}
page = g_new(HWPoisonPage, 1);
page->ram_addr = ram_addr;
QLIST_INSERT_HEAD(&hwpoison_page_list, page, list);
}
static uint32_t adjust_ioeventfd_endianness(uint32_t val, uint32_t size)
{
#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
@ -1628,9 +1711,13 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg,
return kvm_update_routing_entry(s, &kroute);
}
static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int rfd, int virq,
static int kvm_irqchip_assign_irqfd(KVMState *s, EventNotifier *event,
EventNotifier *resample, int virq,
bool assign)
{
int fd = event_notifier_get_fd(event);
int rfd = resample ? event_notifier_get_fd(resample) : -1;
struct kvm_irqfd irqfd = {
.fd = fd,
.gsi = virq,
@ -1638,8 +1725,33 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int rfd, int virq,
};
if (rfd != -1) {
irqfd.flags |= KVM_IRQFD_FLAG_RESAMPLE;
irqfd.resamplefd = rfd;
assert(assign);
if (kvm_irqchip_is_split()) {
/*
* When the slow irqchip (e.g. IOAPIC) is in the
* userspace, KVM kernel resamplefd will not work because
* the EOI of the interrupt will be delivered to userspace
* instead, so the KVM kernel resamplefd kick will be
* skipped. The userspace here mimics what the kernel
* provides with resamplefd, remember the resamplefd and
* kick it when we receive EOI of this IRQ.
*
* This is hackery because IOAPIC is mostly bypassed
* (except EOI broadcasts) when irqfd is used. However
* this can bring much performance back for split irqchip
* with INTx IRQs (for VFIO, this gives 93% perf of the
* full fast path, which is 46% perf boost comparing to
* the INTx slow path).
*/
kvm_resample_fd_insert(virq, resample);
} else {
irqfd.flags |= KVM_IRQFD_FLAG_RESAMPLE;
irqfd.resamplefd = rfd;
}
} else if (!assign) {
if (kvm_irqchip_is_split()) {
kvm_resample_fd_remove(virq);
}
}
if (!kvm_irqfds_enabled()) {
@ -1735,7 +1847,9 @@ int kvm_irqchip_add_hv_sint_route(KVMState *s, uint32_t vcpu, uint32_t sint)
return -ENOSYS;
}
static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign)
static int kvm_irqchip_assign_irqfd(KVMState *s, EventNotifier *event,
EventNotifier *resample, int virq,
bool assign)
{
abort();
}
@ -1749,15 +1863,13 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg)
int kvm_irqchip_add_irqfd_notifier_gsi(KVMState *s, EventNotifier *n,
EventNotifier *rn, int virq)
{
return kvm_irqchip_assign_irqfd(s, event_notifier_get_fd(n),
rn ? event_notifier_get_fd(rn) : -1, virq, true);
return kvm_irqchip_assign_irqfd(s, n, rn, virq, true);
}
int kvm_irqchip_remove_irqfd_notifier_gsi(KVMState *s, EventNotifier *n,
int virq)
{
return kvm_irqchip_assign_irqfd(s, event_notifier_get_fd(n), -1, virq,
false);
return kvm_irqchip_assign_irqfd(s, n, NULL, virq, false);
}
int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n,
@ -1882,6 +1994,7 @@ static int kvm_init(MachineState *ms)
int ret;
int type = 0;
const char *kvm_type;
uint64_t dirty_log_manual_caps;
s = KVM_STATE(ms->accelerator);
@ -2007,14 +2120,20 @@ static int kvm_init(MachineState *ms)
s->coalesced_pio = s->coalesced_mmio &&
kvm_check_extension(s, KVM_CAP_COALESCED_PIO);
s->manual_dirty_log_protect =
dirty_log_manual_caps =
kvm_check_extension(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2);
if (s->manual_dirty_log_protect) {
ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0, 1);
dirty_log_manual_caps &= (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE |
KVM_DIRTY_LOG_INITIALLY_SET);
s->manual_dirty_log_protect = dirty_log_manual_caps;
if (dirty_log_manual_caps) {
ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0,
dirty_log_manual_caps);
if (ret) {
warn_report("Trying to enable KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 "
"but failed. Falling back to the legacy mode. ");
s->manual_dirty_log_protect = false;
warn_report("Trying to enable capability %"PRIu64" of "
"KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 but failed. "
"Falling back to the legacy mode. ",
dirty_log_manual_caps);
s->manual_dirty_log_protect = 0;
}
}
@ -2085,6 +2204,8 @@ static int kvm_init(MachineState *ms)
s->kernel_irqchip_split = mc->default_kernel_irqchip_split ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
}
qemu_register_reset(kvm_unpoison_all, NULL);
if (s->kernel_irqchip_allowed) {
kvm_irqchip_create(s);
}
@ -2107,7 +2228,8 @@ static int kvm_init(MachineState *ms)
s->sync_mmu = !!kvm_vm_check_extension(kvm_state, KVM_CAP_SYNC_MMU);
if (!s->sync_mmu) {
qemu_balloon_inhibit(true);
ret = ram_block_discard_disable(true);
assert(!ret);
}
return 0;
@ -2991,12 +3113,9 @@ static void kvm_set_kvm_shadow_mem(Object *obj, Visitor *v,
Error **errp)
{
KVMState *s = KVM_STATE(obj);
Error *error = NULL;
int64_t value;
visit_type_int(v, name, &value, &error);
if (error) {
error_propagate(errp, error);
if (!visit_type_int(v, name, &value, errp)) {
return;
}
@ -3007,37 +3126,33 @@ static void kvm_set_kernel_irqchip(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
Error *err = NULL;
KVMState *s = KVM_STATE(obj);
OnOffSplit mode;
visit_type_OnOffSplit(v, name, &mode, &err);
if (err) {
error_propagate(errp, err);
if (!visit_type_OnOffSplit(v, name, &mode, errp)) {
return;
} else {
switch (mode) {
case ON_OFF_SPLIT_ON:
s->kernel_irqchip_allowed = true;
s->kernel_irqchip_required = true;
s->kernel_irqchip_split = ON_OFF_AUTO_OFF;
break;
case ON_OFF_SPLIT_OFF:
s->kernel_irqchip_allowed = false;
s->kernel_irqchip_required = false;
s->kernel_irqchip_split = ON_OFF_AUTO_OFF;
break;
case ON_OFF_SPLIT_SPLIT:
s->kernel_irqchip_allowed = true;
s->kernel_irqchip_required = true;
s->kernel_irqchip_split = ON_OFF_AUTO_ON;
break;
default:
/* The value was checked in visit_type_OnOffSplit() above. If
* we get here, then something is wrong in QEMU.
*/
abort();
}
}
switch (mode) {
case ON_OFF_SPLIT_ON:
s->kernel_irqchip_allowed = true;
s->kernel_irqchip_required = true;
s->kernel_irqchip_split = ON_OFF_AUTO_OFF;
break;
case ON_OFF_SPLIT_OFF:
s->kernel_irqchip_allowed = false;
s->kernel_irqchip_required = false;
s->kernel_irqchip_split = ON_OFF_AUTO_OFF;
break;
case ON_OFF_SPLIT_SPLIT:
s->kernel_irqchip_allowed = true;
s->kernel_irqchip_required = true;
s->kernel_irqchip_split = ON_OFF_AUTO_ON;
break;
default:
/* The value was checked in visit_type_OnOffSplit() above. If
* we get here, then something is wrong in QEMU.
*/
abort();
}
}
@ -3075,15 +3190,15 @@ static void kvm_accel_class_init(ObjectClass *oc, void *data)
object_class_property_add(oc, "kernel-irqchip", "on|off|split",
NULL, kvm_set_kernel_irqchip,
NULL, NULL, &error_abort);
NULL, NULL);
object_class_property_set_description(oc, "kernel-irqchip",
"Configure KVM in-kernel irqchip", &error_abort);
"Configure KVM in-kernel irqchip");
object_class_property_add(oc, "kvm-shadow-mem", "int",
kvm_get_kvm_shadow_mem, kvm_set_kvm_shadow_mem,
NULL, NULL, &error_abort);
NULL, NULL);
object_class_property_set_description(oc, "kvm-shadow-mem",
"KVM shadow MMU size", &error_abort);
"KVM shadow MMU size");
}
static const TypeInfo kvm_accel_type = {

View File

@ -16,4 +16,5 @@ kvm_set_ioeventfd_mmio(int fd, uint64_t addr, uint32_t val, bool assign, uint32_
kvm_set_ioeventfd_pio(int fd, uint16_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%x val=0x%x assign: %d size: %d match: %d"
kvm_set_user_memory(uint32_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, int ret) "Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " ret=%d"
kvm_clear_dirty_log(uint32_t slot, uint64_t start, uint32_t size) "slot#%"PRId32" start 0x%"PRIx64" size 0x%"PRIx32
kvm_resample_fd_notify(int gsi) "gsi %d"

View File

@ -3,3 +3,4 @@ obj-$(call lnot,$(CONFIG_HVF)) += hvf-stub.o
obj-$(call lnot,$(CONFIG_WHPX)) += whpx-stub.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o
obj-$(call lnot,$(CONFIG_XEN)) += xen-stub.o

View File

@ -22,3 +22,10 @@ void tb_flush(CPUState *cpu)
void tlb_set_dirty(CPUState *cpu, target_ulong vaddr)
{
}
void *probe_access(CPUArchState *env, target_ulong addr, int size,
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
{
/* Handled by hardware accelerator. */
g_assert_not_reached();
}

View File

@ -1,18 +1,20 @@
/*
* Copyright (C) 2010 Citrix Ltd.
* Copyright (C) 2014 Citrix Systems UK Ltd.
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "hw/xen/xen.h"
#include "exec/memory.h"
#include "qapi/qapi-commands-misc.h"
bool xen_allowed;
void xenstore_store_pv_console_info(int i, Chardev *chr)
{
}
int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
{
return -1;
@ -35,11 +37,6 @@ int xen_is_pirq_msi(uint32_t msi_data)
return 0;
}
void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, MemoryRegion *mr,
Error **errp)
{
}
qemu_irq *xen_interrupt_controller_init(void)
{
return NULL;
@ -49,10 +46,6 @@ void xen_register_framebuffer(MemoryRegion *mr)
{
}
void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length)
{
}
void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
{
}

View File

@ -504,6 +504,17 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
cc->do_interrupt(cpu);
qemu_mutex_unlock_iothread();
cpu->exception_index = -1;
if (unlikely(cpu->singlestep_enabled)) {
/*
* After processing the exception, ensure an EXCP_DEBUG is
* raised when single-stepping so that GDB doesn't miss the
* next instruction.
*/
*ret = EXCP_DEBUG;
cpu_handle_debug_exception(cpu);
return true;
}
} else if (!replay_has_interrupt()) {
/* give a chance to iothread in replay mode */
*ret = EXCP_INTERRUPT;
@ -577,7 +588,13 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
else {
if (cc->cpu_exec_interrupt(cpu, interrupt_request)) {
replay_interrupt();
cpu->exception_index = -1;
/*
* After processing the interrupt, ensure an EXCP_DEBUG is
* raised when single-stepping so that GDB doesn't miss the
* next instruction.
*/
cpu->exception_index =
(cpu->singlestep_enabled ? EXCP_DEBUG : -1);
*last_tb = NULL;
}
/* The target hook may have updated the 'cpu->interrupt_request';

View File

@ -270,6 +270,21 @@ void tlb_init(CPUState *cpu)
}
}
void tlb_destroy(CPUState *cpu)
{
CPUArchState *env = cpu->env_ptr;
int i;
qemu_spin_destroy(&env_tlb(env)->c.lock);
for (i = 0; i < NB_MMU_MODES; i++) {
CPUTLBDesc *desc = &env_tlb(env)->d[i];
CPUTLBDescFast *fast = &env_tlb(env)->f[i];
g_free(fast->table);
g_free(desc->iotlb);
}
}
/* flush_all_helper: run fn across all cpus
*
* If the wait flag is set then the src cpu's helper will be queued as
@ -1058,6 +1073,22 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
return val;
}
/*
* Save a potentially trashed IOTLB entry for later lookup by plugin.
* This is read by tlb_plugin_lookup if the iotlb entry doesn't match
* because of the side effect of io_writex changing memory layout.
*/
static void save_iotlb_data(CPUState *cs, hwaddr addr,
MemoryRegionSection *section, hwaddr mr_offset)
{
#ifdef CONFIG_PLUGIN
SavedIOTLB *saved = &cs->saved_iotlb;
saved->addr = addr;
saved->section = section;
saved->mr_offset = mr_offset;
#endif
}
static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
int mmu_idx, uint64_t val, target_ulong addr,
uintptr_t retaddr, MemOp op)
@ -1077,6 +1108,12 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
}
cpu->mem_io_pc = retaddr;
/*
* The memory_region_dispatch may trigger a flush/resize
* so for plugins we save the iotlb_data just in case.
*/
save_iotlb_data(cpu, iotlbentry->addr, section, mr_offset);
if (mr->global_locking && !qemu_mutex_iothread_locked()) {
qemu_mutex_lock_iothread();
locked = true;
@ -1231,86 +1268,16 @@ static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size,
}
}
/*
* Probe for whether the specified guest access is permitted. If it is not
* permitted then an exception will be taken in the same way as if this
* were a real access (and we will not return).
* If the size is 0 or the page requires I/O access, returns NULL; otherwise,
* returns the address of the host page similar to tlb_vaddr_to_host().
*/
void *probe_access(CPUArchState *env, target_ulong addr, int size,
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
static int probe_access_internal(CPUArchState *env, target_ulong addr,
int fault_size, MMUAccessType access_type,
int mmu_idx, bool nonfault,
void **phost, uintptr_t retaddr)
{
uintptr_t index = tlb_index(env, mmu_idx, addr);
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
target_ulong tlb_addr;
size_t elt_ofs;
int wp_access;
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
switch (access_type) {
case MMU_DATA_LOAD:
elt_ofs = offsetof(CPUTLBEntry, addr_read);
wp_access = BP_MEM_READ;
break;
case MMU_DATA_STORE:
elt_ofs = offsetof(CPUTLBEntry, addr_write);
wp_access = BP_MEM_WRITE;
break;
case MMU_INST_FETCH:
elt_ofs = offsetof(CPUTLBEntry, addr_code);
wp_access = BP_MEM_READ;
break;
default:
g_assert_not_reached();
}
tlb_addr = tlb_read_ofs(entry, elt_ofs);
if (unlikely(!tlb_hit(tlb_addr, addr))) {
if (!victim_tlb_hit(env, mmu_idx, index, elt_ofs,
addr & TARGET_PAGE_MASK)) {
tlb_fill(env_cpu(env), addr, size, access_type, mmu_idx, retaddr);
/* TLB resize via tlb_fill may have moved the entry. */
index = tlb_index(env, mmu_idx, addr);
entry = tlb_entry(env, mmu_idx, addr);
}
tlb_addr = tlb_read_ofs(entry, elt_ofs);
}
if (!size) {
return NULL;
}
if (unlikely(tlb_addr & TLB_FLAGS_MASK)) {
CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index];
/* Reject I/O access, or other required slow-path. */
if (tlb_addr & (TLB_MMIO | TLB_BSWAP | TLB_DISCARD_WRITE)) {
return NULL;
}
/* Handle watchpoints. */
if (tlb_addr & TLB_WATCHPOINT) {
cpu_check_watchpoint(env_cpu(env), addr, size,
iotlbentry->attrs, wp_access, retaddr);
}
/* Handle clean RAM pages. */
if (tlb_addr & TLB_NOTDIRTY) {
notdirty_write(env_cpu(env), addr, size, iotlbentry, retaddr);
}
}
return (void *)((uintptr_t)addr + entry->addend);
}
void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
MMUAccessType access_type, int mmu_idx)
{
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
target_ulong tlb_addr, page;
target_ulong tlb_addr, page_addr;
size_t elt_ofs;
int flags;
switch (access_type) {
case MMU_DATA_LOAD:
@ -1325,20 +1292,19 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
default:
g_assert_not_reached();
}
page = addr & TARGET_PAGE_MASK;
tlb_addr = tlb_read_ofs(entry, elt_ofs);
if (!tlb_hit_page(tlb_addr, page)) {
uintptr_t index = tlb_index(env, mmu_idx, addr);
if (!victim_tlb_hit(env, mmu_idx, index, elt_ofs, page)) {
page_addr = addr & TARGET_PAGE_MASK;
if (!tlb_hit_page(tlb_addr, page_addr)) {
if (!victim_tlb_hit(env, mmu_idx, index, elt_ofs, page_addr)) {
CPUState *cs = env_cpu(env);
CPUClass *cc = CPU_GET_CLASS(cs);
if (!cc->tlb_fill(cs, addr, 0, access_type, mmu_idx, true, 0)) {
if (!cc->tlb_fill(cs, addr, fault_size, access_type,
mmu_idx, nonfault, retaddr)) {
/* Non-faulting page table read failed. */
return NULL;
*phost = NULL;
return TLB_INVALID_MASK;
}
/* TLB resize via tlb_fill may have moved the entry. */
@ -1346,15 +1312,89 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
}
tlb_addr = tlb_read_ofs(entry, elt_ofs);
}
flags = tlb_addr & TLB_FLAGS_MASK;
if (tlb_addr & ~TARGET_PAGE_MASK) {
/* IO access */
/* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */
if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY))) {
*phost = NULL;
return TLB_MMIO;
}
/* Everything else is RAM. */
*phost = (void *)((uintptr_t)addr + entry->addend);
return flags;
}
int probe_access_flags(CPUArchState *env, target_ulong addr,
MMUAccessType access_type, int mmu_idx,
bool nonfault, void **phost, uintptr_t retaddr)
{
int flags;
flags = probe_access_internal(env, addr, 0, access_type, mmu_idx,
nonfault, phost, retaddr);
/* Handle clean RAM pages. */
if (unlikely(flags & TLB_NOTDIRTY)) {
uintptr_t index = tlb_index(env, mmu_idx, addr);
CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index];
notdirty_write(env_cpu(env), addr, 1, iotlbentry, retaddr);
flags &= ~TLB_NOTDIRTY;
}
return flags;
}
void *probe_access(CPUArchState *env, target_ulong addr, int size,
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
{
void *host;
int flags;
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
flags = probe_access_internal(env, addr, size, access_type, mmu_idx,
false, &host, retaddr);
/* Per the interface, size == 0 merely faults the access. */
if (size == 0) {
return NULL;
}
return (void *)((uintptr_t)addr + entry->addend);
if (unlikely(flags & (TLB_NOTDIRTY | TLB_WATCHPOINT))) {
uintptr_t index = tlb_index(env, mmu_idx, addr);
CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index];
/* Handle watchpoints. */
if (flags & TLB_WATCHPOINT) {
int wp_access = (access_type == MMU_DATA_STORE
? BP_MEM_WRITE : BP_MEM_READ);
cpu_check_watchpoint(env_cpu(env), addr, size,
iotlbentry->attrs, wp_access, retaddr);
}
/* Handle clean RAM pages. */
if (flags & TLB_NOTDIRTY) {
notdirty_write(env_cpu(env), addr, 1, iotlbentry, retaddr);
}
}
return host;
}
void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
MMUAccessType access_type, int mmu_idx)
{
void *host;
int flags;
flags = probe_access_internal(env, addr, 0, access_type,
mmu_idx, true, &host, 0);
/* No combination of flags are expected by the caller. */
return flags ? NULL : host;
}
#ifdef CONFIG_PLUGIN
/*
@ -1363,8 +1403,12 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
* in the softmmu lookup code (or helper). We don't handle re-fills or
* checking the victim table. This is purely informational.
*
* This should never fail as the memory access being instrumented
* should have just filled the TLB.
* This almost never fails as the memory access being instrumented
* should have just filled the TLB. The one corner case is io_writex
* which can cause TLB flushes and potential resizing of the TLBs
* losing the information we need. In those cases we need to recover
* data from a copy of the iotlbentry. As long as this always occurs
* from the same thread (which a mem callback will be) this is safe.
*/
bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx,
@ -1388,8 +1432,13 @@ bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx,
data->v.ram.hostaddr = addr + tlbe->addend;
}
return true;
} else {
SavedIOTLB *saved = &cpu->saved_iotlb;
data->is_io = true;
data->v.io.section = saved->section;
data->v.io.offset = saved->mr_offset;
return true;
}
return false;
}
#endif
@ -1769,36 +1818,54 @@ int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr,
full_ldub_mmu);
}
uint32_t cpu_lduw_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
uint32_t cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return cpu_load_helper(env, addr, mmu_idx, ra, MO_TEUW,
MO_TE == MO_LE
? full_le_lduw_mmu : full_be_lduw_mmu);
return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEUW, full_be_lduw_mmu);
}
int cpu_ldsw_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
int cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return (int16_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_TESW,
MO_TE == MO_LE
? full_le_lduw_mmu : full_be_lduw_mmu);
return (int16_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_BESW,
full_be_lduw_mmu);
}
uint32_t cpu_ldl_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return cpu_load_helper(env, addr, mmu_idx, ra, MO_TEUL,
MO_TE == MO_LE
? full_le_ldul_mmu : full_be_ldul_mmu);
return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEUL, full_be_ldul_mmu);
}
uint64_t cpu_ldq_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return cpu_load_helper(env, addr, mmu_idx, ra, MO_TEQ,
MO_TE == MO_LE
? helper_le_ldq_mmu : helper_be_ldq_mmu);
return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEQ, helper_be_ldq_mmu);
}
uint32_t cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEUW, full_le_lduw_mmu);
}
int cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return (int16_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_LESW,
full_le_lduw_mmu);
}
uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEUL, full_le_ldul_mmu);
}
uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEQ, helper_le_ldq_mmu);
}
uint32_t cpu_ldub_data_ra(CPUArchState *env, target_ulong ptr,
@ -1812,25 +1879,50 @@ int cpu_ldsb_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
return cpu_ldsb_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint32_t cpu_lduw_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
uint32_t cpu_lduw_be_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
{
return cpu_lduw_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
return cpu_lduw_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
int cpu_ldsw_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
int cpu_ldsw_be_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
{
return cpu_ldsw_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
return cpu_ldsw_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint32_t cpu_ldl_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
uint32_t cpu_ldl_be_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
{
return cpu_ldl_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
return cpu_ldl_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint64_t cpu_ldq_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
uint64_t cpu_ldq_be_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
{
return cpu_ldq_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
return cpu_ldq_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint32_t cpu_lduw_le_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
{
return cpu_lduw_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
int cpu_ldsw_le_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
{
return cpu_ldsw_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint32_t cpu_ldl_le_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
{
return cpu_ldl_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint64_t cpu_ldq_le_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
{
return cpu_ldq_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint32_t cpu_ldub_data(CPUArchState *env, target_ulong ptr)
@ -1843,24 +1935,44 @@ int cpu_ldsb_data(CPUArchState *env, target_ulong ptr)
return cpu_ldsb_data_ra(env, ptr, 0);
}
uint32_t cpu_lduw_data(CPUArchState *env, target_ulong ptr)
uint32_t cpu_lduw_be_data(CPUArchState *env, target_ulong ptr)
{
return cpu_lduw_data_ra(env, ptr, 0);
return cpu_lduw_be_data_ra(env, ptr, 0);
}
int cpu_ldsw_data(CPUArchState *env, target_ulong ptr)
int cpu_ldsw_be_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldsw_data_ra(env, ptr, 0);
return cpu_ldsw_be_data_ra(env, ptr, 0);
}
uint32_t cpu_ldl_data(CPUArchState *env, target_ulong ptr)
uint32_t cpu_ldl_be_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldl_data_ra(env, ptr, 0);
return cpu_ldl_be_data_ra(env, ptr, 0);
}
uint64_t cpu_ldq_data(CPUArchState *env, target_ulong ptr)
uint64_t cpu_ldq_be_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldq_data_ra(env, ptr, 0);
return cpu_ldq_be_data_ra(env, ptr, 0);
}
uint32_t cpu_lduw_le_data(CPUArchState *env, target_ulong ptr)
{
return cpu_lduw_le_data_ra(env, ptr, 0);
}
int cpu_ldsw_le_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldsw_le_data_ra(env, ptr, 0);
}
uint32_t cpu_ldl_le_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldl_le_data_ra(env, ptr, 0);
}
uint64_t cpu_ldq_le_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldq_le_data_ra(env, ptr, 0);
}
/*
@ -2118,22 +2230,40 @@ void cpu_stb_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_UB);
}
void cpu_stw_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
int mmu_idx, uintptr_t retaddr)
void cpu_stw_be_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
int mmu_idx, uintptr_t retaddr)
{
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_TEUW);
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEUW);
}
void cpu_stl_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
int mmu_idx, uintptr_t retaddr)
void cpu_stl_be_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
int mmu_idx, uintptr_t retaddr)
{
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_TEUL);
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEUL);
}
void cpu_stq_mmuidx_ra(CPUArchState *env, target_ulong addr, uint64_t val,
int mmu_idx, uintptr_t retaddr)
void cpu_stq_be_mmuidx_ra(CPUArchState *env, target_ulong addr, uint64_t val,
int mmu_idx, uintptr_t retaddr)
{
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_TEQ);
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEQ);
}
void cpu_stw_le_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
int mmu_idx, uintptr_t retaddr)
{
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEUW);
}
void cpu_stl_le_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
int mmu_idx, uintptr_t retaddr)
{
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEUL);
}
void cpu_stq_le_mmuidx_ra(CPUArchState *env, target_ulong addr, uint64_t val,
int mmu_idx, uintptr_t retaddr)
{
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEQ);
}
void cpu_stb_data_ra(CPUArchState *env, target_ulong ptr,
@ -2142,22 +2272,40 @@ void cpu_stb_data_ra(CPUArchState *env, target_ulong ptr,
cpu_stb_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stw_data_ra(CPUArchState *env, target_ulong ptr,
uint32_t val, uintptr_t retaddr)
void cpu_stw_be_data_ra(CPUArchState *env, target_ulong ptr,
uint32_t val, uintptr_t retaddr)
{
cpu_stw_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
cpu_stw_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stl_data_ra(CPUArchState *env, target_ulong ptr,
uint32_t val, uintptr_t retaddr)
void cpu_stl_be_data_ra(CPUArchState *env, target_ulong ptr,
uint32_t val, uintptr_t retaddr)
{
cpu_stl_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
cpu_stl_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stq_data_ra(CPUArchState *env, target_ulong ptr,
uint64_t val, uintptr_t retaddr)
void cpu_stq_be_data_ra(CPUArchState *env, target_ulong ptr,
uint64_t val, uintptr_t retaddr)
{
cpu_stq_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
cpu_stq_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stw_le_data_ra(CPUArchState *env, target_ulong ptr,
uint32_t val, uintptr_t retaddr)
{
cpu_stw_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stl_le_data_ra(CPUArchState *env, target_ulong ptr,
uint32_t val, uintptr_t retaddr)
{
cpu_stl_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stq_le_data_ra(CPUArchState *env, target_ulong ptr,
uint64_t val, uintptr_t retaddr)
{
cpu_stq_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stb_data(CPUArchState *env, target_ulong ptr, uint32_t val)
@ -2165,19 +2313,34 @@ void cpu_stb_data(CPUArchState *env, target_ulong ptr, uint32_t val)
cpu_stb_data_ra(env, ptr, val, 0);
}
void cpu_stw_data(CPUArchState *env, target_ulong ptr, uint32_t val)
void cpu_stw_be_data(CPUArchState *env, target_ulong ptr, uint32_t val)
{
cpu_stw_data_ra(env, ptr, val, 0);
cpu_stw_be_data_ra(env, ptr, val, 0);
}
void cpu_stl_data(CPUArchState *env, target_ulong ptr, uint32_t val)
void cpu_stl_be_data(CPUArchState *env, target_ulong ptr, uint32_t val)
{
cpu_stl_data_ra(env, ptr, val, 0);
cpu_stl_be_data_ra(env, ptr, val, 0);
}
void cpu_stq_data(CPUArchState *env, target_ulong ptr, uint64_t val)
void cpu_stq_be_data(CPUArchState *env, target_ulong ptr, uint64_t val)
{
cpu_stq_data_ra(env, ptr, val, 0);
cpu_stq_be_data_ra(env, ptr, val, 0);
}
void cpu_stw_le_data(CPUArchState *env, target_ulong ptr, uint32_t val)
{
cpu_stw_le_data_ra(env, ptr, val, 0);
}
void cpu_stl_le_data(CPUArchState *env, target_ulong ptr, uint32_t val)
{
cpu_stl_le_data_ra(env, ptr, val, 0);
}
void cpu_stq_le_data(CPUArchState *env, target_ulong ptr, uint64_t val)
{
cpu_stq_le_data_ra(env, ptr, val, 0);
}
/* First set of helpers allows passing in of OI and RETADDR. This makes

View File

@ -182,12 +182,9 @@ static void tcg_set_tb_size(Object *obj, Visitor *v,
Error **errp)
{
TCGState *s = TCG_STATE(obj);
Error *error = NULL;
uint32_t value;
visit_type_uint32(v, name, &value, &error);
if (error) {
error_propagate(errp, error);
if (!visit_type_uint32(v, name, &value, errp)) {
return;
}
@ -203,14 +200,13 @@ static void tcg_accel_class_init(ObjectClass *oc, void *data)
object_class_property_add_str(oc, "thread",
tcg_get_thread,
tcg_set_thread,
NULL);
tcg_set_thread);
object_class_property_add(oc, "tb-size", "int",
tcg_get_tb_size, tcg_set_tb_size,
NULL, NULL, &error_abort);
NULL, NULL);
object_class_property_set_description(oc, "tb-size",
"TCG translation block cache size", &error_abort);
"TCG translation block cache size");
}

View File

@ -716,6 +716,54 @@ void HELPER(gvec_sar64i)(void *d, void *a, uint32_t desc)
clear_high(d, oprsz, desc);
}
void HELPER(gvec_rotl8i)(void *d, void *a, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
int shift = simd_data(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
*(uint8_t *)(d + i) = rol8(*(uint8_t *)(a + i), shift);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_rotl16i)(void *d, void *a, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
int shift = simd_data(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
*(uint16_t *)(d + i) = rol16(*(uint16_t *)(a + i), shift);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_rotl32i)(void *d, void *a, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
int shift = simd_data(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
*(uint32_t *)(d + i) = rol32(*(uint32_t *)(a + i), shift);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_rotl64i)(void *d, void *a, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
int shift = simd_data(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
*(uint64_t *)(d + i) = rol64(*(uint64_t *)(a + i), shift);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_shl8v)(void *d, void *a, void *b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
@ -860,6 +908,102 @@ void HELPER(gvec_sar64v)(void *d, void *a, void *b, uint32_t desc)
clear_high(d, oprsz, desc);
}
void HELPER(gvec_rotl8v)(void *d, void *a, void *b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
uint8_t sh = *(uint8_t *)(b + i) & 7;
*(uint8_t *)(d + i) = rol8(*(uint8_t *)(a + i), sh);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_rotl16v)(void *d, void *a, void *b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
uint8_t sh = *(uint16_t *)(b + i) & 15;
*(uint16_t *)(d + i) = rol16(*(uint16_t *)(a + i), sh);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_rotl32v)(void *d, void *a, void *b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
uint8_t sh = *(uint32_t *)(b + i) & 31;
*(uint32_t *)(d + i) = rol32(*(uint32_t *)(a + i), sh);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_rotl64v)(void *d, void *a, void *b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
uint8_t sh = *(uint64_t *)(b + i) & 63;
*(uint64_t *)(d + i) = rol64(*(uint64_t *)(a + i), sh);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_rotr8v)(void *d, void *a, void *b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
uint8_t sh = *(uint8_t *)(b + i) & 7;
*(uint8_t *)(d + i) = ror8(*(uint8_t *)(a + i), sh);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_rotr16v)(void *d, void *a, void *b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
uint8_t sh = *(uint16_t *)(b + i) & 15;
*(uint16_t *)(d + i) = ror16(*(uint16_t *)(a + i), sh);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_rotr32v)(void *d, void *a, void *b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
uint8_t sh = *(uint32_t *)(b + i) & 31;
*(uint32_t *)(d + i) = ror32(*(uint32_t *)(a + i), sh);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_rotr64v)(void *d, void *a, void *b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
uint8_t sh = *(uint64_t *)(b + i) & 63;
*(uint64_t *)(d + i) = ror64(*(uint64_t *)(a + i), sh);
}
clear_high(d, oprsz, desc);
}
#define DO_CMP1(NAME, TYPE, OP) \
void HELPER(NAME)(void *d, void *a, void *b, uint32_t desc) \
{ \

View File

@ -259,6 +259,11 @@ DEF_HELPER_FLAGS_3(gvec_sar16i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_sar32i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_sar64i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_rotl8i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_rotl16i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_rotl32i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_rotl64i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_shl8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_shl16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_shl32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
@ -274,6 +279,16 @@ DEF_HELPER_FLAGS_4(gvec_sar16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_sar32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_sar64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_rotl8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_rotl16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_rotl32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_rotl64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_rotr8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_rotr16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_rotr32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_rotr64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_eq8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_eq16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_eq32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)

View File

@ -1,10 +1,10 @@
# See docs/devel/tracing.txt for syntax documentation.
# TCG related tracing (mostly disabled by default)
# TCG related tracing
# cpu-exec.c
disable exec_tb(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR
disable exec_tb_nocache(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR
disable exec_tb_exit(void *last_tb, unsigned int flags) "tb:%p flags=0x%x"
exec_tb(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR
exec_tb_nocache(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR
exec_tb_exit(void *last_tb, unsigned int flags) "tb:%p flags=0x%x"
# translate-all.c
translate_block(void *tb, uintptr_t pc, uint8_t *tb_code) "tb:%p, pc:0x%"PRIxPTR", tb_code:%p"

View File

@ -173,8 +173,13 @@ struct page_collection {
#define TB_FOR_EACH_JMP(head_tb, tb, n) \
TB_FOR_EACH_TAGGED((head_tb)->jmp_list_head, tb, n, jmp_list_next)
/* In system mode we want L1_MAP to be based on ram offsets,
while in user mode we want it to be based on virtual addresses. */
/*
* In system mode we want L1_MAP to be based on ram offsets,
* while in user mode we want it to be based on virtual addresses.
*
* TODO: For user mode, see the caveat re host vs guest virtual
* address spaces near GUEST_ADDR_MAX.
*/
#if !defined(CONFIG_USER_ONLY)
#if HOST_LONG_BITS < TARGET_PHYS_ADDR_SPACE_BITS
# define L1_MAP_ADDR_SPACE_BITS HOST_LONG_BITS
@ -182,7 +187,7 @@ struct page_collection {
# define L1_MAP_ADDR_SPACE_BITS TARGET_PHYS_ADDR_SPACE_BITS
#endif
#else
# define L1_MAP_ADDR_SPACE_BITS TARGET_VIRT_ADDR_SPACE_BITS
# define L1_MAP_ADDR_SPACE_BITS MIN(HOST_LONG_BITS, TARGET_ABI_BITS)
#endif
/* Size of the L2 (and L3, etc) page tables. */
@ -379,6 +384,11 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
return 0;
}
void tb_destroy(TranslationBlock *tb)
{
qemu_spin_destroy(&tb->jmp_lock);
}
bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
{
TranslationBlock *tb;
@ -408,6 +418,7 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
/* one-shot translation, invalidate it immediately */
tb_phys_invalidate(tb, -1);
tcg_tb_remove(tb);
tb_destroy(tb);
}
r = true;
}
@ -536,6 +547,15 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc)
#endif
existing = atomic_cmpxchg(lp, NULL, pd);
if (unlikely(existing)) {
#ifndef CONFIG_USER_ONLY
{
int i;
for (i = 0; i < V_L2_SIZE; i++) {
qemu_spin_destroy(&pd[i].lock);
}
}
#endif
g_free(pd);
pd = existing;
}
@ -956,7 +976,12 @@ static inline size_t size_code_gen_buffer(size_t tb_size)
{
/* Size the buffer. */
if (tb_size == 0) {
tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
size_t phys_mem = qemu_get_host_physmem();
if (phys_mem == 0) {
tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
} else {
tb_size = MIN(DEFAULT_CODE_GEN_BUFFER_SIZE, phys_mem / 8);
}
}
if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) {
tb_size = MIN_CODE_GEN_BUFFER_SIZE;
@ -1789,14 +1814,43 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM) &&
qemu_log_in_addr_range(tb->pc)) {
FILE *logfile = qemu_log_lock();
int code_size, data_size = 0;
g_autoptr(GString) note = g_string_new("[tb header & initial instruction]");
size_t chunk_start = 0;
int insn = 0;
qemu_log("OUT: [size=%d]\n", gen_code_size);
if (tcg_ctx->data_gen_ptr) {
size_t code_size = tcg_ctx->data_gen_ptr - tb->tc.ptr;
size_t data_size = gen_code_size - code_size;
size_t i;
code_size = tcg_ctx->data_gen_ptr - tb->tc.ptr;
data_size = gen_code_size - code_size;
} else {
code_size = gen_code_size;
}
log_disas(tb->tc.ptr, code_size);
/* Dump header and the first instruction */
chunk_start = tcg_ctx->gen_insn_end_off[insn];
log_disas(tb->tc.ptr, chunk_start, note->str);
/*
* Dump each instruction chunk, wrapping up empty chunks into
* the next instruction. The whole array is offset so the
* first entry is the beginning of the 2nd instruction.
*/
while (insn <= tb->icount && chunk_start < code_size) {
size_t chunk_end = tcg_ctx->gen_insn_end_off[insn];
if (chunk_end > chunk_start) {
g_string_printf(note, "[guest addr: " TARGET_FMT_lx "]",
tcg_ctx->gen_insn_data[insn][0]);
log_disas(tb->tc.ptr + chunk_start, chunk_end - chunk_start,
note->str);
chunk_start = chunk_end;
}
insn++;
}
/* Finally dump any data we may have after the block */
if (data_size) {
int i;
qemu_log(" data: [size=%d]\n", data_size);
for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
if (sizeof(tcg_target_ulong) == 8) {
qemu_log("0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n",
@ -1808,8 +1862,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
*(uint32_t *)(tcg_ctx->data_gen_ptr + i));
}
}
} else {
log_disas(tb->tc.ptr, gen_code_size);
}
qemu_log("\n");
qemu_log_flush();
@ -1854,6 +1906,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
orig_aligned -= ROUND_UP(sizeof(*tb), qemu_icache_linesize);
atomic_set(&tcg_ctx->code_gen_ptr, (void *)orig_aligned);
tb_destroy(tb);
return existing_tb;
}
tcg_tb_insert(tb);
@ -2203,6 +2256,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
tb_phys_invalidate(tb->orig_tb, -1);
}
tcg_tb_remove(tb);
tb_destroy(tb);
}
/* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
@ -2497,9 +2551,7 @@ void page_set_flags(target_ulong start, target_ulong end, int flags)
/* This function should never be called with addresses outside the
guest address space. If this assert fires, it probably indicates
a missing call to h2g_valid. */
#if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS
assert(end <= ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
#endif
assert(end - 1 <= GUEST_ADDR_MAX);
assert(start < end);
assert_memory_lock();
@ -2535,9 +2587,9 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
/* This function should never be called with addresses outside the
guest address space. If this assert fires, it probably indicates
a missing call to h2g_valid. */
#if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS
assert(start < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
#endif
if (TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS) {
assert(start < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
}
if (len == 0) {
return 0;

View File

@ -190,13 +190,12 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
g_assert_not_reached();
}
void *probe_access(CPUArchState *env, target_ulong addr, int size,
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
static int probe_access_internal(CPUArchState *env, target_ulong addr,
int fault_size, MMUAccessType access_type,
bool nonfault, uintptr_t ra)
{
int flags;
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
switch (access_type) {
case MMU_DATA_STORE:
flags = PAGE_WRITE;
@ -211,13 +210,39 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size,
g_assert_not_reached();
}
if (!guest_addr_valid(addr) || page_check_range(addr, size, flags) < 0) {
CPUState *cpu = env_cpu(env);
CPUClass *cc = CPU_GET_CLASS(cpu);
cc->tlb_fill(cpu, addr, size, access_type, MMU_USER_IDX, false,
retaddr);
g_assert_not_reached();
if (!guest_addr_valid(addr) || page_check_range(addr, 1, flags) < 0) {
if (nonfault) {
return TLB_INVALID_MASK;
} else {
CPUState *cpu = env_cpu(env);
CPUClass *cc = CPU_GET_CLASS(cpu);
cc->tlb_fill(cpu, addr, fault_size, access_type,
MMU_USER_IDX, false, ra);
g_assert_not_reached();
}
}
return 0;
}
int probe_access_flags(CPUArchState *env, target_ulong addr,
MMUAccessType access_type, int mmu_idx,
bool nonfault, void **phost, uintptr_t ra)
{
int flags;
flags = probe_access_internal(env, addr, 0, access_type, nonfault, ra);
*phost = flags ? NULL : g2h(addr);
return flags;
}
void *probe_access(CPUArchState *env, target_ulong addr, int size,
MMUAccessType access_type, int mmu_idx, uintptr_t ra)
{
int flags;
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
flags = probe_access_internal(env, addr, size, access_type, false, ra);
g_assert(flags == 0);
return size ? g2h(addr) : NULL;
}
@ -492,6 +517,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
#if defined(__NetBSD__)
#include <ucontext.h>
#include <sys/siginfo.h>
#endif
int cpu_signal_handler(int host_signum, void *pinfo,
@ -500,10 +526,12 @@ int cpu_signal_handler(int host_signum, void *pinfo,
siginfo_t *info = pinfo;
#if defined(__NetBSD__)
ucontext_t *uc = puc;
siginfo_t *si = pinfo;
#else
ucontext_t *uc = puc;
#endif
unsigned long pc;
uint32_t fsr;
int is_write;
#if defined(__NetBSD__)
@ -514,15 +542,48 @@ int cpu_signal_handler(int host_signum, void *pinfo,
pc = uc->uc_mcontext.arm_pc;
#endif
/* error_code is the FSR value, in which bit 11 is WnR (assuming a v6 or
* later processor; on v5 we will always report this as a read).
#ifdef __NetBSD__
fsr = si->si_trap;
#else
fsr = uc->uc_mcontext.error_code;
#endif
/*
* In the FSR, bit 11 is WnR, assuming a v6 or
* later processor. On v5 we will always report
* this as a read, which will fail later.
*/
is_write = extract32(uc->uc_mcontext.error_code, 11, 1);
is_write = extract32(fsr, 11, 1);
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
}
#elif defined(__aarch64__)
#if defined(__NetBSD__)
#include <ucontext.h>
#include <sys/siginfo.h>
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
{
ucontext_t *uc = puc;
siginfo_t *si = pinfo;
unsigned long pc;
int is_write;
uint32_t esr;
pc = uc->uc_mcontext.__gregs[_REG_PC];
esr = si->si_trap;
/*
* siginfo_t::si_trap is the ESR value, for data aborts ESR.EC
* is 0b10010x: then bit 6 is the WnR bit
*/
is_write = extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1) == 1;
return handle_cpu_signal(pc, si, is_write, &uc->uc_sigmask);
}
#else
#ifndef ESR_MAGIC
/* Pre-3.16 kernel headers don't have these, so provide fallback definitions */
#define ESR_MAGIC 0x45535201
@ -585,6 +646,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
}
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
}
#endif
#elif defined(__s390__)
@ -758,46 +820,90 @@ int cpu_ldsb_data(CPUArchState *env, abi_ptr ptr)
return ret;
}
uint32_t cpu_lduw_data(CPUArchState *env, abi_ptr ptr)
uint32_t cpu_lduw_be_data(CPUArchState *env, abi_ptr ptr)
{
uint32_t ret;
uint16_t meminfo = trace_mem_get_info(MO_TEUW, MMU_USER_IDX, false);
uint16_t meminfo = trace_mem_get_info(MO_BEUW, MMU_USER_IDX, false);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
ret = lduw_p(g2h(ptr));
ret = lduw_be_p(g2h(ptr));
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
return ret;
}
int cpu_ldsw_data(CPUArchState *env, abi_ptr ptr)
int cpu_ldsw_be_data(CPUArchState *env, abi_ptr ptr)
{
int ret;
uint16_t meminfo = trace_mem_get_info(MO_TESW, MMU_USER_IDX, false);
uint16_t meminfo = trace_mem_get_info(MO_BESW, MMU_USER_IDX, false);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
ret = ldsw_p(g2h(ptr));
ret = ldsw_be_p(g2h(ptr));
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
return ret;
}
uint32_t cpu_ldl_data(CPUArchState *env, abi_ptr ptr)
uint32_t cpu_ldl_be_data(CPUArchState *env, abi_ptr ptr)
{
uint32_t ret;
uint16_t meminfo = trace_mem_get_info(MO_TEUL, MMU_USER_IDX, false);
uint16_t meminfo = trace_mem_get_info(MO_BEUL, MMU_USER_IDX, false);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
ret = ldl_p(g2h(ptr));
ret = ldl_be_p(g2h(ptr));
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
return ret;
}
uint64_t cpu_ldq_data(CPUArchState *env, abi_ptr ptr)
uint64_t cpu_ldq_be_data(CPUArchState *env, abi_ptr ptr)
{
uint64_t ret;
uint16_t meminfo = trace_mem_get_info(MO_TEQ, MMU_USER_IDX, false);
uint16_t meminfo = trace_mem_get_info(MO_BEQ, MMU_USER_IDX, false);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
ret = ldq_p(g2h(ptr));
ret = ldq_be_p(g2h(ptr));
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
return ret;
}
uint32_t cpu_lduw_le_data(CPUArchState *env, abi_ptr ptr)
{
uint32_t ret;
uint16_t meminfo = trace_mem_get_info(MO_LEUW, MMU_USER_IDX, false);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
ret = lduw_le_p(g2h(ptr));
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
return ret;
}
int cpu_ldsw_le_data(CPUArchState *env, abi_ptr ptr)
{
int ret;
uint16_t meminfo = trace_mem_get_info(MO_LESW, MMU_USER_IDX, false);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
ret = ldsw_le_p(g2h(ptr));
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
return ret;
}
uint32_t cpu_ldl_le_data(CPUArchState *env, abi_ptr ptr)
{
uint32_t ret;
uint16_t meminfo = trace_mem_get_info(MO_LEUL, MMU_USER_IDX, false);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
ret = ldl_le_p(g2h(ptr));
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
return ret;
}
uint64_t cpu_ldq_le_data(CPUArchState *env, abi_ptr ptr)
{
uint64_t ret;
uint16_t meminfo = trace_mem_get_info(MO_LEQ, MMU_USER_IDX, false);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
ret = ldq_le_p(g2h(ptr));
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
return ret;
}
@ -822,42 +928,82 @@ int cpu_ldsb_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
return ret;
}
uint32_t cpu_lduw_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
uint32_t cpu_lduw_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
{
uint32_t ret;
set_helper_retaddr(retaddr);
ret = cpu_lduw_data(env, ptr);
ret = cpu_lduw_be_data(env, ptr);
clear_helper_retaddr();
return ret;
}
int cpu_ldsw_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
int cpu_ldsw_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
{
int ret;
set_helper_retaddr(retaddr);
ret = cpu_ldsw_data(env, ptr);
ret = cpu_ldsw_be_data(env, ptr);
clear_helper_retaddr();
return ret;
}
uint32_t cpu_ldl_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
uint32_t cpu_ldl_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
{
uint32_t ret;
set_helper_retaddr(retaddr);
ret = cpu_ldl_data(env, ptr);
ret = cpu_ldl_be_data(env, ptr);
clear_helper_retaddr();
return ret;
}
uint64_t cpu_ldq_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
uint64_t cpu_ldq_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
{
uint64_t ret;
set_helper_retaddr(retaddr);
ret = cpu_ldq_data(env, ptr);
ret = cpu_ldq_be_data(env, ptr);
clear_helper_retaddr();
return ret;
}
uint32_t cpu_lduw_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
{
uint32_t ret;
set_helper_retaddr(retaddr);
ret = cpu_lduw_le_data(env, ptr);
clear_helper_retaddr();
return ret;
}
int cpu_ldsw_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
{
int ret;
set_helper_retaddr(retaddr);
ret = cpu_ldsw_le_data(env, ptr);
clear_helper_retaddr();
return ret;
}
uint32_t cpu_ldl_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
{
uint32_t ret;
set_helper_retaddr(retaddr);
ret = cpu_ldl_le_data(env, ptr);
clear_helper_retaddr();
return ret;
}
uint64_t cpu_ldq_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
{
uint64_t ret;
set_helper_retaddr(retaddr);
ret = cpu_ldq_le_data(env, ptr);
clear_helper_retaddr();
return ret;
}
@ -871,30 +1017,57 @@ void cpu_stb_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
}
void cpu_stw_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
void cpu_stw_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
{
uint16_t meminfo = trace_mem_get_info(MO_TEUW, MMU_USER_IDX, true);
uint16_t meminfo = trace_mem_get_info(MO_BEUW, MMU_USER_IDX, true);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
stw_p(g2h(ptr), val);
stw_be_p(g2h(ptr), val);
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
}
void cpu_stl_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
void cpu_stl_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
{
uint16_t meminfo = trace_mem_get_info(MO_TEUL, MMU_USER_IDX, true);
uint16_t meminfo = trace_mem_get_info(MO_BEUL, MMU_USER_IDX, true);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
stl_p(g2h(ptr), val);
stl_be_p(g2h(ptr), val);
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
}
void cpu_stq_data(CPUArchState *env, abi_ptr ptr, uint64_t val)
void cpu_stq_be_data(CPUArchState *env, abi_ptr ptr, uint64_t val)
{
uint16_t meminfo = trace_mem_get_info(MO_TEQ, MMU_USER_IDX, true);
uint16_t meminfo = trace_mem_get_info(MO_BEQ, MMU_USER_IDX, true);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
stq_p(g2h(ptr), val);
stq_be_p(g2h(ptr), val);
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
}
void cpu_stw_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
{
uint16_t meminfo = trace_mem_get_info(MO_LEUW, MMU_USER_IDX, true);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
stw_le_p(g2h(ptr), val);
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
}
void cpu_stl_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
{
uint16_t meminfo = trace_mem_get_info(MO_LEUL, MMU_USER_IDX, true);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
stl_le_p(g2h(ptr), val);
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
}
void cpu_stq_le_data(CPUArchState *env, abi_ptr ptr, uint64_t val)
{
uint16_t meminfo = trace_mem_get_info(MO_LEQ, MMU_USER_IDX, true);
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
stq_le_p(g2h(ptr), val);
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
}
@ -906,27 +1079,51 @@ void cpu_stb_data_ra(CPUArchState *env, abi_ptr ptr,
clear_helper_retaddr();
}
void cpu_stw_data_ra(CPUArchState *env, abi_ptr ptr,
uint32_t val, uintptr_t retaddr)
void cpu_stw_be_data_ra(CPUArchState *env, abi_ptr ptr,
uint32_t val, uintptr_t retaddr)
{
set_helper_retaddr(retaddr);
cpu_stw_data(env, ptr, val);
cpu_stw_be_data(env, ptr, val);
clear_helper_retaddr();
}
void cpu_stl_data_ra(CPUArchState *env, abi_ptr ptr,
uint32_t val, uintptr_t retaddr)
void cpu_stl_be_data_ra(CPUArchState *env, abi_ptr ptr,
uint32_t val, uintptr_t retaddr)
{
set_helper_retaddr(retaddr);
cpu_stl_data(env, ptr, val);
cpu_stl_be_data(env, ptr, val);
clear_helper_retaddr();
}
void cpu_stq_data_ra(CPUArchState *env, abi_ptr ptr,
uint64_t val, uintptr_t retaddr)
void cpu_stq_be_data_ra(CPUArchState *env, abi_ptr ptr,
uint64_t val, uintptr_t retaddr)
{
set_helper_retaddr(retaddr);
cpu_stq_data(env, ptr, val);
cpu_stq_be_data(env, ptr, val);
clear_helper_retaddr();
}
void cpu_stw_le_data_ra(CPUArchState *env, abi_ptr ptr,
uint32_t val, uintptr_t retaddr)
{
set_helper_retaddr(retaddr);
cpu_stw_le_data(env, ptr, val);
clear_helper_retaddr();
}
void cpu_stl_le_data_ra(CPUArchState *env, abi_ptr ptr,
uint32_t val, uintptr_t retaddr)
{
set_helper_retaddr(retaddr);
cpu_stl_le_data(env, ptr, val);
clear_helper_retaddr();
}
void cpu_stq_le_data_ra(CPUArchState *env, abi_ptr ptr,
uint64_t val, uintptr_t retaddr)
{
set_helper_retaddr(retaddr);
cpu_stq_le_data(env, ptr, val);
clear_helper_retaddr();
}

1
accel/xen/Makefile.objs Normal file
View File

@ -0,0 +1 @@
obj-y += xen-all.o

View File

@ -16,6 +16,7 @@
#include "hw/xen/xen_pt.h"
#include "chardev/char.h"
#include "sysemu/accel.h"
#include "sysemu/xen.h"
#include "sysemu/runstate.h"
#include "migration/misc.h"
#include "migration/global_state.h"
@ -31,6 +32,8 @@
do { } while (0)
#endif
bool xen_allowed;
xc_interface *xen_xc;
xenforeignmemory_handle *xen_fmem;
xendevicemodel_handle *xen_dmod;
@ -129,12 +132,12 @@ static void xen_change_state_handler(void *opaque, int running,
static bool xen_get_igd_gfx_passthru(Object *obj, Error **errp)
{
return has_igd_gfx_passthru;
return xen_igd_gfx_pt_enabled();
}
static void xen_set_igd_gfx_passthru(Object *obj, bool value, Error **errp)
{
has_igd_gfx_passthru = value;
xen_igd_gfx_pt_set(value, errp);
}
static void xen_setup_post(MachineState *ms, AccelState *accel)
@ -198,10 +201,9 @@ static void xen_accel_class_init(ObjectClass *oc, void *data)
compat_props_add(ac->compat_props, compat, G_N_ELEMENTS(compat));
object_class_property_add_bool(oc, "igd-passthru",
xen_get_igd_gfx_passthru, xen_set_igd_gfx_passthru,
&error_abort);
xen_get_igd_gfx_passthru, xen_set_igd_gfx_passthru);
object_class_property_set_description(oc, "igd-passthru",
"Set on/off to enable/disable igd passthrou", &error_abort);
"Set on/off to enable/disable igd passthrou");
}
#define TYPE_XEN_ACCEL ACCEL_CLASS_NAME("xen")

View File

@ -28,3 +28,8 @@ common-obj-$(CONFIG_AUDIO_SDL) += sdl.mo
sdl.mo-objs = sdlaudio.o
sdl.mo-cflags := $(SDL_CFLAGS)
sdl.mo-libs := $(SDL_LIBS)
# jack module
common-obj-$(CONFIG_AUDIO_JACK) += jack.mo
jack.mo-objs = jackaudio.o
jack.mo-libs := $(JACK_LIBS)

View File

@ -649,7 +649,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
total += isamp;
}
if (!hw->pcm_ops->volume_in) {
if (hw->pcm_ops && !hw->pcm_ops->volume_in) {
mixeng_volume (sw->buf, ret, &sw->vol);
}
@ -736,7 +736,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
if (swlim) {
sw->conv (sw->buf, buf, swlim);
if (!sw->hw->pcm_ops->volume_out) {
if (sw->hw->pcm_ops && !sw->hw->pcm_ops->volume_out) {
mixeng_volume (sw->buf, swlim, &sw->vol);
}
}
@ -1969,6 +1969,7 @@ void audio_create_pdos(Audiodev *dev)
CASE(ALSA, alsa, Alsa);
CASE(COREAUDIO, coreaudio, Coreaudio);
CASE(DSOUND, dsound, );
CASE(JACK, jack, Jack);
CASE(OSS, oss, Oss);
CASE(PA, pa, Pa);
CASE(SDL, sdl, );

View File

@ -60,7 +60,7 @@ typedef enum {
struct audio_capture_ops {
void (*notify) (void *opaque, audcnotification_e cmd);
void (*capture) (void *opaque, void *buf, int size);
void (*capture) (void *opaque, const void *buf, int size);
void (*destroy) (void *opaque);
};
@ -163,7 +163,7 @@ int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
bool audio_is_cleaning_up(void);
void audio_cleanup(void);
void audio_sample_to_uint64(void *samples, int pos,
void audio_sample_to_uint64(const void *samples, int pos,
uint64_t *left, uint64_t *right);
void audio_sample_from_uint64(void *samples, int pos,
uint64_t left, uint64_t right);

View File

@ -421,11 +421,12 @@ typedef struct {
GList *path;
} LegacyPrintVisitor;
static void lv_start_struct(Visitor *v, const char *name, void **obj,
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)
@ -453,27 +454,30 @@ static void lv_print_key(Visitor *v, const char *name)
printf("%s=", name);
}
static void lv_type_int64(Visitor *v, const char *name, int64_t *obj,
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 void lv_type_uint64(Visitor *v, const char *name, uint64_t *obj,
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 void lv_type_bool(Visitor *v, const char *name, bool *obj, Error **errp)
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 void lv_type_str(Visitor *v, const char *name, char **obj, Error **errp)
static bool lv_type_str(Visitor *v, const char *name, char **obj, Error **errp)
{
const char *str = *obj;
lv_print_key(v, name);
@ -484,6 +488,7 @@ static void lv_type_str(Visitor *v, const char *name, char **obj, Error **errp)
}
putchar(*str++);
}
return true;
}
static void lv_complete(Visitor *v, void *opaque)

View File

@ -330,6 +330,8 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
dev->u.coreaudio.TYPE);
case AUDIODEV_DRIVER_DSOUND:
return dev->u.dsound.TYPE;
case AUDIODEV_DRIVER_JACK:
return qapi_AudiodevJackPerDirectionOptions_base(dev->u.jack.TYPE);
case AUDIODEV_DRIVER_OSS:
return qapi_AudiodevOssPerDirectionOptions_base(dev->u.oss.TYPE);
case AUDIODEV_DRIVER_PA:

670
audio/jackaudio.c Normal file
View File

@ -0,0 +1,670 @@
/*
* QEMU JACK Audio Connection Kit Client
*
* Copyright (c) 2020 Geoffrey McRae (gnif)
*
* 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 "qemu/module.h"
#include "qemu/atomic.h"
#include "qemu-common.h"
#include "audio.h"
#define AUDIO_CAP "jack"
#include "audio_int.h"
#include <jack/jack.h>
#include <jack/thread.h>
struct QJack;
typedef enum QJackState {
QJACK_STATE_DISCONNECTED,
QJACK_STATE_RUNNING,
QJACK_STATE_SHUTDOWN
}
QJackState;
typedef struct QJackBuffer {
int channels;
int frames;
uint32_t used;
int rptr, wptr;
float **data;
}
QJackBuffer;
typedef struct QJackClient {
AudiodevJackPerDirectionOptions *opt;
bool out;
bool enabled;
bool connect_ports;
int packets;
QJackState state;
jack_client_t *client;
jack_nframes_t freq;
struct QJack *j;
int nchannels;
int buffersize;
jack_port_t **port;
QJackBuffer fifo;
}
QJackClient;
typedef struct QJackOut {
HWVoiceOut hw;
QJackClient c;
}
QJackOut;
typedef struct QJackIn {
HWVoiceIn hw;
QJackClient c;
}
QJackIn;
static int qjack_client_init(QJackClient *c);
static void qjack_client_connect_ports(QJackClient *c);
static void qjack_client_fini(QJackClient *c);
static void qjack_buffer_create(QJackBuffer *buffer, int channels, int frames)
{
buffer->channels = channels;
buffer->frames = frames;
buffer->used = 0;
buffer->rptr = 0;
buffer->wptr = 0;
buffer->data = g_malloc(channels * sizeof(float *));
for (int i = 0; i < channels; ++i) {
buffer->data[i] = g_malloc(frames * sizeof(float));
}
}
static void qjack_buffer_clear(QJackBuffer *buffer)
{
assert(buffer->data);
atomic_store_release(&buffer->used, 0);
buffer->rptr = 0;
buffer->wptr = 0;
}
static void qjack_buffer_free(QJackBuffer *buffer)
{
if (!buffer->data) {
return;
}
for (int i = 0; i < buffer->channels; ++i) {
g_free(buffer->data[i]);
}
g_free(buffer->data);
buffer->data = NULL;
}
/* write PCM interleaved */
static int qjack_buffer_write(QJackBuffer *buffer, float *data, int size)
{
assert(buffer->data);
const int samples = size / sizeof(float);
int frames = samples / buffer->channels;
const int avail = buffer->frames - atomic_load_acquire(&buffer->used);
if (frames > avail) {
frames = avail;
}
int copy = frames;
int wptr = buffer->wptr;
while (copy) {
for (int c = 0; c < buffer->channels; ++c) {
buffer->data[c][wptr] = *data++;
}
if (++wptr == buffer->frames) {
wptr = 0;
}
--copy;
}
buffer->wptr = wptr;
atomic_add(&buffer->used, frames);
return frames * buffer->channels * sizeof(float);
};
/* write PCM linear */
static int qjack_buffer_write_l(QJackBuffer *buffer, float **dest, int frames)
{
assert(buffer->data);
const int avail = buffer->frames - atomic_load_acquire(&buffer->used);
int wptr = buffer->wptr;
if (frames > avail) {
frames = avail;
}
int right = buffer->frames - wptr;
if (right > frames) {
right = frames;
}
const int left = frames - right;
for (int c = 0; c < buffer->channels; ++c) {
memcpy(buffer->data[c] + wptr, dest[c] , right * sizeof(float));
memcpy(buffer->data[c] , dest[c] + right, left * sizeof(float));
}
wptr += frames;
if (wptr >= buffer->frames) {
wptr -= buffer->frames;
}
buffer->wptr = wptr;
atomic_add(&buffer->used, frames);
return frames;
}
/* read PCM interleaved */
static int qjack_buffer_read(QJackBuffer *buffer, float *dest, int size)
{
assert(buffer->data);
const int samples = size / sizeof(float);
int frames = samples / buffer->channels;
const int avail = atomic_load_acquire(&buffer->used);
if (frames > avail) {
frames = avail;
}
int copy = frames;
int rptr = buffer->rptr;
while (copy) {
for (int c = 0; c < buffer->channels; ++c) {
*dest++ = buffer->data[c][rptr];
}
if (++rptr == buffer->frames) {
rptr = 0;
}
--copy;
}
buffer->rptr = rptr;
atomic_sub(&buffer->used, frames);
return frames * buffer->channels * sizeof(float);
}
/* read PCM linear */
static int qjack_buffer_read_l(QJackBuffer *buffer, float **dest, int frames)
{
assert(buffer->data);
int copy = frames;
const int used = atomic_load_acquire(&buffer->used);
int rptr = buffer->rptr;
if (copy > used) {
copy = used;
}
int right = buffer->frames - rptr;
if (right > copy) {
right = copy;
}
const int left = copy - right;
for (int c = 0; c < buffer->channels; ++c) {
memcpy(dest[c] , buffer->data[c] + rptr, right * sizeof(float));
memcpy(dest[c] + right, buffer->data[c] , left * sizeof(float));
}
rptr += copy;
if (rptr >= buffer->frames) {
rptr -= buffer->frames;
}
buffer->rptr = rptr;
atomic_sub(&buffer->used, copy);
return copy;
}
static int qjack_process(jack_nframes_t nframes, void *arg)
{
QJackClient *c = (QJackClient *)arg;
if (c->state != QJACK_STATE_RUNNING) {
return 0;
}
/* get the buffers for the ports */
float *buffers[c->nchannels];
for (int i = 0; i < c->nchannels; ++i) {
buffers[i] = jack_port_get_buffer(c->port[i], nframes);
}
if (c->out) {
if (likely(c->enabled)) {
qjack_buffer_read_l(&c->fifo, buffers, nframes);
} else {
for(int i = 0; i < c->nchannels; ++i) {
memset(buffers[i], 0, nframes * sizeof(float));
}
}
} else {
if (likely(c->enabled)) {
qjack_buffer_write_l(&c->fifo, buffers, nframes);
}
}
return 0;
}
static void qjack_port_registration(jack_port_id_t port, int reg, void *arg)
{
if (reg) {
QJackClient *c = (QJackClient *)arg;
c->connect_ports = true;
}
}
static int qjack_xrun(void *arg)
{
QJackClient *c = (QJackClient *)arg;
if (c->state != QJACK_STATE_RUNNING) {
return 0;
}
qjack_buffer_clear(&c->fifo);
return 0;
}
static void qjack_shutdown(void *arg)
{
QJackClient *c = (QJackClient *)arg;
c->state = QJACK_STATE_SHUTDOWN;
}
static void qjack_client_recover(QJackClient *c)
{
if (c->state == QJACK_STATE_SHUTDOWN) {
qjack_client_fini(c);
}
/* packets is used simply to throttle this */
if (c->state == QJACK_STATE_DISCONNECTED &&
c->packets % 100 == 0) {
/* if enabled then attempt to recover */
if (c->enabled) {
dolog("attempting to reconnect to server\n");
qjack_client_init(c);
}
}
}
static size_t qjack_write(HWVoiceOut *hw, void *buf, size_t len)
{
QJackOut *jo = (QJackOut *)hw;
++jo->c.packets;
if (jo->c.state != QJACK_STATE_RUNNING) {
qjack_client_recover(&jo->c);
return len;
}
qjack_client_connect_ports(&jo->c);
return qjack_buffer_write(&jo->c.fifo, buf, len);
}
static size_t qjack_read(HWVoiceIn *hw, void *buf, size_t len)
{
QJackIn *ji = (QJackIn *)hw;
++ji->c.packets;
if (ji->c.state != QJACK_STATE_RUNNING) {
qjack_client_recover(&ji->c);
return len;
}
qjack_client_connect_ports(&ji->c);
return qjack_buffer_read(&ji->c.fifo, buf, len);
}
static void qjack_client_connect_ports(QJackClient *c)
{
if (!c->connect_ports || !c->opt->connect_ports) {
return;
}
c->connect_ports = false;
const char **ports;
ports = jack_get_ports(c->client, c->opt->connect_ports, NULL,
c->out ? JackPortIsInput : JackPortIsOutput);
if (!ports) {
return;
}
for (int i = 0; i < c->nchannels && ports[i]; ++i) {
const char *p = jack_port_name(c->port[i]);
if (jack_port_connected_to(c->port[i], ports[i])) {
continue;
}
if (c->out) {
dolog("connect %s -> %s\n", p, ports[i]);
jack_connect(c->client, p, ports[i]);
} else {
dolog("connect %s -> %s\n", ports[i], p);
jack_connect(c->client, ports[i], p);
}
}
}
static int qjack_client_init(QJackClient *c)
{
jack_status_t status;
char client_name[jack_client_name_size()];
jack_options_t options = JackNullOption;
if (c->state == QJACK_STATE_RUNNING) {
return 0;
}
c->connect_ports = true;
snprintf(client_name, sizeof(client_name), "%s-%s",
c->out ? "out" : "in",
c->opt->client_name ? c->opt->client_name : qemu_get_vm_name());
if (c->opt->exact_name) {
options |= JackUseExactName;
}
if (!c->opt->start_server) {
options |= JackNoStartServer;
}
if (c->opt->server_name) {
options |= JackServerName;
}
c->client = jack_client_open(client_name, options, &status,
c->opt->server_name);
if (c->client == NULL) {
dolog("jack_client_open failed: status = 0x%2.0x\n", status);
if (status & JackServerFailed) {
dolog("unable to connect to JACK server\n");
}
return -1;
}
c->freq = jack_get_sample_rate(c->client);
if (status & JackServerStarted) {
dolog("JACK server started\n");
}
if (status & JackNameNotUnique) {
dolog("JACK unique name assigned %s\n",
jack_get_client_name(c->client));
}
jack_set_process_callback(c->client, qjack_process , c);
jack_set_port_registration_callback(c->client, qjack_port_registration, c);
jack_set_xrun_callback(c->client, qjack_xrun, c);
jack_on_shutdown(c->client, qjack_shutdown, c);
/* allocate and register the ports */
c->port = g_malloc(sizeof(jack_port_t *) * c->nchannels);
for (int i = 0; i < c->nchannels; ++i) {
char port_name[16];
snprintf(
port_name,
sizeof(port_name),
c->out ? "output %d" : "input %d",
i);
c->port[i] = jack_port_register(
c->client,
port_name,
JACK_DEFAULT_AUDIO_TYPE,
c->out ? JackPortIsOutput : JackPortIsInput,
0);
}
/* activate the session */
jack_activate(c->client);
c->buffersize = jack_get_buffer_size(c->client);
/*
* ensure the buffersize is no smaller then 512 samples, some (all?) qemu
* virtual devices do not work correctly otherwise
*/
if (c->buffersize < 512) {
c->buffersize = 512;
}
/* create a 2 period buffer */
qjack_buffer_create(&c->fifo, c->nchannels, c->buffersize * 2);
qjack_client_connect_ports(c);
c->state = QJACK_STATE_RUNNING;
return 0;
}
static int qjack_init_out(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
{
QJackOut *jo = (QJackOut *)hw;
Audiodev *dev = (Audiodev *)drv_opaque;
qjack_client_fini(&jo->c);
jo->c.out = true;
jo->c.enabled = false;
jo->c.nchannels = as->nchannels;
jo->c.opt = dev->u.jack.out;
int ret = qjack_client_init(&jo->c);
if (ret != 0) {
return ret;
}
/* report the buffer size to qemu */
hw->samples = jo->c.buffersize;
/* report the audio format we support */
struct audsettings os = {
.freq = jo->c.freq,
.nchannels = jo->c.nchannels,
.fmt = AUDIO_FORMAT_F32,
.endianness = 0
};
audio_pcm_init_info(&hw->info, &os);
dolog("JACK output configured for %dHz (%d samples)\n",
jo->c.freq, jo->c.buffersize);
return 0;
}
static int qjack_init_in(HWVoiceIn *hw, struct audsettings *as,
void *drv_opaque)
{
QJackIn *ji = (QJackIn *)hw;
Audiodev *dev = (Audiodev *)drv_opaque;
qjack_client_fini(&ji->c);
ji->c.out = false;
ji->c.enabled = false;
ji->c.nchannels = as->nchannels;
ji->c.opt = dev->u.jack.in;
int ret = qjack_client_init(&ji->c);
if (ret != 0) {
return ret;
}
/* report the buffer size to qemu */
hw->samples = ji->c.buffersize;
/* report the audio format we support */
struct audsettings is = {
.freq = ji->c.freq,
.nchannels = ji->c.nchannels,
.fmt = AUDIO_FORMAT_F32,
.endianness = 0
};
audio_pcm_init_info(&hw->info, &is);
dolog("JACK input configured for %dHz (%d samples)\n",
ji->c.freq, ji->c.buffersize);
return 0;
}
static void qjack_client_fini(QJackClient *c)
{
switch (c->state) {
case QJACK_STATE_RUNNING:
jack_deactivate(c->client);
/* fallthrough */
case QJACK_STATE_SHUTDOWN:
jack_client_close(c->client);
/* fallthrough */
case QJACK_STATE_DISCONNECTED:
break;
}
qjack_buffer_free(&c->fifo);
g_free(c->port);
c->state = QJACK_STATE_DISCONNECTED;
}
static void qjack_fini_out(HWVoiceOut *hw)
{
QJackOut *jo = (QJackOut *)hw;
qjack_client_fini(&jo->c);
}
static void qjack_fini_in(HWVoiceIn *hw)
{
QJackIn *ji = (QJackIn *)hw;
qjack_client_fini(&ji->c);
}
static void qjack_enable_out(HWVoiceOut *hw, bool enable)
{
QJackOut *jo = (QJackOut *)hw;
jo->c.enabled = enable;
}
static void qjack_enable_in(HWVoiceIn *hw, bool enable)
{
QJackIn *ji = (QJackIn *)hw;
ji->c.enabled = enable;
}
static int qjack_thread_creator(jack_native_thread_t *thread,
const pthread_attr_t *attr, void *(*function)(void *), void *arg)
{
int ret = pthread_create(thread, attr, function, arg);
if (ret != 0) {
return ret;
}
/* set the name of the thread */
pthread_setname_np(*thread, "jack-client");
return ret;
}
static void *qjack_init(Audiodev *dev)
{
assert(dev->driver == AUDIODEV_DRIVER_JACK);
return dev;
}
static void qjack_fini(void *opaque)
{
}
static struct audio_pcm_ops jack_pcm_ops = {
.init_out = qjack_init_out,
.fini_out = qjack_fini_out,
.write = qjack_write,
.run_buffer_out = audio_generic_run_buffer_out,
.enable_out = qjack_enable_out,
.init_in = qjack_init_in,
.fini_in = qjack_fini_in,
.read = qjack_read,
.enable_in = qjack_enable_in
};
static struct audio_driver jack_driver = {
.name = "jack",
.descr = "JACK Audio Connection Kit Client",
.init = qjack_init,
.fini = qjack_fini,
.pcm_ops = &jack_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX,
.max_voices_in = INT_MAX,
.voice_size_out = sizeof(QJackOut),
.voice_size_in = sizeof(QJackIn)
};
static void qjack_error(const char *msg)
{
dolog("E: %s\n", msg);
}
static void qjack_info(const char *msg)
{
dolog("I: %s\n", msg);
}
static void register_audio_jack(void)
{
audio_driver_register(&jack_driver);
jack_set_thread_creator(qjack_thread_creator);
jack_set_error_function(qjack_error);
jack_set_info_function(qjack_info);
}
type_init(register_audio_jack);

View File

@ -271,11 +271,12 @@ f_sample *mixeng_clip[2][2][2][3] = {
#define CONV_NATURAL_FLOAT(x) (x)
#define CLIP_NATURAL_FLOAT(x) (x)
#else
static const float float_scale = UINT_MAX / 2.f;
/* macros to map [-1.f, 1.f] <-> [INT32_MIN, INT32_MAX + 1] */
static const float float_scale = (int64_t)INT32_MAX + 1;
#define CONV_NATURAL_FLOAT(x) ((x) * float_scale)
#ifdef RECIPROCAL
static const float float_scale_reciprocal = 2.f / UINT_MAX;
static const float float_scale_reciprocal = 1.f / ((int64_t)INT32_MAX + 1);
#define CLIP_NATURAL_FLOAT(x) ((x) * float_scale_reciprocal)
#else
#define CLIP_NATURAL_FLOAT(x) ((x) / float_scale)
@ -338,10 +339,10 @@ f_sample *mixeng_clip_float[2] = {
clip_natural_float_from_stereo,
};
void audio_sample_to_uint64(void *samples, int pos,
void audio_sample_to_uint64(const void *samples, int pos,
uint64_t *left, uint64_t *right)
{
struct st_sample *sample = samples;
const struct st_sample *sample = samples;
sample += pos;
#ifdef FLOAT_MIXENG
error_report(

View File

@ -691,6 +691,7 @@ static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len)
len, dst);
break;
}
break;
}
pos += nread;

View File

@ -71,7 +71,7 @@ static void wav_destroy (void *opaque)
g_free (wav->path);
}
static void wav_capture (void *opaque, void *buf, int size)
static void wav_capture(void *opaque, const void *buf, int size)
{
WAVState *wav = opaque;

View File

@ -124,13 +124,12 @@ qauthz_list_class_init(ObjectClass *oc, void *data)
"QAuthZListPolicy",
&QAuthZListPolicy_lookup,
qauthz_list_prop_get_policy,
qauthz_list_prop_set_policy,
NULL);
qauthz_list_prop_set_policy);
object_class_property_add(oc, "rules", "QAuthZListRule",
qauthz_list_prop_get_rules,
qauthz_list_prop_set_rules,
NULL, NULL, NULL);
NULL, NULL);
authz->is_allowed = qauthz_list_is_allowed;
}

View File

@ -221,12 +221,10 @@ qauthz_list_file_class_init(ObjectClass *oc, void *data)
object_class_property_add_str(oc, "filename",
qauthz_list_file_prop_get_filename,
qauthz_list_file_prop_set_filename,
NULL);
qauthz_list_file_prop_set_filename);
object_class_property_add_bool(oc, "refresh",
qauthz_list_file_prop_get_refresh,
qauthz_list_file_prop_set_refresh,
NULL);
qauthz_list_file_prop_set_refresh);
authz->is_allowed = qauthz_list_file_is_allowed;
}

View File

@ -107,8 +107,7 @@ qauthz_pam_class_init(ObjectClass *oc, void *data)
object_class_property_add_str(oc, "service",
qauthz_pam_prop_get_service,
qauthz_pam_prop_set_service,
NULL);
qauthz_pam_prop_set_service);
}

View File

@ -74,8 +74,7 @@ qauthz_simple_class_init(ObjectClass *oc, void *data)
object_class_property_add_str(oc, "identity",
qauthz_simple_prop_get_identity,
qauthz_simple_prop_set_identity,
NULL);
qauthz_simple_prop_set_identity);
}

1
backends/Kconfig Normal file
View File

@ -0,0 +1 @@
source tpm/Kconfig

View File

@ -1,7 +1,7 @@
common-obj-y += rng.o rng-egd.o rng-builtin.o
common-obj-$(CONFIG_POSIX) += rng-random.o
common-obj-$(CONFIG_TPM) += tpm.o
common-obj-$(CONFIG_TPM) += tpm/
common-obj-y += hostmem.o hostmem-ram.o
common-obj-$(CONFIG_POSIX) += hostmem-file.o

View File

@ -282,12 +282,7 @@ static int cryptodev_builtin_sym_close_session(
CryptoDevBackendBuiltin *builtin =
CRYPTODEV_BACKEND_BUILTIN(backend);
if (session_id >= MAX_NUM_SESSIONS ||
builtin->sessions[session_id] == NULL) {
error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
session_id);
return -1;
}
assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]);
qcrypto_cipher_free(builtin->sessions[session_id]->cipher);
g_free(builtin->sessions[session_id]);
@ -356,8 +351,7 @@ static void cryptodev_builtin_cleanup(
for (i = 0; i < MAX_NUM_SESSIONS; i++) {
if (builtin->sessions[i] != NULL) {
cryptodev_builtin_sym_close_session(
backend, i, 0, errp);
cryptodev_builtin_sym_close_session(backend, i, 0, &error_abort);
}
}

View File

@ -209,8 +209,7 @@ static void cryptodev_vhost_user_init(
backend->conf.peers.ccs[i] = cc;
if (i == 0) {
if (!qemu_chr_fe_init(&s->chr, chr, &local_err)) {
error_propagate(errp, local_err);
if (!qemu_chr_fe_init(&s->chr, chr, errp)) {
return;
}
}
@ -340,8 +339,7 @@ static void cryptodev_vhost_user_instance_int(Object *obj)
{
object_property_add_str(obj, "chardev",
cryptodev_vhost_user_get_chardev,
cryptodev_vhost_user_set_chardev,
NULL);
cryptodev_vhost_user_set_chardev);
}
static void cryptodev_vhost_user_finalize(Object *obj)

View File

@ -154,21 +154,17 @@ cryptodev_backend_set_queues(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
Error *local_err = NULL;
uint32_t value;
visit_type_uint32(v, name, &value, &local_err);
if (local_err) {
goto out;
if (!visit_type_uint32(v, name, &value, errp)) {
return;
}
if (!value) {
error_setg(&local_err, "Property '%s.%s' doesn't take value '%"
PRIu32 "'", object_get_typename(obj), name, value);
goto out;
error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu32 "'",
object_get_typename(obj), name, value);
return;
}
backend->conf.peers.queues = value;
out:
error_propagate(errp, local_err);
}
static void
@ -213,9 +209,9 @@ static void cryptodev_backend_instance_init(Object *obj)
object_property_add(obj, "queues", "uint32",
cryptodev_backend_get_queues,
cryptodev_backend_set_queues,
NULL, NULL, NULL);
NULL, NULL);
/* Initialize devices' queues property to 1 */
object_property_set_int(obj, 1, "queues", NULL);
object_property_set_int(obj, "queues", 1, NULL);
}
static void cryptodev_backend_finalize(Object *obj)

View File

@ -481,11 +481,9 @@ dbus_vmstate_class_init(ObjectClass *oc, void *data)
vc->get_id = dbus_vmstate_get_id;
object_class_property_add_str(oc, "addr",
get_dbus_addr, set_dbus_addr,
&error_abort);
get_dbus_addr, set_dbus_addr);
object_class_property_add_str(oc, "id-list",
get_id_list, set_id_list,
&error_abort);
get_id_list, set_id_list);
}
static const TypeInfo dbus_vmstate_info = {

View File

@ -110,23 +110,18 @@ static void file_memory_backend_set_align(Object *o, Visitor *v,
{
HostMemoryBackend *backend = MEMORY_BACKEND(o);
HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
Error *local_err = NULL;
uint64_t val;
if (host_memory_backend_mr_inited(backend)) {
error_setg(&local_err, "cannot change property '%s' of %s",
name, object_get_typename(o));
goto out;
error_setg(errp, "cannot change property '%s' of %s", name,
object_get_typename(o));
return;
}
visit_type_size(v, name, &val, &local_err);
if (local_err) {
goto out;
if (!visit_type_size(v, name, &val, errp)) {
return;
}
fb->align = val;
out:
error_propagate(errp, local_err);
}
static bool file_memory_backend_get_pmem(Object *o, Error **errp)
@ -140,7 +135,6 @@ static void file_memory_backend_set_pmem(Object *o, bool value, Error **errp)
HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
if (host_memory_backend_mr_inited(backend)) {
error_setg(errp, "cannot change property 'pmem' of %s.",
object_get_typename(o));
return;
@ -148,13 +142,9 @@ static void file_memory_backend_set_pmem(Object *o, bool value, Error **errp)
#ifndef CONFIG_LIBPMEM
if (value) {
Error *local_err = NULL;
error_setg(&local_err,
"Lack of libpmem support while setting the 'pmem=on'"
error_setg(errp, "Lack of libpmem support while setting the 'pmem=on'"
" of %s. We can't ensure data persistence.",
object_get_typename(o));
error_propagate(errp, local_err);
return;
}
#endif
@ -184,18 +174,15 @@ file_backend_class_init(ObjectClass *oc, void *data)
oc->unparent = file_backend_unparent;
object_class_property_add_bool(oc, "discard-data",
file_memory_backend_get_discard_data, file_memory_backend_set_discard_data,
&error_abort);
file_memory_backend_get_discard_data, file_memory_backend_set_discard_data);
object_class_property_add_str(oc, "mem-path",
get_mem_path, set_mem_path,
&error_abort);
get_mem_path, set_mem_path);
object_class_property_add(oc, "align", "int",
file_memory_backend_get_align,
file_memory_backend_set_align,
NULL, NULL, &error_abort);
NULL, NULL);
object_class_property_add_bool(oc, "pmem",
file_memory_backend_get_pmem, file_memory_backend_set_pmem,
&error_abort);
file_memory_backend_get_pmem, file_memory_backend_set_pmem);
}
static void file_backend_instance_finalize(Object *o)

View File

@ -77,26 +77,22 @@ memfd_backend_set_hugetlbsize(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj);
Error *local_err = NULL;
uint64_t value;
if (host_memory_backend_mr_inited(MEMORY_BACKEND(obj))) {
error_setg(&local_err, "cannot change property value");
goto out;
error_setg(errp, "cannot change property value");
return;
}
visit_type_size(v, name, &value, &local_err);
if (local_err) {
goto out;
if (!visit_type_size(v, name, &value, errp)) {
return;
}
if (!value) {
error_setg(&local_err, "Property '%s.%s' doesn't take value '%"
PRIu64 "'", object_get_typename(obj), name, value);
goto out;
error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu64 "'",
object_get_typename(obj), name, value);
return;
}
m->hugetlbsize = value;
out:
error_propagate(errp, local_err);
}
static void
@ -141,26 +137,21 @@ memfd_backend_class_init(ObjectClass *oc, void *data)
if (qemu_memfd_check(MFD_HUGETLB)) {
object_class_property_add_bool(oc, "hugetlb",
memfd_backend_get_hugetlb,
memfd_backend_set_hugetlb,
&error_abort);
memfd_backend_set_hugetlb);
object_class_property_set_description(oc, "hugetlb",
"Use huge pages",
&error_abort);
"Use huge pages");
object_class_property_add(oc, "hugetlbsize", "int",
memfd_backend_get_hugetlbsize,
memfd_backend_set_hugetlbsize,
NULL, NULL, &error_abort);
NULL, NULL);
object_class_property_set_description(oc, "hugetlbsize",
"Huge pages size (ex: 2M, 1G)",
&error_abort);
"Huge pages size (ex: 2M, 1G)");
}
object_class_property_add_bool(oc, "seal",
memfd_backend_get_seal,
memfd_backend_set_seal,
&error_abort);
memfd_backend_set_seal);
object_class_property_set_description(oc, "seal",
"Seal growing & shrinking",
&error_abort);
"Seal growing & shrinking");
}
static const TypeInfo memfd_backend_info = {

View File

@ -33,7 +33,7 @@ char *
host_memory_backend_get_name(HostMemoryBackend *backend)
{
if (!backend->use_canonical_path) {
return object_get_canonical_path_component(OBJECT(backend));
return g_strdup(object_get_canonical_path_component(OBJECT(backend)));
}
return object_get_canonical_path(OBJECT(backend));
@ -54,28 +54,24 @@ host_memory_backend_set_size(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
Error *local_err = NULL;
uint64_t value;
if (host_memory_backend_mr_inited(backend)) {
error_setg(&local_err, "cannot change property %s of %s ",
name, object_get_typename(obj));
goto out;
error_setg(errp, "cannot change property %s of %s ", name,
object_get_typename(obj));
return;
}
visit_type_size(v, name, &value, &local_err);
if (local_err) {
goto out;
if (!visit_type_size(v, name, &value, errp)) {
return;
}
if (!value) {
error_setg(&local_err,
error_setg(errp,
"property '%s' of %s doesn't take value '%" PRIu64 "'",
name, object_get_typename(obj), value);
goto out;
return;
}
backend->size = value;
out:
error_propagate(errp, local_err);
}
static void
@ -254,22 +250,17 @@ static void host_memory_backend_set_prealloc_threads(Object *obj, Visitor *v,
const char *name, void *opaque, Error **errp)
{
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
Error *local_err = NULL;
uint32_t value;
visit_type_uint32(v, name, &value, &local_err);
if (local_err) {
goto out;
if (!visit_type_uint32(v, name, &value, errp)) {
return;
}
if (value <= 0) {
error_setg(&local_err,
"property '%s' of %s doesn't take value '%d'",
name, object_get_typename(obj), value);
goto out;
error_setg(errp, "property '%s' of %s doesn't take value '%d'", name,
object_get_typename(obj), value);
return;
}
backend->prealloc_threads = value;
out:
error_propagate(errp, local_err);
}
static void host_memory_backend_init(Object *obj)
@ -383,8 +374,10 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
assert(sizeof(backend->host_nodes) >=
BITS_TO_LONGS(MAX_NODES + 1) * sizeof(unsigned long));
assert(maxnode <= MAX_NODES);
if (mbind(ptr, sz, backend->policy,
maxnode ? backend->host_nodes : NULL, maxnode + 1, flags)) {
if (maxnode &&
mbind(ptr, sz, backend->policy, backend->host_nodes, maxnode + 1,
flags)) {
if (backend->policy != MPOL_DEFAULT || errno != ENOSYS) {
error_setg_errno(errp, errno,
"cannot bind memory to host NUMA nodes");
@ -463,51 +456,50 @@ host_memory_backend_class_init(ObjectClass *oc, void *data)
object_class_property_add_bool(oc, "merge",
host_memory_backend_get_merge,
host_memory_backend_set_merge, &error_abort);
host_memory_backend_set_merge);
object_class_property_set_description(oc, "merge",
"Mark memory as mergeable", &error_abort);
"Mark memory as mergeable");
object_class_property_add_bool(oc, "dump",
host_memory_backend_get_dump,
host_memory_backend_set_dump, &error_abort);
host_memory_backend_set_dump);
object_class_property_set_description(oc, "dump",
"Set to 'off' to exclude from core dump", &error_abort);
"Set to 'off' to exclude from core dump");
object_class_property_add_bool(oc, "prealloc",
host_memory_backend_get_prealloc,
host_memory_backend_set_prealloc, &error_abort);
host_memory_backend_set_prealloc);
object_class_property_set_description(oc, "prealloc",
"Preallocate memory", &error_abort);
"Preallocate memory");
object_class_property_add(oc, "prealloc-threads", "int",
host_memory_backend_get_prealloc_threads,
host_memory_backend_set_prealloc_threads,
NULL, NULL, &error_abort);
NULL, NULL);
object_class_property_set_description(oc, "prealloc-threads",
"Number of CPU threads to use for prealloc", &error_abort);
"Number of CPU threads to use for prealloc");
object_class_property_add(oc, "size", "int",
host_memory_backend_get_size,
host_memory_backend_set_size,
NULL, NULL, &error_abort);
NULL, NULL);
object_class_property_set_description(oc, "size",
"Size of the memory region (ex: 500M)", &error_abort);
"Size of the memory region (ex: 500M)");
object_class_property_add(oc, "host-nodes", "int",
host_memory_backend_get_host_nodes,
host_memory_backend_set_host_nodes,
NULL, NULL, &error_abort);
NULL, NULL);
object_class_property_set_description(oc, "host-nodes",
"Binds memory to the list of NUMA host nodes", &error_abort);
"Binds memory to the list of NUMA host nodes");
object_class_property_add_enum(oc, "policy", "HostMemPolicy",
&HostMemPolicy_lookup,
host_memory_backend_get_policy,
host_memory_backend_set_policy, &error_abort);
host_memory_backend_set_policy);
object_class_property_set_description(oc, "policy",
"Set the NUMA policy", &error_abort);
"Set the NUMA policy");
object_class_property_add_bool(oc, "share",
host_memory_backend_get_share, host_memory_backend_set_share,
&error_abort);
host_memory_backend_get_share, host_memory_backend_set_share);
object_class_property_set_description(oc, "share",
"Mark the memory as private to QEMU or shared", &error_abort);
"Mark the memory as private to QEMU or shared");
object_class_property_add_bool(oc, "x-use-canonical-path-for-ramblock-id",
host_memory_backend_get_use_canonical_path,
host_memory_backend_set_use_canonical_path, &error_abort);
host_memory_backend_set_use_canonical_path);
}
static const TypeInfo host_memory_backend_info = {

View File

@ -138,8 +138,7 @@ static char *rng_egd_get_chardev(Object *obj, Error **errp)
static void rng_egd_init(Object *obj)
{
object_property_add_str(obj, "chardev",
rng_egd_get_chardev, rng_egd_set_chardev,
NULL);
rng_egd_get_chardev, rng_egd_set_chardev);
}
static void rng_egd_finalize(Object *obj)

View File

@ -110,8 +110,7 @@ static void rng_random_init(Object *obj)
object_property_add_str(obj, "filename",
rng_random_get_filename,
rng_random_set_filename,
NULL);
rng_random_set_filename);
s->filename = g_strdup("/dev/urandom");
s->fd = -1;

View File

@ -48,7 +48,7 @@ static bool rng_backend_prop_get_opened(Object *obj, Error **errp)
static void rng_backend_complete(UserCreatable *uc, Error **errp)
{
object_property_set_bool(OBJECT(uc), true, "opened", errp);
object_property_set_bool(OBJECT(uc), "opened", true, errp);
}
static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
@ -108,8 +108,7 @@ static void rng_backend_init(Object *obj)
object_property_add_bool(obj, "opened",
rng_backend_prop_get_opened,
rng_backend_prop_set_opened,
NULL);
rng_backend_prop_set_opened);
}
static void rng_backend_finalize(Object *obj)

14
backends/tpm/Kconfig Normal file
View File

@ -0,0 +1,14 @@
config TPM_BACKEND
bool
depends on TPM
config TPM_PASSTHROUGH
bool
default y
# FIXME: should check for x86 host as well
depends on TPM_BACKEND && LINUX
config TPM_EMULATOR
bool
default y
depends on TPM_BACKEND

View File

@ -0,0 +1,4 @@
common-obj-y += tpm_backend.o
common-obj-y += tpm_util.o
common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o

View File

@ -32,8 +32,8 @@
#include "qemu/sockets.h"
#include "io/channel-socket.h"
#include "sysemu/tpm_backend.h"
#include "sysemu/tpm_util.h"
#include "tpm_int.h"
#include "tpm_util.h"
#include "tpm_ioctl.h"
#include "migration/blocker.h"
#include "migration/vmstate.h"
@ -549,27 +549,30 @@ err_exit:
static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts)
{
const char *value;
Error *err = NULL;
Chardev *dev;
value = qemu_opt_get(opts, "chardev");
if (value) {
Error *err = NULL;
Chardev *dev = qemu_chr_find(value);
if (!dev) {
error_report("tpm-emulator: tpm chardev '%s' not found.", value);
goto err;
}
if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) {
error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':",
value);
error_report_err(err);
goto err;
}
tpm_emu->options->chardev = g_strdup(value);
if (!value) {
error_report("tpm-emulator: parameter 'chardev' is missing");
goto err;
}
dev = qemu_chr_find(value);
if (!dev) {
error_report("tpm-emulator: tpm chardev '%s' not found", value);
goto err;
}
if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) {
error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':",
value);
error_report_err(err);
goto err;
}
tpm_emu->options->chardev = g_strdup(value);
if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
goto err;
}
@ -925,6 +928,11 @@ static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
{
ptm_res res;
if (!tpm_emu->options->chardev) {
/* was never properly initialized */
return;
}
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SHUTDOWN, &res, 0, sizeof(res)) < 0) {
error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s",
strerror(errno));

View File

@ -9,8 +9,11 @@
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef TPM_TPM_INT_H
#define TPM_TPM_INT_H
#ifndef BACKENDS_TPM_INT_H
#define BACKENDS_TPM_INT_H
#include "qemu/option.h"
#include "sysemu/tpm.h"
#define TPM_STANDARD_CMDLINE_OPTS \
{ \
@ -72,4 +75,14 @@ struct tpm_resp_hdr {
#define TPM_RC_FAILURE 0x101
#define TPM_RC_LOCALITY 0x907
#endif /* TPM_TPM_INT_H */
int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version,
size_t *buffersize);
typedef struct TPMSizedBuffer {
uint32_t size;
uint8_t *buffer;
} TPMSizedBuffer;
void tpm_sized_buffer_reset(TPMSizedBuffer *tsb);
#endif /* BACKENDS_TPM_INT_H */

View File

@ -28,10 +28,10 @@
#include "qemu/module.h"
#include "qemu/sockets.h"
#include "sysemu/tpm_backend.h"
#include "sysemu/tpm_util.h"
#include "tpm_int.h"
#include "qapi/clone-visitor.h"
#include "qapi/qapi-visit-tpm.h"
#include "tpm_util.h"
#include "trace.h"
#define TYPE_TPM_PASSTHROUGH "tpm-passthrough"

View File

@ -23,11 +23,11 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "tpm_util.h"
#include "tpm_int.h"
#include "exec/memory.h"
#include "hw/qdev-properties.h"
#include "sysemu/tpm_backend.h"
#include "sysemu/tpm_util.h"
#include "trace.h"
/* tpm backend property */
@ -48,7 +48,6 @@ static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
DeviceState *dev = DEVICE(obj);
Error *local_err = NULL;
Property *prop = opaque;
TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop);
char *str;
@ -58,9 +57,7 @@ static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
return;
}
visit_type_str(v, name, &str, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!visit_type_str(v, name, &str, errp)) {
return;
}
@ -357,6 +354,9 @@ void tpm_util_show_buffer(const unsigned char *buffer,
size_t len, i;
char *line_buffer, *p;
if (!trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) {
return;
}
len = MIN(tpm_cmd_get_size(buffer), buffer_size);
/*

33
backends/tpm/trace-events Normal file
View File

@ -0,0 +1,33 @@
# See docs/devel/tracing.txt for syntax documentation.
# tpm_passthrough.c
tpm_passthrough_handle_request(void *cmd) "processing command %p"
tpm_passthrough_reset(void) "reset"
# tpm_util.c
tpm_util_get_buffer_size_hdr_len(uint32_t len, size_t expected) "tpm_resp->hdr.len = %u, expected = %zu"
tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, expected = %zu"
tpm_util_get_buffer_size_hdr_len2(uint32_t len, size_t expected) "tpm2_resp->hdr.len = %u, expected = %zu"
tpm_util_get_buffer_size_len2(uint32_t len, size_t expected) "tpm2_resp->len = %u, expected = %zu"
tpm_util_get_buffer_size(size_t len) "buffersize of device: %zu"
tpm_util_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s"
# tpm_emulator.c
tpm_emulator_set_locality(uint8_t locty) "setting locality to %d"
tpm_emulator_handle_request(void) "processing TPM command"
tpm_emulator_probe_caps(uint64_t caps) "capabilities: 0x%"PRIx64
tpm_emulator_set_buffer_size(uint32_t buffersize, uint32_t minsize, uint32_t maxsize) "buffer size: %u, min: %u, max: %u"
tpm_emulator_startup_tpm_resume(bool is_resume, size_t buffersize) "is_resume: %d, buffer size: %zu"
tpm_emulator_get_tpm_established_flag(uint8_t flag) "got established flag: %d"
tpm_emulator_cancel_cmd_not_supt(void) "Backend does not support CANCEL_TPM_CMD"
tpm_emulator_handle_device_opts_tpm12(void) "TPM Version 1.2"
tpm_emulator_handle_device_opts_tpm2(void) "TPM Version 2"
tpm_emulator_handle_device_opts_unspec(void) "TPM Version Unspecified"
tpm_emulator_handle_device_opts_startup_error(void) "Startup error"
tpm_emulator_get_state_blob(uint8_t type, uint32_t size, uint32_t flags) "got state blob type %d, %u bytes, flags 0x%08x"
tpm_emulator_set_state_blob(uint8_t type, uint32_t size, uint32_t flags) "set state blob type %d, %u bytes, flags 0x%08x"
tpm_emulator_set_state_blobs(void) "setting state blobs"
tpm_emulator_set_state_blobs_error(const char *msg) "error while setting state blobs: %s"
tpm_emulator_set_state_blobs_done(void) "Done setting state blobs"
tpm_emulator_pre_save(void) ""
tpm_emulator_inst_init(void) ""

View File

@ -177,7 +177,7 @@ static char *get_chardev(Object *obj, Error **errp)
static void vhost_user_backend_init(Object *obj)
{
object_property_add_str(obj, "chardev", get_chardev, set_chardev, NULL);
object_property_add_str(obj, "chardev", get_chardev, set_chardev);
}
static void vhost_user_backend_finalize(Object *obj)

750
block.c

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@ block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
block-obj-$(CONFIG_POSIX) += file-posix.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
block-obj-$(CONFIG_LINUX_IO_URING) += io_uring.o
block-obj-y += null.o mirror.o commit.o io.o create.o
block-obj-y += null.o mirror.o commit.o io.o create.o amend.o
block-obj-y += throttle-groups.o
block-obj-$(CONFIG_LINUX) += nvme.o
@ -31,7 +31,6 @@ block-obj-$(CONFIG_LIBNFS) += nfs.o
block-obj-$(CONFIG_CURL) += curl.o
block-obj-$(CONFIG_RBD) += rbd.o
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
block-obj-$(CONFIG_VXHS) += vxhs.o
block-obj-$(CONFIG_LIBSSH) += ssh.o
block-obj-y += accounting.o dirty-bitmap.o
block-obj-y += write-threshold.o
@ -46,6 +45,7 @@ block-obj-y += aio_task.o
block-obj-y += backup-top.o
block-obj-y += filter-compress.o
common-obj-y += monitor/
block-obj-y += monitor/
block-obj-y += stream.o
@ -60,7 +60,6 @@ rbd.o-cflags := $(RBD_CFLAGS)
rbd.o-libs := $(RBD_LIBS)
gluster.o-cflags := $(GLUSTERFS_CFLAGS)
gluster.o-libs := $(GLUSTERFS_LIBS)
vxhs.o-libs := $(VXHS_LIBS)
ssh.o-cflags := $(LIBSSH_CFLAGS)
ssh.o-libs := $(LIBSSH_LIBS)
block-obj-dmg-bz2-$(CONFIG_BZIP2) += dmg-bz2.o

117
block/amend.c Normal file
View File

@ -0,0 +1,117 @@
/*
* Block layer code related to image options amend
*
* Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com>
* Copyright (c) 2020 Red Hat. Inc
*
* Heavily based on create.c
*
* 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 "block/block_int.h"
#include "qemu/job.h"
#include "qemu/main-loop.h"
#include "qapi/qapi-commands-block-core.h"
#include "qapi/qapi-visit-block-core.h"
#include "qapi/clone-visitor.h"
#include "qapi/error.h"
typedef struct BlockdevAmendJob {
Job common;
BlockdevAmendOptions *opts;
BlockDriverState *bs;
bool force;
} BlockdevAmendJob;
static int coroutine_fn blockdev_amend_run(Job *job, Error **errp)
{
BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common);
int ret;
job_progress_set_remaining(&s->common, 1);
ret = s->bs->drv->bdrv_co_amend(s->bs, s->opts, s->force, errp);
job_progress_update(&s->common, 1);
qapi_free_BlockdevAmendOptions(s->opts);
return ret;
}
static const JobDriver blockdev_amend_job_driver = {
.instance_size = sizeof(BlockdevAmendJob),
.job_type = JOB_TYPE_AMEND,
.run = blockdev_amend_run,
};
void qmp_x_blockdev_amend(const char *job_id,
const char *node_name,
BlockdevAmendOptions *options,
bool has_force,
bool force,
Error **errp)
{
BlockdevAmendJob *s;
const char *fmt = BlockdevDriver_str(options->driver);
BlockDriver *drv = bdrv_find_format(fmt);
BlockDriverState *bs;
bs = bdrv_lookup_bs(NULL, node_name, errp);
if (!bs) {
return;
}
if (!drv) {
error_setg(errp, "Block driver '%s' not found or not supported", fmt);
return;
}
/*
* If the driver is in the schema, we know that it exists. But it may not
* be whitelisted.
*/
if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) {
error_setg(errp, "Driver is not whitelisted");
return;
}
if (bs->drv != drv) {
error_setg(errp,
"x-blockdev-amend doesn't support changing the block driver");
return;
}
/* Error out if the driver doesn't support .bdrv_co_amend */
if (!drv->bdrv_co_amend) {
error_setg(errp, "Driver does not support x-blockdev-amend");
return;
}
/* Create the block job */
s = job_create(job_id, &blockdev_amend_job_driver, NULL,
bdrv_get_aio_context(bs), JOB_DEFAULT | JOB_MANUAL_DISMISS,
NULL, NULL, errp);
if (!s) {
return;
}
s->bs = bs,
s->opts = QAPI_CLONE(BlockdevAmendOptions, options),
s->force = has_force ? force : false;
job_start(&s->common);
}

View File

@ -122,7 +122,7 @@ static void backup_top_refresh_filename(BlockDriverState *bs)
}
static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c,
const BdrvChildRole *role,
BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
@ -142,24 +142,26 @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c,
return;
}
if (role == &child_file) {
if (!(role & BDRV_CHILD_FILTERED)) {
/*
* Target child
*
* Share write to target (child_file), to not interfere
* with guest writes to its disk which may be in target backing chain.
* Can't resize during a backup block job because we check the size
* only upfront.
*/
*nshared = BLK_PERM_ALL;
*nshared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
*nperm = BLK_PERM_WRITE;
} else {
/* Source child */
bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
nperm, nshared);
bdrv_default_perms(bs, c, role, reopen_queue,
perm, shared, nperm, nshared);
if (perm & BLK_PERM_WRITE) {
*nperm = *nperm | BLK_PERM_CONSISTENT_READ;
}
*nshared &= ~BLK_PERM_WRITE;
*nshared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
}
}
@ -192,11 +194,13 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
{
Error *local_err = NULL;
BDRVBackupTopState *state;
BlockDriverState *top = bdrv_new_open_driver(&bdrv_backup_top_filter,
filter_node_name,
BDRV_O_RDWR, errp);
BlockDriverState *top;
bool appended = false;
assert(source->total_sectors == target->total_sectors);
top = bdrv_new_open_driver(&bdrv_backup_top_filter, filter_node_name,
BDRV_O_RDWR, errp);
if (!top) {
return NULL;
}
@ -210,7 +214,8 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
source->supported_zero_flags);
bdrv_ref(target);
state->target = bdrv_attach_child(top, target, "target", &child_file, errp);
state->target = bdrv_attach_child(top, target, "target", &child_of_bds,
BDRV_CHILD_DATA, errp);
if (!state->target) {
bdrv_unref(target);
bdrv_unref(top);

View File

@ -340,7 +340,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockCompletionFunc *cb, void *opaque,
JobTxn *txn, Error **errp)
{
int64_t len;
int64_t len, target_len;
BackupBlockJob *job = NULL;
int64_t cluster_size;
BdrvRequestFlags write_flags;
@ -400,8 +400,20 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
len = bdrv_getlength(bs);
if (len < 0) {
error_setg_errno(errp, -len, "unable to get length for '%s'",
bdrv_get_device_name(bs));
error_setg_errno(errp, -len, "Unable to get length for '%s'",
bdrv_get_device_or_node_name(bs));
goto error;
}
target_len = bdrv_getlength(target);
if (target_len < 0) {
error_setg_errno(errp, -target_len, "Unable to get length for '%s'",
bdrv_get_device_or_node_name(bs));
goto error;
}
if (target_len != len) {
error_setg(errp, "Source and target image have different sizes");
goto error;
}

View File

@ -359,7 +359,6 @@ static int blkdebug_parse_perm_list(uint64_t *dest, QDict *options,
QObject *crumpled_subqdict = NULL;
Visitor *v = NULL;
BlockPermissionList *perm_list = NULL, *element;
Error *local_err = NULL;
*dest = 0;
@ -375,9 +374,7 @@ static int blkdebug_parse_perm_list(uint64_t *dest, QDict *options,
}
v = qobject_input_visitor_new(crumpled_subqdict);
visit_type_BlockPermissionList(v, NULL, &perm_list, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!visit_type_BlockPermissionList(v, NULL, &perm_list, errp)) {
ret = -EINVAL;
goto out;
}
@ -472,9 +469,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
uint64_t align;
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
ret = -EINVAL;
goto out;
}
@ -497,7 +492,9 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
/* Open the image file */
bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
bs, &child_file, false, &local_err);
bs, &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
false, &local_err);
if (local_err) {
ret = -EINVAL;
error_propagate(errp, local_err);
@ -993,15 +990,15 @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
}
static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c,
const BdrvChildRole *role,
BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
{
BDRVBlkdebugState *s = bs->opaque;
bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
nperm, nshared);
bdrv_default_perms(bs, c, role, reopen_queue,
perm, shared, nperm, nshared);
*nperm |= s->take_child_perms;
*nshared &= ~s->unshare_child_perms;

View File

@ -149,15 +149,14 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
bool log_append;
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
ret = -EINVAL;
error_propagate(errp, local_err);
goto fail;
}
/* Open the file */
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, false,
&local_err);
if (local_err) {
ret = -EINVAL;
@ -166,8 +165,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
}
/* Open the log file */
s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, false,
&local_err);
s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_of_bds,
BDRV_CHILD_METADATA, false, &local_err);
if (local_err) {
ret = -EINVAL;
error_propagate(errp, local_err);
@ -282,7 +281,7 @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs)
}
static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c,
const BdrvChildRole *role,
BdrvChildRole role,
BlockReopenQueue *ro_q,
uint64_t perm, uint64_t shrd,
uint64_t *nperm, uint64_t *nshrd)
@ -293,11 +292,8 @@ static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c,
return;
}
if (!strcmp(c->name, "log")) {
bdrv_format_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd);
} else {
bdrv_filter_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd);
}
bdrv_default_perms(bs, c, role, ro_q, perm, shrd,
nperm, nshrd);
}
static void blk_log_writes_refresh_limits(BlockDriverState *bs, Error **errp)

View File

@ -27,8 +27,9 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
int ret;
/* Open the image file */
bs->file = bdrv_open_child(NULL, options, "image",
bs, &child_file, false, &local_err);
bs->file = bdrv_open_child(NULL, options, "image", bs, &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
false, &local_err);
if (local_err) {
ret = -EINVAL;
error_propagate(errp, local_err);
@ -135,9 +136,10 @@ static int blkreplay_snapshot_goto(BlockDriverState *bs,
static BlockDriver bdrv_blkreplay = {
.format_name = "blkreplay",
.instance_size = 0,
.is_filter = true,
.bdrv_open = blkreplay_open,
.bdrv_child_perm = bdrv_filter_default_perms,
.bdrv_child_perm = bdrv_default_perms,
.bdrv_getlength = blkreplay_getlength,
.bdrv_co_preadv = blkreplay_co_preadv,

View File

@ -116,16 +116,16 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
int ret;
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
ret = -EINVAL;
goto fail;
}
/* Open the raw file */
bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw",
bs, &child_file, false, &local_err);
bs, &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
false, &local_err);
if (local_err) {
ret = -EINVAL;
error_propagate(errp, local_err);
@ -134,8 +134,8 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
/* Open the test file */
s->test_file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options,
"test", bs, &child_format, false,
&local_err);
"test", bs, &child_of_bds, BDRV_CHILD_DATA,
false, &local_err);
if (local_err) {
ret = -EINVAL;
error_propagate(errp, local_err);
@ -317,7 +317,7 @@ static BlockDriver bdrv_blkverify = {
.bdrv_parse_filename = blkverify_parse_filename,
.bdrv_file_open = blkverify_open,
.bdrv_close = blkverify_close,
.bdrv_child_perm = bdrv_filter_default_perms,
.bdrv_child_perm = bdrv_default_perms,
.bdrv_getlength = blkverify_getlength,
.bdrv_refresh_filename = blkverify_refresh_filename,
.bdrv_dirname = blkverify_dirname,

View File

@ -120,7 +120,8 @@ static QTAILQ_HEAD(, BlockBackend) block_backends =
static QTAILQ_HEAD(, BlockBackend) monitor_block_backends =
QTAILQ_HEAD_INITIALIZER(monitor_block_backends);
static void blk_root_inherit_options(int *child_flags, QDict *child_options,
static void blk_root_inherit_options(BdrvChildRole role, bool parent_is_format,
int *child_flags, QDict *child_options,
int parent_flags, QDict *parent_options)
{
/* We're not supposed to call this function for root nodes */
@ -297,7 +298,7 @@ static void blk_root_detach(BdrvChild *child)
}
}
static const BdrvChildRole child_root = {
static const BdrvChildClass child_root = {
.inherit_options = blk_root_inherit_options,
.change_media = blk_root_change_media,
@ -355,6 +356,29 @@ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm)
return blk;
}
/*
* Create a new BlockBackend connected to an existing BlockDriverState.
*
* @perm is a bitmasks of BLK_PERM_* constants which describes the
* permissions to request for @bs that is attached to this
* BlockBackend. @shared_perm is a bitmask which describes which
* permissions may be granted to other users of the attached node.
* Both sets of permissions can be changed later using blk_set_perm().
*
* Return the new BlockBackend on success, null on failure.
*/
BlockBackend *blk_new_with_bs(BlockDriverState *bs, uint64_t perm,
uint64_t shared_perm, Error **errp)
{
BlockBackend *blk = blk_new(bdrv_get_aio_context(bs), perm, shared_perm);
if (blk_insert_bs(blk, bs, errp) < 0) {
blk_unref(blk);
return NULL;
}
return blk;
}
/*
* Creates a new BlockBackend, opens a new BlockDriverState, and connects both.
* The new BlockBackend is in the main AioContext.
@ -400,8 +424,9 @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
return NULL;
}
blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
perm, BLK_PERM_ALL, blk, errp);
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
blk->ctx, perm, BLK_PERM_ALL, blk, errp);
if (!blk->root) {
blk_unref(blk);
return NULL;
@ -693,7 +718,7 @@ static BlockBackend *bdrv_first_blk(BlockDriverState *bs)
{
BdrvChild *child;
QLIST_FOREACH(child, &bs->parents, next_parent) {
if (child->role == &child_root) {
if (child->klass == &child_root) {
return child->opaque;
}
}
@ -717,7 +742,7 @@ bool bdrv_is_root_node(BlockDriverState *bs)
BdrvChild *c;
QLIST_FOREACH(c, &bs->parents, next_parent) {
if (c->role != &child_root) {
if (c->klass != &child_root) {
return false;
}
}
@ -783,6 +808,7 @@ void blk_remove_bs(BlockBackend *blk)
{
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
BlockDriverState *bs;
BdrvChild *root;
notifier_list_notify(&blk->remove_bs_notifiers, blk);
if (tgm->throttle_state) {
@ -800,8 +826,9 @@ void blk_remove_bs(BlockBackend *blk)
* to avoid that and a potential QEMU crash.
*/
blk_drain(blk);
bdrv_root_unref_child(blk->root);
root = blk->root;
blk->root = NULL;
bdrv_root_unref_child(root);
}
/*
@ -811,8 +838,10 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
{
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
bdrv_ref(bs);
blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
blk->perm, blk->shared_perm, blk, errp);
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
blk->ctx, blk->perm, blk->shared_perm,
blk, errp);
if (blk->root == NULL) {
return -EPERM;
}
@ -1365,8 +1394,16 @@ typedef struct BlkAioEmAIOCB {
bool has_returned;
} BlkAioEmAIOCB;
static AioContext *blk_aio_em_aiocb_get_aio_context(BlockAIOCB *acb_)
{
BlkAioEmAIOCB *acb = container_of(acb_, BlkAioEmAIOCB, common);
return blk_get_aio_context(acb->rwco.blk);
}
static const AIOCBInfo blk_aio_em_aiocb_info = {
.aiocb_size = sizeof(BlkAioEmAIOCB),
.get_aio_context = blk_aio_em_aiocb_get_aio_context,
};
static void blk_aio_complete(BlkAioEmAIOCB *acb)
@ -2137,14 +2174,14 @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
}
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp)
PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
{
if (!blk_is_available(blk)) {
error_setg(errp, "No medium inserted");
return -ENOMEDIUM;
}
return bdrv_truncate(blk->root, offset, exact, prealloc, errp);
return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp);
}
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
@ -2379,3 +2416,13 @@ const BdrvChild *blk_root(BlockBackend *blk)
{
return blk->root;
}
int blk_make_empty(BlockBackend *blk, Error **errp)
{
if (!blk_is_available(blk)) {
error_setg(errp, "No medium inserted");
return -ENOMEDIUM;
}
return bdrv_make_empty(blk->root, errp);
}

View File

@ -19,17 +19,37 @@
#include "block/block-copy.h"
#include "sysemu/block-backend.h"
#include "qemu/units.h"
#include "qemu/coroutine.h"
#include "block/aio_task.h"
#define BLOCK_COPY_MAX_COPY_RANGE (16 * MiB)
#define BLOCK_COPY_MAX_BUFFER (1 * MiB)
#define BLOCK_COPY_MAX_MEM (128 * MiB)
#define BLOCK_COPY_MAX_WORKERS 64
typedef struct BlockCopyInFlightReq {
static coroutine_fn int block_copy_task_entry(AioTask *task);
typedef struct BlockCopyCallState {
bool failed;
bool error_is_read;
} BlockCopyCallState;
typedef struct BlockCopyTask {
AioTask task;
BlockCopyState *s;
BlockCopyCallState *call_state;
int64_t offset;
int64_t bytes;
QLIST_ENTRY(BlockCopyInFlightReq) list;
CoQueue wait_queue; /* coroutines blocked on this request */
} BlockCopyInFlightReq;
bool zeroes;
QLIST_ENTRY(BlockCopyTask) list;
CoQueue wait_queue; /* coroutines blocked on this task */
} BlockCopyTask;
static int64_t task_end(BlockCopyTask *task)
{
return task->offset + task->bytes;
}
typedef struct BlockCopyState {
/*
@ -45,7 +65,7 @@ typedef struct BlockCopyState {
bool use_copy_range;
int64_t copy_size;
uint64_t len;
QLIST_HEAD(, BlockCopyInFlightReq) inflight_reqs;
QLIST_HEAD(, BlockCopyTask) tasks;
BdrvRequestFlags write_flags;
@ -73,15 +93,14 @@ typedef struct BlockCopyState {
SharedResource *mem;
} BlockCopyState;
static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
int64_t offset,
int64_t bytes)
static BlockCopyTask *find_conflicting_task(BlockCopyState *s,
int64_t offset, int64_t bytes)
{
BlockCopyInFlightReq *req;
BlockCopyTask *t;
QLIST_FOREACH(req, &s->inflight_reqs, list) {
if (offset + bytes > req->offset && offset < req->offset + req->bytes) {
return req;
QLIST_FOREACH(t, &s->tasks, list) {
if (offset + bytes > t->offset && offset < t->offset + t->bytes) {
return t;
}
}
@ -89,73 +108,92 @@ static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
}
/*
* If there are no intersecting requests return false. Otherwise, wait for the
* first found intersecting request to finish and return true.
* If there are no intersecting tasks return false. Otherwise, wait for the
* first found intersecting tasks to finish and return true.
*/
static bool coroutine_fn block_copy_wait_one(BlockCopyState *s, int64_t offset,
int64_t bytes)
{
BlockCopyInFlightReq *req = find_conflicting_inflight_req(s, offset, bytes);
BlockCopyTask *task = find_conflicting_task(s, offset, bytes);
if (!req) {
if (!task) {
return false;
}
qemu_co_queue_wait(&req->wait_queue, NULL);
qemu_co_queue_wait(&task->wait_queue, NULL);
return true;
}
/* Called only on full-dirty region */
static void block_copy_inflight_req_begin(BlockCopyState *s,
BlockCopyInFlightReq *req,
int64_t offset, int64_t bytes)
/*
* Search for the first dirty area in offset/bytes range and create task at
* the beginning of it.
*/
static BlockCopyTask *block_copy_task_create(BlockCopyState *s,
BlockCopyCallState *call_state,
int64_t offset, int64_t bytes)
{
assert(!find_conflicting_inflight_req(s, offset, bytes));
BlockCopyTask *task;
if (!bdrv_dirty_bitmap_next_dirty_area(s->copy_bitmap,
offset, offset + bytes,
s->copy_size, &offset, &bytes))
{
return NULL;
}
/* region is dirty, so no existent tasks possible in it */
assert(!find_conflicting_task(s, offset, bytes));
bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes);
s->in_flight_bytes += bytes;
req->offset = offset;
req->bytes = bytes;
qemu_co_queue_init(&req->wait_queue);
QLIST_INSERT_HEAD(&s->inflight_reqs, req, list);
task = g_new(BlockCopyTask, 1);
*task = (BlockCopyTask) {
.task.func = block_copy_task_entry,
.s = s,
.call_state = call_state,
.offset = offset,
.bytes = bytes,
};
qemu_co_queue_init(&task->wait_queue);
QLIST_INSERT_HEAD(&s->tasks, task, list);
return task;
}
/*
* block_copy_inflight_req_shrink
* block_copy_task_shrink
*
* Drop the tail of the request to be handled later. Set dirty bits back and
* wake up all requests waiting for us (may be some of them are not intersecting
* with shrunk request)
* Drop the tail of the task to be handled later. Set dirty bits back and
* wake up all tasks waiting for us (may be some of them are not intersecting
* with shrunk task)
*/
static void coroutine_fn block_copy_inflight_req_shrink(BlockCopyState *s,
BlockCopyInFlightReq *req, int64_t new_bytes)
static void coroutine_fn block_copy_task_shrink(BlockCopyTask *task,
int64_t new_bytes)
{
if (new_bytes == req->bytes) {
if (new_bytes == task->bytes) {
return;
}
assert(new_bytes > 0 && new_bytes < req->bytes);
assert(new_bytes > 0 && new_bytes < task->bytes);
s->in_flight_bytes -= req->bytes - new_bytes;
bdrv_set_dirty_bitmap(s->copy_bitmap,
req->offset + new_bytes, req->bytes - new_bytes);
task->s->in_flight_bytes -= task->bytes - new_bytes;
bdrv_set_dirty_bitmap(task->s->copy_bitmap,
task->offset + new_bytes, task->bytes - new_bytes);
req->bytes = new_bytes;
qemu_co_queue_restart_all(&req->wait_queue);
task->bytes = new_bytes;
qemu_co_queue_restart_all(&task->wait_queue);
}
static void coroutine_fn block_copy_inflight_req_end(BlockCopyState *s,
BlockCopyInFlightReq *req,
int ret)
static void coroutine_fn block_copy_task_end(BlockCopyTask *task, int ret)
{
s->in_flight_bytes -= req->bytes;
task->s->in_flight_bytes -= task->bytes;
if (ret < 0) {
bdrv_set_dirty_bitmap(s->copy_bitmap, req->offset, req->bytes);
bdrv_set_dirty_bitmap(task->s->copy_bitmap, task->offset, task->bytes);
}
QLIST_REMOVE(req, list);
qemu_co_queue_restart_all(&req->wait_queue);
QLIST_REMOVE(task, list);
qemu_co_queue_restart_all(&task->wait_queue);
}
void block_copy_state_free(BlockCopyState *s)
@ -223,7 +261,7 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
s->copy_size = MAX(s->cluster_size, BLOCK_COPY_MAX_BUFFER);
}
QLIST_INIT(&s->inflight_reqs);
QLIST_INIT(&s->tasks);
return s;
}
@ -242,6 +280,38 @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm)
s->progress = pm;
}
/*
* Takes ownership of @task
*
* If pool is NULL directly run the task, otherwise schedule it into the pool.
*
* Returns: task.func return code if pool is NULL
* otherwise -ECANCELED if pool status is bad
* otherwise 0 (successfully scheduled)
*/
static coroutine_fn int block_copy_task_run(AioTaskPool *pool,
BlockCopyTask *task)
{
if (!pool) {
int ret = task->task.func(&task->task);
g_free(task);
return ret;
}
aio_task_pool_wait_slot(pool);
if (aio_task_pool_status(pool) < 0) {
co_put_to_shres(task->s->mem, task->bytes);
block_copy_task_end(task, -ECANCELED);
g_free(task);
return -ECANCELED;
}
aio_task_pool_start_task(pool, &task->task);
return 0;
}
/*
* block_copy_do_copy
*
@ -273,9 +343,7 @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
~BDRV_REQ_WRITE_COMPRESSED);
if (ret < 0) {
trace_block_copy_write_zeroes_fail(s, offset, ret);
if (error_is_read) {
*error_is_read = false;
}
*error_is_read = false;
}
return ret;
}
@ -323,9 +391,7 @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
ret = bdrv_co_pread(s->source, offset, nbytes, bounce_buffer, 0);
if (ret < 0) {
trace_block_copy_read_fail(s, offset, ret);
if (error_is_read) {
*error_is_read = true;
}
*error_is_read = true;
goto out;
}
@ -333,9 +399,7 @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
s->write_flags);
if (ret < 0) {
trace_block_copy_write_fail(s, offset, ret);
if (error_is_read) {
*error_is_read = false;
}
*error_is_read = false;
goto out;
}
@ -345,6 +409,27 @@ out:
return ret;
}
static coroutine_fn int block_copy_task_entry(AioTask *task)
{
BlockCopyTask *t = container_of(task, BlockCopyTask, task);
bool error_is_read = false;
int ret;
ret = block_copy_do_copy(t->s, t->offset, t->bytes, t->zeroes,
&error_is_read);
if (ret < 0 && !t->call_state->failed) {
t->call_state->failed = true;
t->call_state->error_is_read = error_is_read;
} else {
progress_work_done(t->s->progress, t->bytes);
t->s->progress_bytes_callback(t->bytes, t->s->progress_opaque);
}
co_put_to_shres(t->s->mem, t->bytes);
block_copy_task_end(t, ret);
return ret;
}
static int block_copy_block_status(BlockCopyState *s, int64_t offset,
int64_t bytes, int64_t *pnum)
{
@ -462,6 +547,9 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s,
{
int ret = 0;
bool found_dirty = false;
int64_t end = offset + bytes;
AioTaskPool *aio = NULL;
BlockCopyCallState call_state = {false, false};
/*
* block_copy() user is responsible for keeping source and target in same
@ -473,63 +561,80 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s,
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
assert(QEMU_IS_ALIGNED(bytes, s->cluster_size));
while (bytes) {
BlockCopyInFlightReq req;
int64_t next_zero, cur_bytes, status_bytes;
while (bytes && aio_task_pool_status(aio) == 0) {
BlockCopyTask *task;
int64_t status_bytes;
if (!bdrv_dirty_bitmap_get(s->copy_bitmap, offset)) {
trace_block_copy_skip(s, offset);
offset += s->cluster_size;
bytes -= s->cluster_size;
continue; /* already copied */
task = block_copy_task_create(s, &call_state, offset, bytes);
if (!task) {
/* No more dirty bits in the bitmap */
trace_block_copy_skip_range(s, offset, bytes);
break;
}
if (task->offset > offset) {
trace_block_copy_skip_range(s, offset, task->offset - offset);
}
found_dirty = true;
cur_bytes = MIN(bytes, s->copy_size);
next_zero = bdrv_dirty_bitmap_next_zero(s->copy_bitmap, offset,
cur_bytes);
if (next_zero >= 0) {
assert(next_zero > offset); /* offset is dirty */
assert(next_zero < offset + cur_bytes); /* no need to do MIN() */
cur_bytes = next_zero - offset;
}
block_copy_inflight_req_begin(s, &req, offset, cur_bytes);
ret = block_copy_block_status(s, offset, cur_bytes, &status_bytes);
ret = block_copy_block_status(s, task->offset, task->bytes,
&status_bytes);
assert(ret >= 0); /* never fail */
cur_bytes = MIN(cur_bytes, status_bytes);
block_copy_inflight_req_shrink(s, &req, cur_bytes);
if (status_bytes < task->bytes) {
block_copy_task_shrink(task, status_bytes);
}
if (s->skip_unallocated && !(ret & BDRV_BLOCK_ALLOCATED)) {
block_copy_inflight_req_end(s, &req, 0);
block_copy_task_end(task, 0);
progress_set_remaining(s->progress,
bdrv_get_dirty_count(s->copy_bitmap) +
s->in_flight_bytes);
trace_block_copy_skip_range(s, offset, status_bytes);
offset += status_bytes;
bytes -= status_bytes;
trace_block_copy_skip_range(s, task->offset, task->bytes);
offset = task_end(task);
bytes = end - offset;
g_free(task);
continue;
}
task->zeroes = ret & BDRV_BLOCK_ZERO;
trace_block_copy_process(s, offset);
trace_block_copy_process(s, task->offset);
co_get_from_shres(s->mem, cur_bytes);
ret = block_copy_do_copy(s, offset, cur_bytes, ret & BDRV_BLOCK_ZERO,
error_is_read);
co_put_to_shres(s->mem, cur_bytes);
block_copy_inflight_req_end(s, &req, ret);
if (ret < 0) {
return ret;
co_get_from_shres(s->mem, task->bytes);
offset = task_end(task);
bytes = end - offset;
if (!aio && bytes) {
aio = aio_task_pool_new(BLOCK_COPY_MAX_WORKERS);
}
progress_work_done(s->progress, cur_bytes);
s->progress_bytes_callback(cur_bytes, s->progress_opaque);
offset += cur_bytes;
bytes -= cur_bytes;
ret = block_copy_task_run(aio, task);
if (ret < 0) {
goto out;
}
}
return found_dirty;
out:
if (aio) {
aio_task_pool_wait_all(aio);
/*
* We are not really interested in -ECANCELED returned from
* block_copy_task_run. If it fails, it means some task already failed
* for real reason, let's return first failure.
* Still, assert that we don't rewrite failure by success.
*
* Note: ret may be positive here because of block-status result.
*/
assert(ret >= 0 || aio_task_pool_status(aio) < 0);
ret = aio_task_pool_status(aio);
aio_task_pool_free(aio);
}
if (error_is_read && ret < 0) {
*error_is_read = call_state.error_is_read;
}
return ret < 0 ? ret : found_dirty;
}
/*

View File

@ -110,8 +110,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
return ret;
}
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
false, errp);
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@ -297,10 +297,11 @@ static BlockDriver bdrv_bochs = {
.instance_size = sizeof(BDRVBochsState),
.bdrv_probe = bochs_probe,
.bdrv_open = bochs_open,
.bdrv_child_perm = bdrv_format_default_perms,
.bdrv_child_perm = bdrv_default_perms,
.bdrv_refresh_limits = bochs_refresh_limits,
.bdrv_co_preadv = bochs_co_preadv,
.bdrv_close = bochs_close,
.is_format = true,
};
static void bdrv_bochs_init(void)

View File

@ -71,8 +71,8 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
return ret;
}
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
false, errp);
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@ -293,10 +293,11 @@ static BlockDriver bdrv_cloop = {
.instance_size = sizeof(BDRVCloopState),
.bdrv_probe = cloop_probe,
.bdrv_open = cloop_open,
.bdrv_child_perm = bdrv_format_default_perms,
.bdrv_child_perm = bdrv_default_perms,
.bdrv_refresh_limits = cloop_refresh_limits,
.bdrv_co_preadv = cloop_co_preadv,
.bdrv_close = cloop_close,
.is_format = true,
};
static void bdrv_cloop_init(void)

View File

@ -133,7 +133,7 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
}
if (base_len < len) {
ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, NULL);
ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL);
if (ret) {
goto out;
}
@ -223,7 +223,7 @@ static void bdrv_commit_top_refresh_filename(BlockDriverState *bs)
}
static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c,
const BdrvChildRole *role,
BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
@ -240,6 +240,8 @@ static BlockDriver bdrv_commit_top = {
.bdrv_co_block_status = bdrv_co_block_status_from_backing,
.bdrv_refresh_filename = bdrv_commit_top_refresh_filename,
.bdrv_child_perm = bdrv_commit_top_child_perm,
.is_filter = true,
};
void commit_start(const char *job_id, BlockDriverState *bs,
@ -414,7 +416,9 @@ int bdrv_commit(BlockDriverState *bs)
}
ctx = bdrv_get_aio_context(bs);
src = blk_new(ctx, BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
/* WRITE_UNCHANGED is required for bdrv_make_empty() */
src = blk_new(ctx, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED,
BLK_PERM_ALL);
backing = blk_new(ctx, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
ret = blk_insert_bs(src, bs, &local_err);
@ -458,7 +462,7 @@ int bdrv_commit(BlockDriverState *bs)
* grow the backing file image if possible. If not possible,
* we must return an error */
if (length > backing_length) {
ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF,
ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, 0,
&local_err);
if (ret < 0) {
error_report_err(local_err);
@ -492,14 +496,14 @@ int bdrv_commit(BlockDriverState *bs)
}
}
if (drv->bdrv_make_empty) {
ret = drv->bdrv_make_empty(bs);
if (ret < 0) {
goto ro_cleanup;
}
blk_flush(src);
ret = blk_make_empty(src, NULL);
/* Ignore -ENOTSUP */
if (ret < 0 && ret != -ENOTSUP) {
goto ro_cleanup;
}
blk_flush(src);
/*
* Make sure all data we wrote to the backing device is actually
* stable on disk.

View File

@ -28,8 +28,9 @@
static int cor_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
errp);
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
false, errp);
if (!bs->file) {
return -EINVAL;
}
@ -51,7 +52,7 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags,
#define PERM_UNCHANGED (BLK_PERM_ALL & ~PERM_PASSTHROUGH)
static void cor_child_perm(BlockDriverState *bs, BdrvChild *c,
const BdrvChildRole *role,
BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)

View File

@ -37,6 +37,7 @@ typedef struct BlockCrypto BlockCrypto;
struct BlockCrypto {
QCryptoBlock *block;
bool updating_keys;
};
@ -71,6 +72,24 @@ static ssize_t block_crypto_read_func(QCryptoBlock *block,
return ret;
}
static ssize_t block_crypto_write_func(QCryptoBlock *block,
size_t offset,
const uint8_t *buf,
size_t buflen,
void *opaque,
Error **errp)
{
BlockDriverState *bs = opaque;
ssize_t ret;
ret = bdrv_pwrite(bs->file, offset, buf, buflen);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not write encryption header");
return ret;
}
return ret;
}
struct BlockCryptoCreateData {
BlockBackend *blk;
@ -79,12 +98,12 @@ struct BlockCryptoCreateData {
};
static ssize_t block_crypto_write_func(QCryptoBlock *block,
size_t offset,
const uint8_t *buf,
size_t buflen,
void *opaque,
Error **errp)
static ssize_t block_crypto_create_write_func(QCryptoBlock *block,
size_t offset,
const uint8_t *buf,
size_t buflen,
void *opaque,
Error **errp)
{
struct BlockCryptoCreateData *data = opaque;
ssize_t ret;
@ -97,25 +116,41 @@ static ssize_t block_crypto_write_func(QCryptoBlock *block,
return ret;
}
static ssize_t block_crypto_init_func(QCryptoBlock *block,
size_t headerlen,
void *opaque,
Error **errp)
static ssize_t block_crypto_create_init_func(QCryptoBlock *block,
size_t headerlen,
void *opaque,
Error **errp)
{
struct BlockCryptoCreateData *data = opaque;
Error *local_error = NULL;
int ret;
if (data->size > INT64_MAX || headerlen > INT64_MAX - data->size) {
error_setg(errp, "The requested file size is too large");
return -EFBIG;
ret = -EFBIG;
goto error;
}
/* User provided size should reflect amount of space made
* available to the guest, so we must take account of that
* which will be used by the crypto header
*/
return blk_truncate(data->blk, data->size + headerlen, false,
data->prealloc, errp);
ret = blk_truncate(data->blk, data->size + headerlen, false,
data->prealloc, 0, &local_error);
if (ret >= 0) {
return ret;
}
error:
if (ret == -EFBIG) {
/* Replace the error message with a better one */
error_free(local_error);
error_setg(errp, "The requested file size is too large");
} else {
error_propagate(errp, local_error);
}
return ret;
}
@ -150,6 +185,19 @@ static QemuOptsList block_crypto_create_opts_luks = {
};
static QemuOptsList block_crypto_amend_opts_luks = {
.name = "crypto",
.head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head),
.desc = {
BLOCK_CRYPTO_OPT_DEF_LUKS_STATE(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""),
{ /* end of list */ }
},
};
QCryptoBlockOpenOptions *
block_crypto_open_opts_init(QDict *opts, Error **errp)
{
@ -185,6 +233,23 @@ block_crypto_create_opts_init(QDict *opts, Error **errp)
return ret;
}
QCryptoBlockAmendOptions *
block_crypto_amend_opts_init(QDict *opts, Error **errp)
{
Visitor *v;
QCryptoBlockAmendOptions *ret;
v = qobject_input_visitor_new_flat_confused(opts, errp);
if (!v) {
return NULL;
}
visit_type_QCryptoBlockAmendOptions(v, NULL, &ret, errp);
visit_free(v);
return ret;
}
static int block_crypto_open_generic(QCryptoBlockFormat format,
QemuOptsList *opts_spec,
@ -195,14 +260,13 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
{
BlockCrypto *crypto = bs->opaque;
QemuOpts *opts = NULL;
Error *local_err = NULL;
int ret = -EINVAL;
QCryptoBlockOpenOptions *open_opts = NULL;
unsigned int cflags = 0;
QDict *cryptoopts = NULL;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
false, errp);
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@ -211,9 +275,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
bs->file->bs->supported_write_flags;
opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
goto cleanup;
}
@ -261,11 +323,10 @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
QCryptoBlock *crypto = NULL;
struct BlockCryptoCreateData data;
blk = blk_new(bdrv_get_aio_context(bs),
BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
ret = blk_insert_bs(blk, bs, errp);
if (ret < 0) {
blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL,
errp);
if (!blk) {
ret = -EPERM;
goto cleanup;
}
@ -280,8 +341,8 @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
};
crypto = qcrypto_block_create(opts, NULL,
block_crypto_init_func,
block_crypto_write_func,
block_crypto_create_init_func,
block_crypto_create_write_func,
&data,
errp);
@ -299,7 +360,8 @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
static int coroutine_fn
block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp)
PreallocMode prealloc, BdrvRequestFlags flags,
Error **errp)
{
BlockCrypto *crypto = bs->opaque;
uint64_t payload_offset =
@ -312,7 +374,7 @@ block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
offset += payload_offset;
return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
}
static void block_crypto_close(BlockDriverState *bs)
@ -535,7 +597,7 @@ static BlockMeasureInfo *block_crypto_measure(QemuOpts *opts,
* Unallocated blocks are still encrypted so allocation status makes no
* difference to the file size.
*/
info = g_new(BlockMeasureInfo, 1);
info = g_new0(BlockMeasureInfo, 1);
info->fully_allocated = luks_payload_size + size;
info->required = luks_payload_size + size;
return info;
@ -693,7 +755,6 @@ static int block_crypto_get_info_luks(BlockDriverState *bs,
return ret;
}
bdi->unallocated_blocks_are_zero = false;
bdi->cluster_size = subbdi.cluster_size;
return 0;
@ -725,6 +786,131 @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp)
return spec_info;
}
static int
block_crypto_amend_options_generic_luks(BlockDriverState *bs,
QCryptoBlockAmendOptions *amend_options,
bool force,
Error **errp)
{
BlockCrypto *crypto = bs->opaque;
int ret;
assert(crypto);
assert(crypto->block);
/* apply for exclusive read/write permissions to the underlying file*/
crypto->updating_keys = true;
ret = bdrv_child_refresh_perms(bs, bs->file, errp);
if (ret) {
goto cleanup;
}
ret = qcrypto_block_amend_options(crypto->block,
block_crypto_read_func,
block_crypto_write_func,
bs,
amend_options,
force,
errp);
cleanup:
/* release exclusive read/write permissions to the underlying file*/
crypto->updating_keys = false;
bdrv_child_refresh_perms(bs, bs->file, errp);
return ret;
}
static int
block_crypto_amend_options_luks(BlockDriverState *bs,
QemuOpts *opts,
BlockDriverAmendStatusCB *status_cb,
void *cb_opaque,
bool force,
Error **errp)
{
BlockCrypto *crypto = bs->opaque;
QDict *cryptoopts = NULL;
QCryptoBlockAmendOptions *amend_options = NULL;
int ret = -EINVAL;
assert(crypto);
assert(crypto->block);
cryptoopts = qemu_opts_to_qdict(opts, NULL);
qdict_put_str(cryptoopts, "format", "luks");
amend_options = block_crypto_amend_opts_init(cryptoopts, errp);
qobject_unref(cryptoopts);
if (!amend_options) {
goto cleanup;
}
ret = block_crypto_amend_options_generic_luks(bs, amend_options,
force, errp);
cleanup:
qapi_free_QCryptoBlockAmendOptions(amend_options);
return ret;
}
static int
coroutine_fn block_crypto_co_amend_luks(BlockDriverState *bs,
BlockdevAmendOptions *opts,
bool force,
Error **errp)
{
QCryptoBlockAmendOptions amend_opts;
amend_opts = (QCryptoBlockAmendOptions) {
.format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
.u.luks = *qapi_BlockdevAmendOptionsLUKS_base(&opts->u.luks),
};
return block_crypto_amend_options_generic_luks(bs, &amend_opts,
force, errp);
}
static void
block_crypto_child_perms(BlockDriverState *bs, BdrvChild *c,
const BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
{
BlockCrypto *crypto = bs->opaque;
bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared);
/*
* For backward compatibility, manually share the write
* and resize permission
*/
*nshared |= shared & (BLK_PERM_WRITE | BLK_PERM_RESIZE);
/*
* Since we are not fully a format driver, don't always request
* the read/resize permission but only when explicitly
* requested
*/
*nperm &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
*nperm |= perm & (BLK_PERM_WRITE | BLK_PERM_RESIZE);
/*
* This driver doesn't modify LUKS metadata except
* when updating the encryption slots.
* Thus unlike a proper format driver we don't ask for
* shared write/read permission. However we need it
* when we are updating the keys, to ensure that only we
* have access to the device.
*
* Encryption update will set the crypto->updating_keys
* during that period and refresh permissions
*
*/
if (crypto->updating_keys) {
/* need exclusive write access for header update */
*nperm |= BLK_PERM_WRITE;
/* unshare read and write permission */
*nshared &= ~(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE);
}
}
static const char *const block_crypto_strong_runtime_opts[] = {
BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
@ -737,13 +923,12 @@ static BlockDriver bdrv_crypto_luks = {
.bdrv_probe = block_crypto_probe_luks,
.bdrv_open = block_crypto_open_luks,
.bdrv_close = block_crypto_close,
/* This driver doesn't modify LUKS metadata except when creating image.
* Allow share-rw=on as a special case. */
.bdrv_child_perm = bdrv_filter_default_perms,
.bdrv_child_perm = block_crypto_child_perms,
.bdrv_co_create = block_crypto_co_create_luks,
.bdrv_co_create_opts = block_crypto_co_create_opts_luks,
.bdrv_co_truncate = block_crypto_co_truncate,
.create_opts = &block_crypto_create_opts_luks,
.amend_opts = &block_crypto_amend_opts_luks,
.bdrv_reopen_prepare = block_crypto_reopen_prepare,
.bdrv_refresh_limits = block_crypto_refresh_limits,
@ -753,6 +938,10 @@ static BlockDriver bdrv_crypto_luks = {
.bdrv_measure = block_crypto_measure,
.bdrv_get_info = block_crypto_get_info_luks,
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
.bdrv_amend_options = block_crypto_amend_options_luks,
.bdrv_co_amend = block_crypto_co_amend_luks,
.is_format = true,
.strong_runtime_opts = block_crypto_strong_runtime_opts,
};

View File

@ -41,6 +41,11 @@
#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg"
#define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg"
#define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time"
#define BLOCK_CRYPTO_OPT_LUKS_KEYSLOT "keyslot"
#define BLOCK_CRYPTO_OPT_LUKS_STATE "state"
#define BLOCK_CRYPTO_OPT_LUKS_OLD_SECRET "old-secret"
#define BLOCK_CRYPTO_OPT_LUKS_NEW_SECRET "new-secret"
#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(prefix) \
BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, \
@ -88,9 +93,41 @@
.help = "Time to spend in PBKDF in milliseconds", \
}
#define BLOCK_CRYPTO_OPT_DEF_LUKS_STATE(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_STATE, \
.type = QEMU_OPT_STRING, \
.help = "Select new state of affected keyslots (active/inactive)",\
}
#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_KEYSLOT, \
.type = QEMU_OPT_NUMBER, \
.help = "Select a single keyslot to modify explicitly",\
}
#define BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_OLD_SECRET, \
.type = QEMU_OPT_STRING, \
.help = "Select all keyslots that match this password", \
}
#define BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_NEW_SECRET, \
.type = QEMU_OPT_STRING, \
.help = "New secret to set in the matching keyslots. " \
"Empty string to erase", \
}
QCryptoBlockCreateOptions *
block_crypto_create_opts_init(QDict *opts, Error **errp);
QCryptoBlockAmendOptions *
block_crypto_amend_opts_init(QDict *opts, Error **errp);
QCryptoBlockOpenOptions *
block_crypto_open_opts_init(QDict *opts, Error **errp);

View File

@ -669,7 +669,6 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
BDRVCURLState *s = bs->opaque;
CURLState *state = NULL;
QemuOpts *opts;
Error *local_err = NULL;
const char *file;
const char *cookie;
const char *cookie_secret;
@ -695,9 +694,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
qemu_mutex_init(&s->mutex);
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
goto out_noclean;
}

View File

@ -478,6 +478,15 @@ int bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name,
}
}
bool
bdrv_supports_persistent_dirty_bitmap(BlockDriverState *bs)
{
if (bs->drv && bs->drv->bdrv_supports_persistent_dirty_bitmap) {
return bs->drv->bdrv_supports_persistent_dirty_bitmap(bs);
}
return false;
}
static bool coroutine_fn
bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
uint32_t granularity, Error **errp)
@ -809,6 +818,19 @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs)
return false;
}
bool bdrv_has_named_bitmaps(BlockDriverState *bs)
{
BdrvDirtyBitmap *bm;
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
if (bdrv_dirty_bitmap_name(bm)) {
return true;
}
}
return false;
}
/* Called with BQL taken. */
void bdrv_dirty_bitmap_set_persistence(BdrvDirtyBitmap *bitmap, bool persistent)
{

View File

@ -439,8 +439,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
return ret;
}
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
false, errp);
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@ -750,9 +750,10 @@ static BlockDriver bdrv_dmg = {
.bdrv_probe = dmg_probe,
.bdrv_open = dmg_open,
.bdrv_refresh_limits = dmg_refresh_limits,
.bdrv_child_perm = bdrv_format_default_perms,
.bdrv_child_perm = bdrv_default_perms,
.bdrv_co_preadv = dmg_co_preadv,
.bdrv_close = dmg_close,
.is_format = true,
};
static void bdrv_dmg_init(void)

View File

@ -30,6 +30,7 @@
#include "block/block_int.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/units.h"
#include "trace.h"
#include "block/thread-pool.h"
#include "qemu/iov.h"
@ -61,10 +62,12 @@
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/syscall.h>
#include <sys/vfs.h>
#include <linux/cdrom.h>
#include <linux/fd.h>
#include <linux/fs.h>
#include <linux/hdreg.h>
#include <linux/magic.h>
#include <scsi/sg.h>
#ifdef __s390__
#include <asm/dasd.h>
@ -299,6 +302,28 @@ static int probe_physical_blocksize(int fd, unsigned int *blk_size)
#endif
}
/*
* Returns true if no alignment restrictions are necessary even for files
* opened with O_DIRECT.
*
* raw_probe_alignment() probes the required alignment and assume that 1 means
* the probing failed, so it falls back to a safe default of 4k. This can be
* avoided if we know that byte alignment is okay for the file.
*/
static bool dio_byte_aligned(int fd)
{
#ifdef __linux__
struct statfs buf;
int ret;
ret = fstatfs(fd, &buf);
if (ret == 0 && buf.f_type == NFS_SUPER_MAGIC) {
return true;
}
#endif
return false;
}
/* Check if read is allowed with given memory buffer and length.
*
* This function is used to check O_DIRECT memory buffer and request alignment.
@ -400,6 +425,39 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
}
}
static int check_hdev_writable(int fd)
{
#if defined(BLKROGET)
/* Linux block devices can be configured "read-only" using blockdev(8).
* This is independent of device node permissions and therefore open(2)
* with O_RDWR succeeds. Actual writes fail with EPERM.
*
* bdrv_open() is supposed to fail if the disk is read-only. Explicitly
* check for read-only block devices so that Linux block devices behave
* properly.
*/
struct stat st;
int readonly = 0;
if (fstat(fd, &st)) {
return -errno;
}
if (!S_ISBLK(st.st_mode)) {
return 0;
}
if (ioctl(fd, BLKROGET, &readonly) < 0) {
return -errno;
}
if (readonly) {
return -EACCES;
}
#endif /* defined(BLKROGET) */
return 0;
}
static void raw_parse_flags(int bdrv_flags, int *open_flags, bool has_writers)
{
bool read_write = false;
@ -490,9 +548,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
OnOffAuto locking;
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
ret = -EINVAL;
goto fail;
}
@ -586,6 +642,15 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
}
s->fd = fd;
/* Check s->open_flags rather than bdrv_flags due to auto-read-only */
if (s->open_flags & O_RDWR) {
ret = check_hdev_writable(s->fd);
if (ret < 0) {
error_setg_errno(errp, -ret, "The device is not writable");
goto fail;
}
}
s->perm = 0;
s->shared_perm = BLK_PERM_ALL;
@ -630,7 +695,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
s->has_discard = true;
s->has_write_zeroes = true;
if ((bs->open_flags & BDRV_O_NOCACHE) != 0) {
if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) {
s->needs_alignment = true;
}
@ -702,8 +767,15 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
#endif
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
if (S_ISREG(st.st_mode)) {
/* When extending regular files, we get zeros from the OS */
bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
}
ret = 0;
fail:
if (ret < 0 && s->fd != -1) {
qemu_close(s->fd);
}
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
unlink(filename);
}
@ -974,6 +1046,15 @@ static int raw_reconfigure_getfd(BlockDriverState *bs, int flags,
}
}
if (fd != -1 && (*open_flags & O_RDWR)) {
ret = check_hdev_writable(fd);
if (ret < 0) {
qemu_close(fd);
error_setg_errno(errp, -ret, "The device is not writable");
return -1;
}
}
return fd;
}
@ -996,9 +1077,7 @@ static int raw_reopen_prepare(BDRVReopenState *state,
/* Handle options changes */
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, state->options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!qemu_opts_absorb_qdict(opts, state->options, errp)) {
ret = -EINVAL;
goto out;
}
@ -1613,22 +1692,24 @@ static int handle_aiocb_write_zeroes_unmap(void *opaque)
{
RawPosixAIOData *aiocb = opaque;
BDRVRawState *s G_GNUC_UNUSED = aiocb->bs->opaque;
int ret;
/* First try to write zeros and unmap at the same time */
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
aiocb->aio_offset, aiocb->aio_nbytes);
if (ret != -ENOTSUP) {
int ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
aiocb->aio_offset, aiocb->aio_nbytes);
switch (ret) {
case -ENOTSUP:
case -EINVAL:
break;
default:
return ret;
}
#endif
/* If we couldn't manage to unmap while guaranteed that the area reads as
* all-zero afterwards, just write zeroes without unmapping */
ret = handle_aiocb_write_zeroes(aiocb);
return ret;
return handle_aiocb_write_zeroes(aiocb);
}
#ifndef HAVE_COPY_FILE_RANGE
@ -2080,7 +2161,7 @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset,
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
bool exact, PreallocMode prealloc,
Error **errp)
BdrvRequestFlags flags, Error **errp)
{
BDRVRawState *s = bs->opaque;
struct stat st;
@ -2320,6 +2401,14 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
if (!file_opts->has_preallocation) {
file_opts->preallocation = PREALLOC_MODE_OFF;
}
if (!file_opts->has_extent_size_hint) {
file_opts->extent_size_hint = 1 * MiB;
}
if (file_opts->extent_size_hint > UINT32_MAX) {
result = -EINVAL;
error_setg(errp, "Extent size hint is too large");
goto out;
}
/* Create file */
fd = qemu_open(file_opts->filename, O_RDWR | O_CREAT | O_BINARY, 0644);
@ -2377,6 +2466,27 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
}
#endif
}
#ifdef FS_IOC_FSSETXATTR
/*
* Try to set the extent size hint. Failure is not fatal, and a warning is
* only printed if the option was explicitly specified.
*/
{
struct fsxattr attr;
result = ioctl(fd, FS_IOC_FSGETXATTR, &attr);
if (result == 0) {
attr.fsx_xflags |= FS_XFLAG_EXTSIZE;
attr.fsx_extsize = file_opts->extent_size_hint;
result = ioctl(fd, FS_IOC_FSSETXATTR, &attr);
}
if (result < 0 && file_opts->has_extent_size_hint &&
file_opts->extent_size_hint)
{
warn_report("Failed to set extent size hint: %s",
strerror(errno));
}
}
#endif
/* Resize and potentially preallocate the file to the desired
* final size */
@ -2412,6 +2522,8 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
{
BlockdevCreateOptions options;
int64_t total_size = 0;
int64_t extent_size_hint = 0;
bool has_extent_size_hint = false;
bool nocow = false;
PreallocMode prealloc;
char *buf = NULL;
@ -2423,6 +2535,11 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
/* Read out options */
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
if (qemu_opt_get(opts, BLOCK_OPT_EXTENT_SIZE_HINT)) {
has_extent_size_hint = true;
extent_size_hint =
qemu_opt_get_size_del(opts, BLOCK_OPT_EXTENT_SIZE_HINT, -1);
}
nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
@ -2442,6 +2559,8 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
.preallocation = prealloc,
.has_nocow = true,
.nocow = nocow,
.has_extent_size_hint = has_extent_size_hint,
.extent_size_hint = extent_size_hint,
},
};
return raw_co_create(&options, errp);
@ -2691,10 +2810,13 @@ static void check_cache_dropped(BlockDriverState *bs, Error **errp)
vec_end = DIV_ROUND_UP(length, page_size);
for (i = 0; i < vec_end; i++) {
if (vec[i] & 0x1) {
error_setg(errp, "page cache still in use!");
break;
}
}
if (i < vec_end) {
error_setg(errp, "page cache still in use!");
break;
}
}
if (window) {
@ -2873,9 +2995,6 @@ static int coroutine_fn raw_co_pwrite_zeroes(
static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
BDRVRawState *s = bs->opaque;
bdi->unallocated_blocks_are_zero = s->discard_zeroes;
return 0;
}
@ -2932,6 +3051,11 @@ static QemuOptsList raw_create_opts = {
#endif
", full)"
},
{
.name = BLOCK_OPT_EXTENT_SIZE_HINT,
.type = QEMU_OPT_SIZE,
.help = "Extent size hint for the image file, 0 to disable"
},
{ /* end of list */ }
}
};
@ -3095,7 +3219,6 @@ BlockDriver bdrv_file = {
.bdrv_co_create = raw_co_create,
.bdrv_co_create_opts = raw_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
.bdrv_co_block_status = raw_co_block_status,
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
.bdrv_co_pwrite_zeroes = raw_co_pwrite_zeroes,
@ -3258,39 +3381,6 @@ static int hdev_probe_device(const char *filename)
return 0;
}
static int check_hdev_writable(BDRVRawState *s)
{
#if defined(BLKROGET)
/* Linux block devices can be configured "read-only" using blockdev(8).
* This is independent of device node permissions and therefore open(2)
* with O_RDWR succeeds. Actual writes fail with EPERM.
*
* bdrv_open() is supposed to fail if the disk is read-only. Explicitly
* check for read-only block devices so that Linux block devices behave
* properly.
*/
struct stat st;
int readonly = 0;
if (fstat(s->fd, &st)) {
return -errno;
}
if (!S_ISBLK(st.st_mode)) {
return 0;
}
if (ioctl(s->fd, BLKROGET, &readonly) < 0) {
return -errno;
}
if (readonly) {
return -EACCES;
}
#endif /* defined(BLKROGET) */
return 0;
}
static void hdev_parse_filename(const char *filename, QDict *options,
Error **errp)
{
@ -3332,7 +3422,6 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVRawState *s = bs->opaque;
Error *local_err = NULL;
int ret;
#if defined(__APPLE__) && defined(__MACH__)
@ -3397,9 +3486,8 @@ hdev_open_Mac_error:
s->type = FTYPE_FILE;
ret = raw_open_common(bs, options, flags, 0, true, &local_err);
ret = raw_open_common(bs, options, flags, 0, true, errp);
if (ret < 0) {
error_propagate(errp, local_err);
#if defined(__APPLE__) && defined(__MACH__)
if (*bsd_path) {
filename = bsd_path;
@ -3415,15 +3503,6 @@ hdev_open_Mac_error:
/* Since this does ioctl the device must be already opened */
bs->sg = hdev_is_sg(bs);
if (flags & BDRV_O_RDWR) {
ret = check_hdev_writable(s);
if (ret < 0) {
raw_close(bs);
error_setg_errno(errp, -ret, "The device is not writable");
return ret;
}
}
return ret;
}
@ -3675,14 +3754,12 @@ static int cdrom_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVRawState *s = bs->opaque;
Error *local_err = NULL;
int ret;
s->type = FTYPE_CD;
ret = raw_open_common(bs, options, flags, 0, true, &local_err);
ret = raw_open_common(bs, options, flags, 0, true, errp);
if (ret) {
error_propagate(errp, local_err);
return ret;
}

View File

@ -338,9 +338,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
s->type = FTYPE_FILE;
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
ret = -EINVAL;
goto fail;
}
@ -408,6 +406,9 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
win32_aio_attach_aio_context(s->aio, bdrv_get_aio_context(bs));
}
/* When extending regular files, we get zeros from the OS */
bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
ret = 0;
fail:
qemu_opts_del(opts);
@ -469,7 +470,7 @@ static void raw_close(BlockDriverState *bs)
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
bool exact, PreallocMode prealloc,
Error **errp)
BdrvRequestFlags flags, Error **errp)
{
BDRVRawState *s = bs->opaque;
LONG low, high;
@ -638,7 +639,6 @@ BlockDriver bdrv_file = {
.bdrv_close = raw_close,
.bdrv_co_create_opts = raw_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
.bdrv_aio_preadv = raw_aio_preadv,
.bdrv_aio_pwritev = raw_aio_pwritev,
@ -737,9 +737,7 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
QemuOpts *opts = qemu_opts_create(&raw_runtime_opts, NULL, 0,
&error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
ret = -EINVAL;
goto done;
}

View File

@ -30,8 +30,9 @@
static int compress_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
errp);
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
false, errp);
if (!bs->file) {
return -EINVAL;
}
@ -132,7 +133,7 @@ static BlockDriver bdrv_compress = {
.format_name = "compress",
.bdrv_open = compress_open,
.bdrv_child_perm = bdrv_filter_default_perms,
.bdrv_child_perm = bdrv_default_perms,
.bdrv_getlength = compress_getlength,

View File

@ -523,8 +523,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
/* create opts info from runtime_json_opts list */
opts = qemu_opts_create(&runtime_json_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
goto out;
}
@ -555,8 +554,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
/* create opts info from runtime_type_opts list */
opts = qemu_opts_create(&runtime_type_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, backing_options, &local_err);
if (local_err) {
if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
goto out;
}
@ -586,8 +584,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
if (gsconf->type == SOCKET_ADDRESS_TYPE_INET) {
/* create opts info from runtime_inet_opts list */
opts = qemu_opts_create(&runtime_inet_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, backing_options, &local_err);
if (local_err) {
if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
goto out;
}
@ -635,8 +632,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
} else {
/* create opts info from runtime_unix_opts list */
opts = qemu_opts_create(&runtime_unix_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, backing_options, &local_err);
if (local_err) {
if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
goto out;
}
@ -815,13 +811,10 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
int ret = 0;
BlockdevOptionsGluster *gconf = NULL;
QemuOpts *opts;
Error *local_err = NULL;
const char *filename, *logfile;
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
ret = -EINVAL;
goto out;
}
@ -1228,6 +1221,7 @@ static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
int64_t offset,
bool exact,
PreallocMode prealloc,
BdrvRequestFlags flags,
Error **errp)
{
BDRVGlusterState *s = bs->opaque;
@ -1358,12 +1352,6 @@ static int64_t qemu_gluster_allocated_file_size(BlockDriverState *bs)
}
}
static int qemu_gluster_has_zero_init(BlockDriverState *bs)
{
/* GlusterFS volume could be backed by a block device */
return 0;
}
/*
* Find allocation range in @bs around offset @start.
* May change underlying file descriptor's file offset.
@ -1568,8 +1556,6 @@ static BlockDriver bdrv_gluster = {
.bdrv_co_readv = qemu_gluster_co_readv,
.bdrv_co_writev = qemu_gluster_co_writev,
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
.bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init,
#ifdef CONFIG_GLUSTERFS_DISCARD
.bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
#endif
@ -1600,8 +1586,6 @@ static BlockDriver bdrv_gluster_tcp = {
.bdrv_co_readv = qemu_gluster_co_readv,
.bdrv_co_writev = qemu_gluster_co_writev,
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
.bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init,
#ifdef CONFIG_GLUSTERFS_DISCARD
.bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
#endif
@ -1632,8 +1616,6 @@ static BlockDriver bdrv_gluster_unix = {
.bdrv_co_readv = qemu_gluster_co_readv,
.bdrv_co_writev = qemu_gluster_co_writev,
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
.bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init,
#ifdef CONFIG_GLUSTERFS_DISCARD
.bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
#endif
@ -1670,8 +1652,6 @@ static BlockDriver bdrv_gluster_rdma = {
.bdrv_co_readv = qemu_gluster_co_readv,
.bdrv_co_writev = qemu_gluster_co_writev,
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
.bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init,
#ifdef CONFIG_GLUSTERFS_DISCARD
.bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
#endif

View File

@ -35,8 +35,6 @@
#include "qemu/main-loop.h"
#include "sysemu/replay.h"
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
/* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */
#define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS)
@ -50,7 +48,7 @@ static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
BdrvChild *c, *next;
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) {
if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) {
continue;
}
bdrv_parent_drained_begin_single(c, false);
@ -62,8 +60,8 @@ static void bdrv_parent_drained_end_single_no_poll(BdrvChild *c,
{
assert(c->parent_quiesce_counter > 0);
c->parent_quiesce_counter--;
if (c->role->drained_end) {
c->role->drained_end(c, drained_end_counter);
if (c->klass->drained_end) {
c->klass->drained_end(c, drained_end_counter);
}
}
@ -81,7 +79,7 @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
BdrvChild *c;
QLIST_FOREACH(c, &bs->parents, next_parent) {
if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) {
if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) {
continue;
}
bdrv_parent_drained_end_single_no_poll(c, drained_end_counter);
@ -90,8 +88,8 @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
static bool bdrv_parent_drained_poll_single(BdrvChild *c)
{
if (c->role->drained_poll) {
return c->role->drained_poll(c);
if (c->klass->drained_poll) {
return c->klass->drained_poll(c);
}
return false;
}
@ -103,7 +101,7 @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
bool busy = false;
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) {
if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) {
continue;
}
busy |= bdrv_parent_drained_poll_single(c);
@ -115,8 +113,8 @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll)
{
c->parent_quiesce_counter++;
if (c->role->drained_begin) {
c->role->drained_begin(c);
if (c->klass->drained_begin) {
c->klass->drained_begin(c);
}
if (poll) {
BDRV_POLL_WHILE(c->bs, bdrv_parent_drained_poll_single(c));
@ -891,29 +889,63 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
return 0;
}
typedef int coroutine_fn BdrvRequestEntry(void *opaque);
typedef struct BdrvRunCo {
BdrvRequestEntry *entry;
void *opaque;
int ret;
bool done;
Coroutine *co; /* Coroutine, running bdrv_run_co_entry, for debugging */
} BdrvRunCo;
static void coroutine_fn bdrv_run_co_entry(void *opaque)
{
BdrvRunCo *arg = opaque;
arg->ret = arg->entry(arg->opaque);
arg->done = true;
aio_wait_kick();
}
static int bdrv_run_co(BlockDriverState *bs, BdrvRequestEntry *entry,
void *opaque)
{
if (qemu_in_coroutine()) {
/* Fast-path if already in coroutine context */
return entry(opaque);
} else {
BdrvRunCo s = { .entry = entry, .opaque = opaque };
s.co = qemu_coroutine_create(bdrv_run_co_entry, &s);
bdrv_coroutine_enter(bs, s.co);
BDRV_POLL_WHILE(bs, !s.done);
return s.ret;
}
}
typedef struct RwCo {
BdrvChild *child;
int64_t offset;
QEMUIOVector *qiov;
bool is_write;
int ret;
BdrvRequestFlags flags;
} RwCo;
static void coroutine_fn bdrv_rw_co_entry(void *opaque)
static int coroutine_fn bdrv_rw_co_entry(void *opaque)
{
RwCo *rwco = opaque;
if (!rwco->is_write) {
rwco->ret = bdrv_co_preadv(rwco->child, rwco->offset,
rwco->qiov->size, rwco->qiov,
rwco->flags);
return bdrv_co_preadv(rwco->child, rwco->offset,
rwco->qiov->size, rwco->qiov,
rwco->flags);
} else {
rwco->ret = bdrv_co_pwritev(rwco->child, rwco->offset,
rwco->qiov->size, rwco->qiov,
rwco->flags);
return bdrv_co_pwritev(rwco->child, rwco->offset,
rwco->qiov->size, rwco->qiov,
rwco->flags);
}
aio_wait_kick();
}
/*
@ -923,25 +955,15 @@ static int bdrv_prwv_co(BdrvChild *child, int64_t offset,
QEMUIOVector *qiov, bool is_write,
BdrvRequestFlags flags)
{
Coroutine *co;
RwCo rwco = {
.child = child,
.offset = offset,
.qiov = qiov,
.is_write = is_write,
.ret = NOT_DONE,
.flags = flags,
};
if (qemu_in_coroutine()) {
/* Fast-path if already in coroutine context */
bdrv_rw_co_entry(&rwco);
} else {
co = qemu_coroutine_create(bdrv_rw_co_entry, &rwco);
bdrv_coroutine_enter(child->bs, co);
BDRV_POLL_WHILE(child->bs, rwco.ret == NOT_DONE);
}
return rwco.ret;
return bdrv_run_co(child->bs, bdrv_rw_co_entry, &rwco);
}
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
@ -960,7 +982,7 @@ int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
* flags are passed through to bdrv_pwrite_zeroes (e.g. BDRV_REQ_MAY_UNMAP,
* BDRV_REQ_FUA).
*
* Returns < 0 on error, 0 on success. For error codes see bdrv_write().
* Returns < 0 on error, 0 on success. For error codes see bdrv_pwrite().
*/
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
{
@ -994,6 +1016,7 @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
}
}
/* return < 0 if error. See bdrv_pwrite() for the return codes */
int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
{
int ret;
@ -1501,12 +1524,13 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
assert(num);
ret = bdrv_driver_preadv(bs, offset + bytes - bytes_remaining,
num, qiov, bytes - bytes_remaining, 0);
num, qiov,
qiov_offset + bytes - bytes_remaining, 0);
max_bytes -= num;
} else {
num = bytes_remaining;
ret = qemu_iovec_memset(qiov, bytes - bytes_remaining, 0,
bytes_remaining);
ret = qemu_iovec_memset(qiov, qiov_offset + bytes - bytes_remaining,
0, bytes_remaining);
}
if (ret < 0) {
goto out;
@ -2009,7 +2033,8 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
}
ret = bdrv_driver_pwritev(bs, offset + bytes - bytes_remaining,
num, qiov, bytes - bytes_remaining,
num, qiov,
qiov_offset + bytes - bytes_remaining,
local_flags);
if (ret < 0) {
break;
@ -2228,8 +2253,6 @@ typedef struct BdrvCoBlockStatusData {
int64_t *pnum;
int64_t *map;
BlockDriverState **file;
int ret;
bool done;
} BdrvCoBlockStatusData;
int coroutine_fn bdrv_co_block_status_from_file(BlockDriverState *bs,
@ -2385,16 +2408,16 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
ret |= BDRV_BLOCK_ALLOCATED;
} else if (want_zero) {
if (bdrv_unallocated_blocks_are_zero(bs)) {
ret |= BDRV_BLOCK_ZERO;
} else if (bs->backing) {
} else if (want_zero && bs->drv->supports_backing) {
if (bs->backing) {
BlockDriverState *bs2 = bs->backing->bs;
int64_t size2 = bdrv_getlength(bs2);
if (size2 >= 0 && offset >= size2) {
ret |= BDRV_BLOCK_ZERO;
}
} else {
ret |= BDRV_BLOCK_ZERO;
}
}
@ -2483,16 +2506,14 @@ static int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
}
/* Coroutine wrapper for bdrv_block_status_above() */
static void coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
static int coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
{
BdrvCoBlockStatusData *data = opaque;
data->ret = bdrv_co_block_status_above(data->bs, data->base,
data->want_zero,
data->offset, data->bytes,
data->pnum, data->map, data->file);
data->done = true;
aio_wait_kick();
return bdrv_co_block_status_above(data->bs, data->base,
data->want_zero,
data->offset, data->bytes,
data->pnum, data->map, data->file);
}
/*
@ -2507,7 +2528,6 @@ static int bdrv_common_block_status_above(BlockDriverState *bs,
int64_t *map,
BlockDriverState **file)
{
Coroutine *co;
BdrvCoBlockStatusData data = {
.bs = bs,
.base = base,
@ -2517,18 +2537,9 @@ static int bdrv_common_block_status_above(BlockDriverState *bs,
.pnum = pnum,
.map = map,
.file = file,
.done = false,
};
if (qemu_in_coroutine()) {
/* Fast-path if already in coroutine context */
bdrv_block_status_above_co_entry(&data);
} else {
co = qemu_coroutine_create(bdrv_block_status_above_co_entry, &data);
bdrv_coroutine_enter(bs, co);
BDRV_POLL_WHILE(bs, !data.done);
}
return data.ret;
return bdrv_run_co(bs, bdrv_block_status_above_co_entry, &data);
}
int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
@ -2629,7 +2640,6 @@ typedef struct BdrvVmstateCo {
QEMUIOVector *qiov;
int64_t pos;
bool is_read;
int ret;
} BdrvVmstateCo;
static int coroutine_fn
@ -2657,33 +2667,25 @@ bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
return ret;
}
static void coroutine_fn bdrv_co_rw_vmstate_entry(void *opaque)
static int coroutine_fn bdrv_co_rw_vmstate_entry(void *opaque)
{
BdrvVmstateCo *co = opaque;
co->ret = bdrv_co_rw_vmstate(co->bs, co->qiov, co->pos, co->is_read);
aio_wait_kick();
return bdrv_co_rw_vmstate(co->bs, co->qiov, co->pos, co->is_read);
}
static inline int
bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
bool is_read)
{
if (qemu_in_coroutine()) {
return bdrv_co_rw_vmstate(bs, qiov, pos, is_read);
} else {
BdrvVmstateCo data = {
.bs = bs,
.qiov = qiov,
.pos = pos,
.is_read = is_read,
.ret = -EINPROGRESS,
};
Coroutine *co = qemu_coroutine_create(bdrv_co_rw_vmstate_entry, &data);
BdrvVmstateCo data = {
.bs = bs,
.qiov = qiov,
.pos = pos,
.is_read = is_read,
};
bdrv_coroutine_enter(bs, co);
BDRV_POLL_WHILE(bs, data.ret == -EINPROGRESS);
return data.ret;
}
return bdrv_run_co(bs, bdrv_co_rw_vmstate_entry, &data);
}
int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
@ -2761,18 +2763,9 @@ void bdrv_aio_cancel_async(BlockAIOCB *acb)
/**************************************************************/
/* Coroutine block device emulation */
typedef struct FlushCo {
BlockDriverState *bs;
int ret;
} FlushCo;
static void coroutine_fn bdrv_flush_co_entry(void *opaque)
static int coroutine_fn bdrv_flush_co_entry(void *opaque)
{
FlushCo *rwco = opaque;
rwco->ret = bdrv_co_flush(rwco->bs);
aio_wait_kick();
return bdrv_co_flush(opaque);
}
int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
@ -2889,36 +2882,20 @@ early_exit:
int bdrv_flush(BlockDriverState *bs)
{
Coroutine *co;
FlushCo flush_co = {
.bs = bs,
.ret = NOT_DONE,
};
if (qemu_in_coroutine()) {
/* Fast-path if already in coroutine context */
bdrv_flush_co_entry(&flush_co);
} else {
co = qemu_coroutine_create(bdrv_flush_co_entry, &flush_co);
bdrv_coroutine_enter(bs, co);
BDRV_POLL_WHILE(bs, flush_co.ret == NOT_DONE);
}
return flush_co.ret;
return bdrv_run_co(bs, bdrv_flush_co_entry, bs);
}
typedef struct DiscardCo {
BdrvChild *child;
int64_t offset;
int64_t bytes;
int ret;
} DiscardCo;
static void coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
static int coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
{
DiscardCo *rwco = opaque;
rwco->ret = bdrv_co_pdiscard(rwco->child, rwco->offset, rwco->bytes);
aio_wait_kick();
return bdrv_co_pdiscard(rwco->child, rwco->offset, rwco->bytes);
}
int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
@ -3037,24 +3014,13 @@ out:
int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes)
{
Coroutine *co;
DiscardCo rwco = {
.child = child,
.offset = offset,
.bytes = bytes,
.ret = NOT_DONE,
};
if (qemu_in_coroutine()) {
/* Fast-path if already in coroutine context */
bdrv_pdiscard_co_entry(&rwco);
} else {
co = qemu_coroutine_create(bdrv_pdiscard_co_entry, &rwco);
bdrv_coroutine_enter(child->bs, co);
BDRV_POLL_WHILE(child->bs, rwco.ret == NOT_DONE);
}
return rwco.ret;
return bdrv_run_co(child->bs, bdrv_pdiscard_co_entry, &rwco);
}
int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf)
@ -3325,8 +3291,8 @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
{
BdrvChild *c;
QLIST_FOREACH(c, &bs->parents, next_parent) {
if (c->role->resize) {
c->role->resize(c);
if (c->klass->resize) {
c->klass->resize(c);
}
}
}
@ -3339,7 +3305,8 @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
* 'offset' bytes in length.
*/
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp)
PreallocMode prealloc, BdrvRequestFlags flags,
Error **errp)
{
BlockDriverState *bs = child->bs;
BlockDriver *drv = bs->drv;
@ -3393,10 +3360,40 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
goto out;
}
/*
* If the image has a backing file that is large enough that it would
* provide data for the new area, we cannot leave it unallocated because
* then the backing file content would become visible. Instead, zero-fill
* the new area.
*
* Note that if the image has a backing file, but was opened without the
* backing file, taking care of keeping things consistent with that backing
* file is the user's responsibility.
*/
if (new_bytes && bs->backing) {
int64_t backing_len;
backing_len = bdrv_getlength(backing_bs(bs));
if (backing_len < 0) {
ret = backing_len;
error_setg_errno(errp, -ret, "Could not get backing file size");
goto out;
}
if (backing_len > old_size) {
flags |= BDRV_REQ_ZERO_WRITE;
}
}
if (drv->bdrv_co_truncate) {
ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, errp);
if (flags & ~bs->supported_truncate_flags) {
error_setg(errp, "Block driver does not support requested flags");
ret = -ENOTSUP;
goto out;
}
ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
} else if (bs->file && drv->is_filter) {
ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
} else {
error_setg(errp, "Image format driver does not support resize");
ret = -ENOTSUP;
@ -3429,39 +3426,29 @@ typedef struct TruncateCo {
int64_t offset;
bool exact;
PreallocMode prealloc;
BdrvRequestFlags flags;
Error **errp;
int ret;
} TruncateCo;
static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
static int coroutine_fn bdrv_truncate_co_entry(void *opaque)
{
TruncateCo *tco = opaque;
tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->exact,
tco->prealloc, tco->errp);
aio_wait_kick();
return bdrv_co_truncate(tco->child, tco->offset, tco->exact,
tco->prealloc, tco->flags, tco->errp);
}
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp)
PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
{
Coroutine *co;
TruncateCo tco = {
.child = child,
.offset = offset,
.exact = exact,
.prealloc = prealloc,
.flags = flags,
.errp = errp,
.ret = NOT_DONE,
};
if (qemu_in_coroutine()) {
/* Fast-path if already in coroutine context */
bdrv_truncate_co_entry(&tco);
} else {
co = qemu_coroutine_create(bdrv_truncate_co_entry, &tco);
bdrv_coroutine_enter(child->bs, co);
BDRV_POLL_WHILE(child->bs, tco.ret == NOT_DONE);
}
return tco.ret;
return bdrv_run_co(child->bs, bdrv_truncate_co_entry, &tco);
}

View File

@ -231,7 +231,7 @@ static int ioq_submit(LuringState *s)
trace_luring_io_uring_submit(s, ret);
/* Prevent infinite loop if submission is refused */
if (ret <= 0) {
if (ret == -EAGAIN) {
if (ret == -EAGAIN || ret == -EINTR) {
continue;
}
break;
@ -277,13 +277,10 @@ static void qemu_luring_completion_cb(void *opaque)
static bool qemu_luring_poll_cb(void *opaque)
{
LuringState *s = opaque;
struct io_uring_cqe *cqes;
if (io_uring_peek_cqe(&s->ring, &cqes) == 0) {
if (cqes) {
luring_process_completions_and_submit(s);
return true;
}
if (io_uring_cq_ready(&s->ring)) {
luring_process_completions_and_submit(s);
return true;
}
return false;

View File

@ -241,9 +241,11 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
iTask->status = status;
iTask->do_retry = 0;
iTask->err_code = 0;
iTask->task = task;
if (status != SCSI_STATUS_GOOD) {
iTask->err_code = -EIO;
if (iTask->retries++ < ISCSI_CMD_RETRIES) {
if (status == SCSI_STATUS_BUSY ||
status == SCSI_STATUS_TIMEOUT ||
@ -266,16 +268,16 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
timer_mod(&iTask->retry_timer,
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + retry_time);
iTask->do_retry = 1;
}
} else if (status == SCSI_STATUS_CHECK_CONDITION) {
int error = iscsi_translate_sense(&task->sense);
if (error == EAGAIN) {
error_report("iSCSI CheckCondition: %s",
iscsi_get_error(iscsi));
iTask->do_retry = 1;
} else {
iTask->err_code = -error;
iTask->err_str = g_strdup(iscsi_get_error(iscsi));
} else if (status == SCSI_STATUS_CHECK_CONDITION) {
int error = iscsi_translate_sense(&task->sense);
if (error == EAGAIN) {
error_report("iSCSI CheckCondition: %s",
iscsi_get_error(iscsi));
iTask->do_retry = 1;
} else {
iTask->err_code = -error;
iTask->err_str = g_strdup(iscsi_get_error(iscsi));
}
}
}
}
@ -1394,20 +1396,17 @@ static void iscsi_nop_timed_event(void *opaque)
{
IscsiLun *iscsilun = opaque;
qemu_mutex_lock(&iscsilun->mutex);
QEMU_LOCK_GUARD(&iscsilun->mutex);
if (iscsi_get_nops_in_flight(iscsilun->iscsi) >= MAX_NOP_FAILURES) {
error_report("iSCSI: NOP timeout. Reconnecting...");
iscsilun->request_timed_out = true;
} else if (iscsi_nop_out_async(iscsilun->iscsi, NULL, NULL, 0, NULL) != 0) {
error_report("iSCSI: failed to sent NOP-Out. Disabling NOP messages.");
goto out;
return;
}
timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
iscsi_set_events(iscsilun);
out:
qemu_mutex_unlock(&iscsilun->mutex);
}
static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
@ -1795,9 +1794,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
int i, ret = 0, timeout = 0, lun;
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
ret = -EINVAL;
goto out;
}
@ -2124,7 +2121,7 @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
bool exact, PreallocMode prealloc,
Error **errp)
BdrvRequestFlags flags, Error **errp)
{
IscsiLun *iscsilun = bs->opaque;
int64_t cur_length;
@ -2166,7 +2163,6 @@ static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
IscsiLun *iscsilun = bs->opaque;
bdi->unallocated_blocks_are_zero = iscsilun->lbprz;
bdi->cluster_size = iscsilun->cluster_size;
return 0;
}

View File

@ -872,6 +872,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
BlockDriverState *target_bs = blk_bs(s->target);
bool need_drain = true;
int64_t length;
int64_t target_length;
BlockDriverInfo bdi;
char backing_filename[2]; /* we only need 2 characters because we are only
checking for a NULL string */
@ -887,24 +888,26 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
goto immediate_exit;
}
target_length = blk_getlength(s->target);
if (target_length < 0) {
ret = target_length;
goto immediate_exit;
}
/* Active commit must resize the base image if its size differs from the
* active layer. */
if (s->base == blk_bs(s->target)) {
int64_t base_length;
base_length = blk_getlength(s->target);
if (base_length < 0) {
ret = base_length;
goto immediate_exit;
}
if (s->bdev_length > base_length) {
if (s->bdev_length > target_length) {
ret = blk_truncate(s->target, s->bdev_length, false,
PREALLOC_MODE_OFF, NULL);
PREALLOC_MODE_OFF, 0, NULL);
if (ret < 0) {
goto immediate_exit;
}
}
} else if (s->bdev_length != target_length) {
error_setg(errp, "Source and target image have different sizes");
ret = -EINVAL;
goto immediate_exit;
}
if (s->bdev_length == 0) {
@ -1489,7 +1492,7 @@ static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs)
}
static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c,
const BdrvChildRole *role,
BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
@ -1527,6 +1530,8 @@ static BlockDriver bdrv_mirror_top = {
.bdrv_co_block_status = bdrv_co_block_status_from_backing,
.bdrv_refresh_filename = bdrv_mirror_top_refresh_filename,
.bdrv_child_perm = bdrv_mirror_top_child_perm,
.is_filter = true,
};
static BlockJob *mirror_start_job(

View File

@ -1 +1,2 @@
common-obj-y += block-hmp-cmds.o
block-obj-y += bitmap-qmp-cmds.o

View File

@ -0,0 +1,321 @@
/*
* QEMU block dirty bitmap QMP commands
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* later. See the COPYING file in the top-level directory.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* 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 "block/block_int.h"
#include "qapi/qapi-commands-block.h"
#include "qapi/error.h"
/**
* block_dirty_bitmap_lookup:
* Return a dirty bitmap (if present), after validating
* the node reference and bitmap names.
*
* @node: The name of the BDS node to search for bitmaps
* @name: The name of the bitmap to search for
* @pbs: Output pointer for BDS lookup, if desired. Can be NULL.
* @errp: Output pointer for error information. Can be NULL.
*
* @return: A bitmap object on success, or NULL on failure.
*/
BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node,
const char *name,
BlockDriverState **pbs,
Error **errp)
{
BlockDriverState *bs;
BdrvDirtyBitmap *bitmap;
if (!node) {
error_setg(errp, "Node cannot be NULL");
return NULL;
}
if (!name) {
error_setg(errp, "Bitmap name cannot be NULL");
return NULL;
}
bs = bdrv_lookup_bs(node, node, NULL);
if (!bs) {
error_setg(errp, "Node '%s' not found", node);
return NULL;
}
bitmap = bdrv_find_dirty_bitmap(bs, name);
if (!bitmap) {
error_setg(errp, "Dirty bitmap '%s' not found", name);
return NULL;
}
if (pbs) {
*pbs = bs;
}
return bitmap;
}
void qmp_block_dirty_bitmap_add(const char *node, const char *name,
bool has_granularity, uint32_t granularity,
bool has_persistent, bool persistent,
bool has_disabled, bool disabled,
Error **errp)
{
BlockDriverState *bs;
BdrvDirtyBitmap *bitmap;
AioContext *aio_context;
if (!name || name[0] == '\0') {
error_setg(errp, "Bitmap name cannot be empty");
return;
}
bs = bdrv_lookup_bs(node, node, errp);
if (!bs) {
return;
}
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
if (has_granularity) {
if (granularity < 512 || !is_power_of_2(granularity)) {
error_setg(errp, "Granularity must be power of 2 "
"and at least 512");
goto out;
}
} else {
/* Default to cluster size, if available: */
granularity = bdrv_get_default_bitmap_granularity(bs);
}
if (!has_persistent) {
persistent = false;
}
if (!has_disabled) {
disabled = false;
}
if (persistent &&
!bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp))
{
goto out;
}
bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
if (bitmap == NULL) {
goto out;
}
if (disabled) {
bdrv_disable_dirty_bitmap(bitmap);
}
bdrv_dirty_bitmap_set_persistence(bitmap, persistent);
out:
aio_context_release(aio_context);
}
BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name,
bool release,
BlockDriverState **bitmap_bs,
Error **errp)
{
BlockDriverState *bs;
BdrvDirtyBitmap *bitmap;
AioContext *aio_context;
bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
if (!bitmap || !bs) {
return NULL;
}
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO,
errp)) {
aio_context_release(aio_context);
return NULL;
}
if (bdrv_dirty_bitmap_get_persistence(bitmap) &&
bdrv_remove_persistent_dirty_bitmap(bs, name, errp) < 0)
{
aio_context_release(aio_context);
return NULL;
}
if (release) {
bdrv_release_dirty_bitmap(bitmap);
}
if (bitmap_bs) {
*bitmap_bs = bs;
}
aio_context_release(aio_context);
return release ? NULL : bitmap;
}
void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
Error **errp)
{
block_dirty_bitmap_remove(node, name, true, NULL, errp);
}
/**
* Completely clear a bitmap, for the purposes of synchronizing a bitmap
* immediately after a full backup operation.
*/
void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
Error **errp)
{
BdrvDirtyBitmap *bitmap;
BlockDriverState *bs;
bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
if (!bitmap || !bs) {
return;
}
if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) {
return;
}
bdrv_clear_dirty_bitmap(bitmap, NULL);
}
void qmp_block_dirty_bitmap_enable(const char *node, const char *name,
Error **errp)
{
BlockDriverState *bs;
BdrvDirtyBitmap *bitmap;
bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
if (!bitmap) {
return;
}
if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
return;
}
bdrv_enable_dirty_bitmap(bitmap);
}
void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
Error **errp)
{
BlockDriverState *bs;
BdrvDirtyBitmap *bitmap;
bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
if (!bitmap) {
return;
}
if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
return;
}
bdrv_disable_dirty_bitmap(bitmap);
}
BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
BlockDirtyBitmapMergeSourceList *bms,
HBitmap **backup, Error **errp)
{
BlockDriverState *bs;
BdrvDirtyBitmap *dst, *src, *anon;
BlockDirtyBitmapMergeSourceList *lst;
Error *local_err = NULL;
dst = block_dirty_bitmap_lookup(node, target, &bs, errp);
if (!dst) {
return NULL;
}
anon = bdrv_create_dirty_bitmap(bs, bdrv_dirty_bitmap_granularity(dst),
NULL, errp);
if (!anon) {
return NULL;
}
for (lst = bms; lst; lst = lst->next) {
switch (lst->value->type) {
const char *name, *node;
case QTYPE_QSTRING:
name = lst->value->u.local;
src = bdrv_find_dirty_bitmap(bs, name);
if (!src) {
error_setg(errp, "Dirty bitmap '%s' not found", name);
dst = NULL;
goto out;
}
break;
case QTYPE_QDICT:
node = lst->value->u.external.node;
name = lst->value->u.external.name;
src = block_dirty_bitmap_lookup(node, name, NULL, errp);
if (!src) {
dst = NULL;
goto out;
}
break;
default:
abort();
}
bdrv_merge_dirty_bitmap(anon, src, NULL, &local_err);
if (local_err) {
error_propagate(errp, local_err);
dst = NULL;
goto out;
}
}
/* Merge into dst; dst is unchanged on failure. */
bdrv_merge_dirty_bitmap(dst, anon, backup, errp);
out:
bdrv_release_dirty_bitmap(anon);
return dst;
}
void qmp_block_dirty_bitmap_merge(const char *node, const char *target,
BlockDirtyBitmapMergeSourceList *bitmaps,
Error **errp)
{
block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp);
}

View File

@ -93,7 +93,10 @@ typedef struct BDRVNBDState {
char *x_dirty_bitmap;
} BDRVNBDState;
static int nbd_client_connect(BlockDriverState *bs, Error **errp);
static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr,
Error **errp);
static int nbd_client_handshake(BlockDriverState *bs, QIOChannelSocket *sioc,
Error **errp);
static void nbd_clear_bdrvstate(BDRVNBDState *s)
{
@ -206,11 +209,15 @@ static void nbd_teardown_connection(BlockDriverState *bs)
{
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
if (s->state == NBD_CLIENT_CONNECTED) {
if (s->ioc) {
/* finish any pending coroutines */
assert(s->ioc);
qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
} else if (s->sioc) {
/* abort negotiation */
qio_channel_shutdown(QIO_CHANNEL(s->sioc), QIO_CHANNEL_SHUTDOWN_BOTH,
NULL);
}
s->state = NBD_CLIENT_QUIT;
if (s->connection_co) {
if (s->connection_co_sleep_ns_state) {
@ -241,7 +248,9 @@ static bool nbd_client_connecting_wait(BDRVNBDState *s)
static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s)
{
int ret;
Error *local_err = NULL;
QIOChannelSocket *sioc;
if (!nbd_client_connecting(s)) {
return;
@ -280,19 +289,39 @@ static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s)
s->ioc = NULL;
}
s->connect_status = nbd_client_connect(s->bs, &local_err);
sioc = nbd_establish_connection(s->saddr, &local_err);
if (!sioc) {
ret = -ECONNREFUSED;
goto out;
}
bdrv_dec_in_flight(s->bs);
ret = nbd_client_handshake(s->bs, sioc, &local_err);
if (s->drained) {
s->wait_drained_end = true;
while (s->drained) {
/*
* We may be entered once from nbd_client_attach_aio_context_bh
* and then from nbd_client_co_drain_end. So here is a loop.
*/
qemu_coroutine_yield();
}
}
bdrv_inc_in_flight(s->bs);
out:
s->connect_status = ret;
error_free(s->connect_err);
s->connect_err = NULL;
error_propagate(&s->connect_err, local_err);
if (s->connect_status < 0) {
/* failed attempt */
return;
if (ret >= 0) {
/* successfully connected */
s->state = NBD_CLIENT_CONNECTED;
qemu_co_queue_restart_all(&s->free_sema);
}
/* successfully connected */
s->state = NBD_CLIENT_CONNECTED;
qemu_co_queue_restart_all(&s->free_sema);
}
static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s)
@ -312,8 +341,6 @@ static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s)
qemu_co_queue_restart_all(&s->free_sema);
}
qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, timeout,
&s->connection_co_sleep_ns_state);
if (s->drained) {
bdrv_dec_in_flight(s->bs);
s->wait_drained_end = true;
@ -325,9 +352,12 @@ static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s)
qemu_coroutine_yield();
}
bdrv_inc_in_flight(s->bs);
}
if (timeout < max_timeout) {
timeout *= 2;
} else {
qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, timeout,
&s->connection_co_sleep_ns_state);
if (timeout < max_timeout) {
timeout *= 2;
}
}
nbd_reconnect_attempt(s);
@ -1320,9 +1350,7 @@ static int coroutine_fn nbd_client_co_block_status(
NBDRequest request = {
.type = NBD_CMD_BLOCK_STATUS,
.from = offset,
.len = MIN(MIN_NON_ZERO(QEMU_ALIGN_DOWN(INT_MAX,
bs->bl.request_alignment),
s->info.max_block),
.len = MIN(QEMU_ALIGN_DOWN(INT_MAX, bs->bl.request_alignment),
MIN(bytes, s->info.size - offset)),
.flags = NBD_CMD_FLAG_REQ_ONE,
};
@ -1410,16 +1438,15 @@ static void nbd_client_close(BlockDriverState *bs)
static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr,
Error **errp)
{
ERRP_GUARD();
QIOChannelSocket *sioc;
Error *local_err = NULL;
sioc = qio_channel_socket_new();
qio_channel_set_name(QIO_CHANNEL(sioc), "nbd-client");
qio_channel_socket_connect_sync(sioc, saddr, &local_err);
if (local_err) {
qio_channel_socket_connect_sync(sioc, saddr, errp);
if (*errp) {
object_unref(OBJECT(sioc));
error_propagate(errp, local_err);
return NULL;
}
@ -1428,24 +1455,18 @@ static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr,
return sioc;
}
static int nbd_client_connect(BlockDriverState *bs, Error **errp)
/* nbd_client_handshake takes ownership on sioc. On failure it is unref'ed. */
static int nbd_client_handshake(BlockDriverState *bs, QIOChannelSocket *sioc,
Error **errp)
{
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
AioContext *aio_context = bdrv_get_aio_context(bs);
int ret;
/*
* establish TCP connection, return error if it fails
* TODO: Configurable retry-until-timeout behaviour.
*/
QIOChannelSocket *sioc = nbd_establish_connection(s->saddr, errp);
trace_nbd_client_handshake(s->export);
if (!sioc) {
return -ECONNREFUSED;
}
s->sioc = sioc;
/* NBD handshake */
trace_nbd_client_connect(s->export);
qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL);
qio_channel_attach_aio_context(QIO_CHANNEL(sioc), aio_context);
@ -1460,6 +1481,7 @@ static int nbd_client_connect(BlockDriverState *bs, Error **errp)
g_free(s->info.name);
if (ret < 0) {
object_unref(OBJECT(sioc));
s->sioc = NULL;
return ret;
}
if (s->x_dirty_bitmap && !s->info.base_allocation) {
@ -1485,14 +1507,12 @@ static int nbd_client_connect(BlockDriverState *bs, Error **errp)
}
}
s->sioc = sioc;
if (!s->ioc) {
s->ioc = QIO_CHANNEL(sioc);
object_ref(OBJECT(s->ioc));
}
trace_nbd_client_connect_success(s->export);
trace_nbd_client_handshake_success(s->export);
return 0;
@ -1507,6 +1527,7 @@ static int nbd_client_connect(BlockDriverState *bs, Error **errp)
nbd_send_request(s->ioc ?: QIO_CHANNEL(sioc), &request);
object_unref(OBJECT(sioc));
s->sioc = NULL;
return ret;
}
@ -1728,7 +1749,6 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
SocketAddress *saddr = NULL;
QDict *addr = NULL;
Visitor *iv = NULL;
Error *local_err = NULL;
qdict_extract_subqdict(options, &addr, "server.");
if (!qdict_size(addr)) {
@ -1741,9 +1761,7 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
goto done;
}
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!visit_type_SocketAddress(iv, NULL, &saddr, errp)) {
goto done;
}
@ -1838,13 +1856,10 @@ static int nbd_process_options(BlockDriverState *bs, QDict *options,
{
BDRVNBDState *s = bs->opaque;
QemuOpts *opts;
Error *local_err = NULL;
int ret = -EINVAL;
opts = qemu_opts_create(&nbd_runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
goto error;
}
@ -1903,6 +1918,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
{
int ret;
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
QIOChannelSocket *sioc;
ret = nbd_process_options(bs, options, errp);
if (ret < 0) {
@ -1913,7 +1929,16 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
qemu_co_mutex_init(&s->send_mutex);
qemu_co_queue_init(&s->free_sema);
ret = nbd_client_connect(bs, errp);
/*
* establish TCP connection, return error if it fails
* TODO: Configurable retry-until-timeout behaviour.
*/
sioc = nbd_establish_connection(s->saddr, errp);
if (!sioc) {
return -ECONNREFUSED;
}
ret = nbd_client_handshake(bs, sioc, errp);
if (ret < 0) {
nbd_clear_bdrvstate(s);
return ret;
@ -1957,7 +1982,7 @@ static void nbd_refresh_limits(BlockDriverState *bs, Error **errp)
}
bs->bl.request_alignment = min;
bs->bl.max_pdiscard = max;
bs->bl.max_pdiscard = QEMU_ALIGN_DOWN(INT_MAX, min);
bs->bl.max_pwrite_zeroes = max;
bs->bl.max_transfer = max;
@ -1975,6 +2000,33 @@ static void nbd_close(BlockDriverState *bs)
nbd_clear_bdrvstate(s);
}
/*
* NBD cannot truncate, but if the caller asks to truncate to the same size, or
* to a smaller size with exact=false, there is no reason to fail the
* operation.
*
* Preallocation mode is ignored since it does not seems useful to fail when
* we never change anything.
*/
static int coroutine_fn nbd_co_truncate(BlockDriverState *bs, int64_t offset,
bool exact, PreallocMode prealloc,
BdrvRequestFlags flags, Error **errp)
{
BDRVNBDState *s = bs->opaque;
if (offset != s->info.size && exact) {
error_setg(errp, "Cannot resize NBD nodes");
return -ENOTSUP;
}
if (offset > s->info.size) {
error_setg(errp, "Cannot grow NBD nodes");
return -EINVAL;
}
return 0;
}
static int64_t nbd_getlength(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
@ -1986,6 +2038,7 @@ static void nbd_refresh_filename(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
const char *host = NULL, *port = NULL, *path = NULL;
size_t len = 0;
if (s->saddr->type == SOCKET_ADDRESS_TYPE_INET) {
const InetSocketAddress *inet = &s->saddr->u.inet;
@ -1998,17 +2051,21 @@ static void nbd_refresh_filename(BlockDriverState *bs)
} /* else can't represent as pseudo-filename */
if (path && s->export) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd+unix:///%s?socket=%s", s->export, path);
len = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd+unix:///%s?socket=%s", s->export, path);
} else if (path && !s->export) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd+unix://?socket=%s", path);
len = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd+unix://?socket=%s", path);
} else if (host && s->export) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd://%s:%s/%s", host, port, s->export);
len = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd://%s:%s/%s", host, port, s->export);
} else if (host && !s->export) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd://%s:%s", host, port);
len = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd://%s:%s", host, port);
}
if (len >= sizeof(bs->exact_filename)) {
/* Name is too long to represent exactly, so leave it empty. */
bs->exact_filename[0] = '\0';
}
}
@ -2049,6 +2106,7 @@ static BlockDriver bdrv_nbd = {
.bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_pdiscard = nbd_client_co_pdiscard,
.bdrv_refresh_limits = nbd_refresh_limits,
.bdrv_co_truncate = nbd_co_truncate,
.bdrv_getlength = nbd_getlength,
.bdrv_detach_aio_context = nbd_client_detach_aio_context,
.bdrv_attach_aio_context = nbd_client_attach_aio_context,
@ -2076,6 +2134,7 @@ static BlockDriver bdrv_nbd_tcp = {
.bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_pdiscard = nbd_client_co_pdiscard,
.bdrv_refresh_limits = nbd_refresh_limits,
.bdrv_co_truncate = nbd_co_truncate,
.bdrv_getlength = nbd_getlength,
.bdrv_detach_aio_context = nbd_client_detach_aio_context,
.bdrv_attach_aio_context = nbd_client_attach_aio_context,
@ -2103,6 +2162,7 @@ static BlockDriver bdrv_nbd_unix = {
.bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_pdiscard = nbd_client_co_pdiscard,
.bdrv_refresh_limits = nbd_refresh_limits,
.bdrv_co_truncate = nbd_co_truncate,
.bdrv_getlength = nbd_getlength,
.bdrv_detach_aio_context = nbd_client_detach_aio_context,
.bdrv_attach_aio_context = nbd_client_attach_aio_context,

View File

@ -273,15 +273,14 @@ static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset,
nfs_co_init_task(bs, &task);
task.iov = iov;
qemu_mutex_lock(&client->mutex);
if (nfs_pread_async(client->context, client->fh,
offset, bytes, nfs_co_generic_cb, &task) != 0) {
qemu_mutex_unlock(&client->mutex);
return -ENOMEM;
}
WITH_QEMU_LOCK_GUARD(&client->mutex) {
if (nfs_pread_async(client->context, client->fh,
offset, bytes, nfs_co_generic_cb, &task) != 0) {
return -ENOMEM;
}
nfs_set_events(client);
qemu_mutex_unlock(&client->mutex);
nfs_set_events(client);
}
while (!task.complete) {
qemu_coroutine_yield();
}
@ -320,19 +319,18 @@ static int coroutine_fn nfs_co_pwritev(BlockDriverState *bs, uint64_t offset,
buf = iov->iov[0].iov_base;
}
qemu_mutex_lock(&client->mutex);
if (nfs_pwrite_async(client->context, client->fh,
offset, bytes, buf,
nfs_co_generic_cb, &task) != 0) {
qemu_mutex_unlock(&client->mutex);
if (my_buffer) {
g_free(buf);
WITH_QEMU_LOCK_GUARD(&client->mutex) {
if (nfs_pwrite_async(client->context, client->fh,
offset, bytes, buf,
nfs_co_generic_cb, &task) != 0) {
if (my_buffer) {
g_free(buf);
}
return -ENOMEM;
}
return -ENOMEM;
}
nfs_set_events(client);
qemu_mutex_unlock(&client->mutex);
nfs_set_events(client);
}
while (!task.complete) {
qemu_coroutine_yield();
}
@ -355,15 +353,14 @@ static int coroutine_fn nfs_co_flush(BlockDriverState *bs)
nfs_co_init_task(bs, &task);
qemu_mutex_lock(&client->mutex);
if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb,
&task) != 0) {
qemu_mutex_unlock(&client->mutex);
return -ENOMEM;
}
WITH_QEMU_LOCK_GUARD(&client->mutex) {
if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb,
&task) != 0) {
return -ENOMEM;
}
nfs_set_events(client);
qemu_mutex_unlock(&client->mutex);
nfs_set_events(client);
}
while (!task.complete) {
qemu_coroutine_yield();
}
@ -566,18 +563,15 @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options,
BlockdevOptionsNfs *opts = NULL;
Visitor *v;
const QDictEntry *e;
Error *local_err = NULL;
v = qobject_input_visitor_new_flat_confused(options, errp);
if (!v) {
return NULL;
}
visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err);
visit_type_BlockdevOptionsNfs(v, NULL, &opts, errp);
visit_free(v);
if (local_err) {
error_propagate(errp, local_err);
if (!opts) {
return NULL;
}
@ -623,8 +617,10 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
}
bs->total_sectors = ret;
ret = 0;
return ret;
if (client->has_zero_init) {
bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
}
return 0;
}
static QemuOptsList nfs_create_opts = {
@ -755,7 +751,8 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
static int coroutine_fn
nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp)
PreallocMode prealloc, BdrvRequestFlags flags,
Error **errp)
{
NFSClient *client = bs->opaque;
int ret;
@ -872,7 +869,6 @@ static BlockDriver bdrv_nfs = {
.create_opts = &nfs_create_opts,
.bdrv_has_zero_init = nfs_has_zero_init,
.bdrv_has_zero_init_truncate = nfs_has_zero_init,
.bdrv_get_allocated_file_size = nfs_get_allocated_file_size,
.bdrv_co_truncate = nfs_file_co_truncate,

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