Compare commits
72 Commits
6.2.0-inst
...
wcet_syste
Author | SHA1 | Date | |
---|---|---|---|
85e0a3f630 | |||
ab54074925 | |||
f5b92c8907 | |||
f438967783 | |||
3493dfa219 | |||
a5a49c3292 | |||
8a379ba198 | |||
6ffc2bbe4f | |||
0cf10fb0ff | |||
404cb91655 | |||
ff823f26ff | |||
80af255c2e | |||
e62b0072ea | |||
6ec50ee9c3 | |||
88a0358a4e | |||
78dac2f524 | |||
9caef2e60f | |||
b781a3ebce | |||
5a1cf4d873 | |||
c1dba1b39d | |||
![]() |
54e1f5be86 | ||
![]() |
fddd169de5 | ||
![]() |
711bd602cc | ||
![]() |
e88636b4d4 | ||
![]() |
34833f361b | ||
![]() |
43583f0c07 | ||
![]() |
1ce084af08 | ||
![]() |
fec12fc888 | ||
![]() |
ef0cf1887e | ||
![]() |
71ba2adfeb | ||
![]() |
7629818574 | ||
![]() |
4658dfcbc0 | ||
![]() |
2b2eb343a0 | ||
![]() |
932333c5f0 | ||
![]() |
8c2d5911de | ||
![]() |
08e46e6d92 | ||
![]() |
df1c9c3039 | ||
![]() |
7204b8f3c6 | ||
![]() |
36c651c226 | ||
![]() |
fceaefb43f | ||
![]() |
7d71e6bfb0 | ||
![]() |
c2c7f108b8 | ||
![]() |
3488bb205d | ||
![]() |
cddfaf96ab | ||
![]() |
43a457841f | ||
![]() |
ebf660beb1 | ||
![]() |
bbbdedb386 | ||
![]() |
8319de607f | ||
![]() |
a759dc19ec | ||
![]() |
24101e36f1 | ||
![]() |
a43e057bd6 | ||
![]() |
3aa2c2cd67 | ||
![]() |
9e80a430ed | ||
![]() |
c66f5dfc12 | ||
![]() |
5cf977a2a1 | ||
![]() |
36cfd11a86 | ||
![]() |
246ccfbf44 | ||
![]() |
3ee93e456d | ||
![]() |
ec08035102 | ||
![]() |
f97853c8cb | ||
![]() |
abeee2a470 | ||
![]() |
ff6d391e10 | ||
![]() |
b19de1137b | ||
![]() |
3c6e5df1f6 | ||
![]() |
695c25e167 | ||
![]() |
23ba9f170f | ||
![]() |
f0dee5a40d | ||
![]() |
7637373b23 | ||
![]() |
4c34ef3d34 | ||
![]() |
9e41f16fca | ||
![]() |
3054f772de | ||
![]() |
aa77e375a5 |
34
.github/lockdown.yml
vendored
Normal file
34
.github/lockdown.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
# Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown
|
||||
|
||||
# Close issues and pull requests
|
||||
close: true
|
||||
|
||||
# Lock issues and pull requests
|
||||
lock: true
|
||||
|
||||
issues:
|
||||
comment: |
|
||||
Thank you for your interest in the QEMU project.
|
||||
|
||||
This repository is a read-only mirror of the project's repostories hosted
|
||||
at https://gitlab.com/qemu-project/qemu.git.
|
||||
The project does not process issues filed on GitHub.
|
||||
|
||||
The project issues are tracked on GitLab:
|
||||
https://gitlab.com/qemu-project/qemu/-/issues
|
||||
|
||||
QEMU welcomes bug report contributions. You can file new ones on:
|
||||
https://gitlab.com/qemu-project/qemu/-/issues/new
|
||||
|
||||
pulls:
|
||||
comment: |
|
||||
Thank you for your interest in the QEMU project.
|
||||
|
||||
This repository is a read-only mirror of the project's repostories hosted
|
||||
on https://gitlab.com/qemu-project/qemu.git.
|
||||
The project does not process merge requests filed on GitHub.
|
||||
|
||||
QEMU welcomes contributions of code (either fixing bugs or adding new
|
||||
functionality). However, we get a lot of patches, and so we have some
|
||||
guidelines about contributing on the project website:
|
||||
https://www.qemu.org/contribute/
|
30
.github/workflows/lockdown.yml
vendored
30
.github/workflows/lockdown.yml
vendored
@ -1,30 +0,0 @@
|
||||
# Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown
|
||||
|
||||
name: 'Repo Lockdown'
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: opened
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/repo-lockdown@v2
|
||||
with:
|
||||
pull-comment: |
|
||||
Thank you for your interest in the QEMU project.
|
||||
|
||||
This repository is a read-only mirror of the project's repostories hosted
|
||||
on https://gitlab.com/qemu-project/qemu.git.
|
||||
The project does not process merge requests filed on GitHub.
|
||||
|
||||
QEMU welcomes contributions of code (either fixing bugs or adding new
|
||||
functionality). However, we get a lot of patches, and so we have some
|
||||
guidelines about contributing on the project website:
|
||||
https://www.qemu.org/contribute/
|
||||
lock-pull: true
|
||||
close-pull: true
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -15,6 +15,6 @@ GTAGS
|
||||
*.depend_raw
|
||||
*.swp
|
||||
*.patch
|
||||
.ccls*
|
||||
.direnv
|
||||
.vscode
|
||||
.cache
|
||||
*.axf
|
||||
*.qcow2
|
@ -37,7 +37,7 @@
|
||||
# Avoid recompiling by hiding ninja with NINJA=":"
|
||||
- make NINJA=":" $MAKE_CHECK_ARGS
|
||||
|
||||
.avocado_test_job_template:
|
||||
.acceptance_test_job_template:
|
||||
extends: .native_test_job_template
|
||||
cache:
|
||||
key: "${CI_JOB_NAME}-cache"
|
||||
|
@ -26,14 +26,14 @@ check-system-alpine:
|
||||
IMAGE: alpine
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-system-alpine:
|
||||
extends: .avocado_test_job_template
|
||||
acceptance-system-alpine:
|
||||
extends: .acceptance_test_job_template
|
||||
needs:
|
||||
- job: build-system-alpine
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: alpine
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
|
||||
build-system-ubuntu:
|
||||
extends: .native_build_job_template
|
||||
@ -59,14 +59,14 @@ check-system-ubuntu:
|
||||
IMAGE: ubuntu2004
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-system-ubuntu:
|
||||
extends: .avocado_test_job_template
|
||||
acceptance-system-ubuntu:
|
||||
extends: .acceptance_test_job_template
|
||||
needs:
|
||||
- job: build-system-ubuntu
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
|
||||
build-system-debian:
|
||||
extends: .native_build_job_template
|
||||
@ -74,6 +74,7 @@ build-system-debian:
|
||||
job: amd64-debian-container
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
CONFIGURE_ARGS: --enable-fdt=system
|
||||
TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu
|
||||
riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
@ -91,14 +92,14 @@ check-system-debian:
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-system-debian:
|
||||
extends: .avocado_test_job_template
|
||||
acceptance-system-debian:
|
||||
extends: .acceptance_test_job_template
|
||||
needs:
|
||||
- job: build-system-debian
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
|
||||
build-system-fedora:
|
||||
extends: .native_build_job_template
|
||||
@ -125,14 +126,14 @@ check-system-fedora:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-system-fedora:
|
||||
extends: .avocado_test_job_template
|
||||
acceptance-system-fedora:
|
||||
extends: .acceptance_test_job_template
|
||||
needs:
|
||||
- job: build-system-fedora
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
|
||||
build-system-centos:
|
||||
extends: .native_build_job_template
|
||||
@ -159,14 +160,14 @@ check-system-centos:
|
||||
IMAGE: centos8
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-system-centos:
|
||||
extends: .avocado_test_job_template
|
||||
acceptance-system-centos:
|
||||
extends: .acceptance_test_job_template
|
||||
needs:
|
||||
- job: build-system-centos
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
|
||||
build-system-opensuse:
|
||||
extends: .native_build_job_template
|
||||
@ -191,16 +192,95 @@ check-system-opensuse:
|
||||
IMAGE: opensuse-leap
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-system-opensuse:
|
||||
extends: .avocado_test_job_template
|
||||
acceptance-system-opensuse:
|
||||
extends: .acceptance_test_job_template
|
||||
needs:
|
||||
- job: build-system-opensuse
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: opensuse-leap
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
|
||||
|
||||
build-disabled:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS:
|
||||
--disable-attr
|
||||
--disable-auth-pam
|
||||
--disable-avx2
|
||||
--disable-bochs
|
||||
--disable-brlapi
|
||||
--disable-bzip2
|
||||
--disable-cap-ng
|
||||
--disable-capstone
|
||||
--disable-cloop
|
||||
--disable-coroutine-pool
|
||||
--disable-curl
|
||||
--disable-curses
|
||||
--disable-dmg
|
||||
--disable-docs
|
||||
--disable-gcrypt
|
||||
--disable-glusterfs
|
||||
--disable-gnutls
|
||||
--disable-gtk
|
||||
--disable-guest-agent
|
||||
--disable-iconv
|
||||
--disable-keyring
|
||||
--disable-kvm
|
||||
--disable-libiscsi
|
||||
--disable-libpmem
|
||||
--disable-libssh
|
||||
--disable-libudev
|
||||
--disable-libusb
|
||||
--disable-libxml2
|
||||
--disable-linux-aio
|
||||
--disable-live-block-migration
|
||||
--disable-lzo
|
||||
--disable-malloc-trim
|
||||
--disable-mpath
|
||||
--disable-nettle
|
||||
--disable-numa
|
||||
--disable-opengl
|
||||
--disable-parallels
|
||||
--disable-pie
|
||||
--disable-qcow1
|
||||
--disable-qed
|
||||
--disable-qom-cast-debug
|
||||
--disable-rbd
|
||||
--disable-rdma
|
||||
--disable-replication
|
||||
--disable-sdl
|
||||
--disable-seccomp
|
||||
--disable-slirp
|
||||
--disable-smartcard
|
||||
--disable-snappy
|
||||
--disable-sparse
|
||||
--disable-spice
|
||||
--disable-strip
|
||||
--disable-tpm
|
||||
--disable-usb-redir
|
||||
--disable-vdi
|
||||
--disable-vhost-crypto
|
||||
--disable-vhost-net
|
||||
--disable-vhost-scsi
|
||||
--disable-vhost-kernel
|
||||
--disable-vhost-user
|
||||
--disable-vhost-vdpa
|
||||
--disable-vhost-vsock
|
||||
--disable-virglrenderer
|
||||
--disable-vnc
|
||||
--disable-vte
|
||||
--disable-vvfat
|
||||
--disable-xen
|
||||
--disable-zstd
|
||||
TARGETS: arm-softmmu i386-softmmu ppc64-softmmu mips64-softmmu
|
||||
s390x-softmmu i386-linux-user
|
||||
MAKE_CHECK_ARGS: check-qtest SPEED=slow
|
||||
|
||||
# This jobs explicitly disable TCG (--disable-tcg), KVM is detected by
|
||||
# the configure script. The container doesn't contain Xen headers so
|
||||
# Xen accelerator is not detected / selected. As result it build the
|
||||
@ -225,11 +305,11 @@ build-tcg-disabled:
|
||||
- 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 208 221 226 227 236 253 277 image-fleecing
|
||||
170 171 183 184 192 194 208 221 222 226 227 236 253 277
|
||||
- ./check -qcow2 028 051 056 057 058 065 068 082 085 091 095 096 102 122
|
||||
124 132 139 142 144 145 151 152 155 157 165 194 196 200 202
|
||||
208 209 216 218 227 234 246 247 248 250 254 255 257 258
|
||||
260 261 262 263 264 270 272 273 277 279 image-fleecing
|
||||
208 209 216 218 222 227 234 246 247 248 250 254 255 257 258
|
||||
260 261 262 263 264 270 272 273 277 279
|
||||
|
||||
build-user:
|
||||
extends: .native_build_job_template
|
||||
@ -317,7 +397,7 @@ clang-user:
|
||||
# This can be accomplished by using -enable-slirp=git, which avoids the use of
|
||||
# a system-wide version of the library
|
||||
#
|
||||
# Split in three sets of build/check/avocado to limit the execution time of each
|
||||
# Split in three sets of build/check/acceptance to limit the execution time of each
|
||||
# job
|
||||
build-cfi-aarch64:
|
||||
extends: .native_build_job_template
|
||||
@ -352,14 +432,14 @@ check-cfi-aarch64:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-cfi-aarch64:
|
||||
extends: .avocado_test_job_template
|
||||
acceptance-cfi-aarch64:
|
||||
extends: .acceptance_test_job_template
|
||||
needs:
|
||||
- job: build-cfi-aarch64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
|
||||
build-cfi-ppc64-s390x:
|
||||
extends: .native_build_job_template
|
||||
@ -394,14 +474,14 @@ check-cfi-ppc64-s390x:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-cfi-ppc64-s390x:
|
||||
extends: .avocado_test_job_template
|
||||
acceptance-cfi-ppc64-s390x:
|
||||
extends: .acceptance_test_job_template
|
||||
needs:
|
||||
- job: build-cfi-ppc64-s390x
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
|
||||
build-cfi-x86_64:
|
||||
extends: .native_build_job_template
|
||||
@ -430,14 +510,14 @@ check-cfi-x86_64:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-cfi-x86_64:
|
||||
extends: .avocado_test_job_template
|
||||
acceptance-cfi-x86_64:
|
||||
extends: .acceptance_test_job_template
|
||||
needs:
|
||||
- job: build-cfi-x86_64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
|
||||
tsan-build:
|
||||
extends: .native_build_job_template
|
||||
@ -569,25 +649,20 @@ build-without-default-devices:
|
||||
build-without-default-features:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
job: amd64-debian-container
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS:
|
||||
--without-default-features
|
||||
--disable-capstone
|
||||
--disable-pie
|
||||
--disable-qom-cast-debug
|
||||
--disable-slirp
|
||||
--disable-strip
|
||||
TARGETS: avr-softmmu i386-softmmu mips64-softmmu s390x-softmmu sh4-softmmu
|
||||
sparc64-softmmu hexagon-linux-user i386-linux-user s390x-linux-user
|
||||
MAKE_CHECK_ARGS: check-unit check-qtest SPEED=slow
|
||||
IMAGE: debian-amd64
|
||||
CONFIGURE_ARGS: --without-default-features --disable-user
|
||||
--target-list-exclude=arm-softmmu,i386-softmmu,mipsel-softmmu,mips64-softmmu,ppc-softmmu
|
||||
MAKE_CHECK_ARGS: check-unit
|
||||
|
||||
build-libvhost-user:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/fedora:latest
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
before_script:
|
||||
- dnf install -y meson ninja-build
|
||||
script:
|
||||
- mkdir subprojects/libvhost-user/build
|
||||
- cd subprojects/libvhost-user/build
|
||||
|
@ -14,7 +14,6 @@
|
||||
stage: build
|
||||
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master
|
||||
needs: []
|
||||
timeout: 80m
|
||||
allow_failure: true
|
||||
script:
|
||||
- source .gitlab-ci.d/cirrus/$NAME.vars
|
||||
@ -36,14 +35,11 @@
|
||||
-e "s|[@]PIP3@|$PIP3|g"
|
||||
-e "s|[@]PYPI_PKGS@|$PYPI_PKGS|g"
|
||||
-e "s|[@]CONFIGURE_ARGS@|$CONFIGURE_ARGS|g"
|
||||
-e "s|[@]TEST_TARGETS@|$TEST_TARGETS|g"
|
||||
-e "s|[@]TEST_TARGETSS@|$TEST_TARGETSS|g"
|
||||
<.gitlab-ci.d/cirrus/build.yml >.gitlab-ci.d/cirrus/$NAME.yml
|
||||
- cat .gitlab-ci.d/cirrus/$NAME.yml
|
||||
- cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml
|
||||
rules:
|
||||
# Allow on 'staging' branch and 'stable-X.Y-staging' branches only
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH !~ /staging/'
|
||||
when: never
|
||||
- if: "$CIRRUS_GITHUB_REPO && $CIRRUS_API_TOKEN"
|
||||
|
||||
x64-freebsd-12-build:
|
||||
|
@ -13,7 +13,6 @@ env:
|
||||
PYTHON: "@PYTHON@"
|
||||
MAKE: "@MAKE@"
|
||||
CONFIGURE_ARGS: "@CONFIGURE_ARGS@"
|
||||
TEST_TARGETS: "@TEST_TARGETS@"
|
||||
|
||||
build_task:
|
||||
install_script:
|
||||
|
@ -134,8 +134,7 @@ ppc64el-debian-cross-container:
|
||||
riscv64-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
# as we are currently based on 'sid/unstable' we may break so...
|
||||
allow_failure: true
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-riscv64-cross
|
||||
|
||||
|
@ -124,25 +124,6 @@ cross-ppc64el-user:
|
||||
variables:
|
||||
IMAGE: debian-ppc64el-cross
|
||||
|
||||
# The riscv64 cross-builds currently use a 'sid' container to get
|
||||
# compilers and libraries. Until something more stable is found we
|
||||
# allow_failure so as not to block CI.
|
||||
cross-riscv64-system:
|
||||
extends: .cross_system_build_job
|
||||
allow_failure: true
|
||||
needs:
|
||||
job: riscv64-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-riscv64-cross
|
||||
|
||||
cross-riscv64-user:
|
||||
extends: .cross_user_build_job
|
||||
allow_failure: true
|
||||
needs:
|
||||
job: riscv64-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-riscv64-cross
|
||||
|
||||
cross-s390x-system:
|
||||
extends: .cross_system_build_job
|
||||
needs:
|
||||
|
@ -13,7 +13,226 @@
|
||||
variables:
|
||||
GIT_STRATEGY: clone
|
||||
|
||||
include:
|
||||
- local: '/.gitlab-ci.d/custom-runners/ubuntu-18.04-s390x.yml'
|
||||
- local: '/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml'
|
||||
- local: '/.gitlab-ci.d/custom-runners/centos-stream-8-x86_64.yml'
|
||||
# All ubuntu-18.04 jobs should run successfully in an environment
|
||||
# setup by the scripts/ci/setup/build-environment.yml task
|
||||
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
|
||||
ubuntu-18.04-s390x-all-linux-static:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
script:
|
||||
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
|
||||
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
- make --output-sync -j`nproc` check-tcg V=1
|
||||
|
||||
ubuntu-18.04-s390x-all:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-18.04-s390x-alldbg:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-debug --disable-libssh
|
||||
- make clean
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-18.04-s390x-clang:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-18.04-s390x-tci:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --enable-tcg-interpreter
|
||||
- make --output-sync -j`nproc`
|
||||
|
||||
ubuntu-18.04-s390x-notcg:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --disable-tcg
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
# All ubuntu-20.04 jobs should run successfully in an environment
|
||||
# setup by the scripts/ci/setup/qemu/build-environment.yml task
|
||||
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
|
||||
ubuntu-20.04-aarch64-all-linux-static:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
script:
|
||||
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
|
||||
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
- make --output-sync -j`nproc` check-tcg V=1
|
||||
|
||||
ubuntu-20.04-aarch64-all:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-20.04-aarch64-alldbg:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-debug --disable-libssh
|
||||
- make clean
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-20.04-aarch64-clang:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-20.04-aarch64-tci:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --enable-tcg-interpreter
|
||||
- make --output-sync -j`nproc`
|
||||
|
||||
ubuntu-20.04-aarch64-notcg:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --disable-tcg
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
@ -1,28 +0,0 @@
|
||||
centos-stream-8-x86_64:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- centos_stream_8
|
||||
- x86_64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$CENTOS_STREAM_8_x86_64_RUNNER_AVAILABLE"
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||
when: on_failure
|
||||
expire_in: 7 days
|
||||
paths:
|
||||
- build/tests/results/latest/results.xml
|
||||
- build/tests/results/latest/test-results
|
||||
reports:
|
||||
junit: build/tests/results/latest/results.xml
|
||||
before_script:
|
||||
- JOBS=$(expr $(nproc) + 1)
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../scripts/ci/org.centos/stream/8/x86_64/configure
|
||||
- make -j"$JOBS"
|
||||
- make NINJA=":" check
|
||||
- ../scripts/ci/org.centos/stream/8/x86_64/test-avocado
|
@ -1,118 +0,0 @@
|
||||
# All ubuntu-18.04 jobs should run successfully in an environment
|
||||
# setup by the scripts/ci/setup/build-environment.yml task
|
||||
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
|
||||
|
||||
ubuntu-18.04-s390x-all-linux-static:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
script:
|
||||
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
|
||||
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
- make --output-sync -j`nproc` check-tcg V=1
|
||||
|
||||
ubuntu-18.04-s390x-all:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-18.04-s390x-alldbg:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-debug --disable-libssh
|
||||
- make clean
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-18.04-s390x-clang:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-18.04-s390x-tci:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --enable-tcg-interpreter
|
||||
- make --output-sync -j`nproc`
|
||||
|
||||
ubuntu-18.04-s390x-notcg:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --disable-tcg
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
@ -1,118 +0,0 @@
|
||||
# All ubuntu-20.04 jobs should run successfully in an environment
|
||||
# setup by the scripts/ci/setup/qemu/build-environment.yml task
|
||||
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
|
||||
|
||||
ubuntu-20.04-aarch64-all-linux-static:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||
script:
|
||||
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
|
||||
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
- make --output-sync -j`nproc` check-tcg V=1
|
||||
|
||||
ubuntu-20.04-aarch64-all:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-20.04-aarch64-alldbg:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-debug --disable-libssh
|
||||
- make clean
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-20.04-aarch64-clang:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-20.04-aarch64-tci:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --enable-tcg-interpreter
|
||||
- make --output-sync -j`nproc`
|
||||
|
||||
ubuntu-20.04-aarch64-notcg:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --disable-tcg
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
@ -50,11 +50,7 @@ build-edk2:
|
||||
GIT_DEPTH: 3
|
||||
script: # Clone the required submodules and build EDK2
|
||||
- git submodule update --init roms/edk2
|
||||
- git -C roms/edk2 submodule update --init --
|
||||
ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3
|
||||
BaseTools/Source/C/BrotliCompress/brotli
|
||||
CryptoPkg/Library/OpensslLib/openssl
|
||||
MdeModulePkg/Library/BrotliCustomDecompressLib/brotli
|
||||
- git -C roms/edk2 submodule update --init
|
||||
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||
- echo "=== Using ${JOBS} simultaneous jobs ==="
|
||||
- make -j${JOBS} -C roms efi 2>&1 1>edk2-stdout.log | tee -a edk2-stderr.log >&2
|
||||
|
@ -8,7 +8,7 @@ check-patch:
|
||||
variables:
|
||||
GIT_DEPTH: 1000
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project"'
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
||||
when: never
|
||||
- when: on_success
|
||||
allow_failure: true
|
||||
|
4
.mailmap
4
.mailmap
@ -69,7 +69,6 @@ Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
|
||||
# git author config, or had utf8/latin1 encoding issues.
|
||||
Aaron Lindsay <aaron@os.amperecomputing.com>
|
||||
Alexey Gerasimenko <x1917x@gmail.com>
|
||||
Alex Chen <alex.chen@huawei.com>
|
||||
Alex Ivanov <void@aleksoft.net>
|
||||
Andreas Färber <afaerber@suse.de>
|
||||
Bandan Das <bsd@redhat.com>
|
||||
@ -100,11 +99,9 @@ Gautham R. Shenoy <ego@in.ibm.com>
|
||||
Gautham R. Shenoy <ego@linux.vnet.ibm.com>
|
||||
Gonglei (Arei) <arei.gonglei@huawei.com>
|
||||
Guang Wang <wang.guang55@zte.com.cn>
|
||||
Haibin Zhang <haibinzhang@tencent.com>
|
||||
Hailiang Zhang <zhang.zhanghailiang@huawei.com>
|
||||
Hanna Reitz <hreitz@redhat.com> <mreitz@redhat.com>
|
||||
Hervé Poussineau <hpoussin@reactos.org>
|
||||
Hyman Huang <huangy81@chinatelecom.cn>
|
||||
Jakub Jermář <jakub@jermar.eu>
|
||||
Jakub Jermář <jakub.jermar@kernkonzept.com>
|
||||
Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
@ -138,7 +135,6 @@ Nicholas Thomas <nick@bytemark.co.uk>
|
||||
Nikunj A Dadhania <nikunj@linux.vnet.ibm.com>
|
||||
Orit Wasserman <owasserm@redhat.com>
|
||||
Paolo Bonzini <pbonzini@redhat.com>
|
||||
Pan Nengyuan <pannengyuan@huawei.com>
|
||||
Pavel Dovgaluk <dovgaluk@ispras.ru>
|
||||
Pavel Dovgaluk <pavel.dovgaluk@gmail.com>
|
||||
Pavel Dovgaluk <Pavel.Dovgaluk@ispras.ru>
|
||||
|
23
.travis.yml
23
.travis.yml
@ -305,3 +305,26 @@ jobs:
|
||||
- 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'.
|
||||
# This is the case when release candidate tags are created.
|
||||
- name: "Release tarball"
|
||||
if: tag IS present AND tag =~ /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
||||
env:
|
||||
# We want to build from the release tarball
|
||||
- BUILD_DIR="release/build/dir" SRC_DIR="../../.."
|
||||
- BASE_CONFIG="--prefix=$PWD/dist"
|
||||
- CONFIG="--target-list=x86_64-softmmu,aarch64-softmmu,armeb-linux-user,ppc-linux-user"
|
||||
- TEST_CMD="make install -j${JOBS}"
|
||||
- QEMU_VERSION="${TRAVIS_TAG:1}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
script:
|
||||
- make -C ${SRC_DIR} qemu-${QEMU_VERSION}.tar.bz2
|
||||
- ls -l ${SRC_DIR}/qemu-${QEMU_VERSION}.tar.bz2
|
||||
- tar -xf ${SRC_DIR}/qemu-${QEMU_VERSION}.tar.bz2 && cd qemu-${QEMU_VERSION}
|
||||
- mkdir -p release-build && cd release-build
|
||||
- ../configure ${BASE_CONFIG} ${CONFIG} || { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
- make install
|
||||
allow_failures:
|
||||
- env: UNRELIABLE=true
|
||||
|
72
3k.c
Normal file
72
3k.c
Normal file
@ -0,0 +1,72 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void libafl_qemu_main_loop( void );
|
||||
void libafl_qemu_sys_init(int argc, char **argv, char **envp);
|
||||
void libafl_qemu_cleanup( void );
|
||||
|
||||
void libafl_qemu_set_breakpoint( unsigned long int );
|
||||
|
||||
void libafl_qemu_remove_native_breakpoint( unsigned long int );
|
||||
void libafl_qemu_set_native_breakpoint( unsigned long int );
|
||||
void libafl_snapshot_save( const char* );
|
||||
void libafl_snapshot_load( const char* );
|
||||
|
||||
void libafl_phys_read(uint32_t, uint8_t*, int);
|
||||
|
||||
void libafl_phys_write(uint32_t, uint8_t*, int);
|
||||
|
||||
int64_t icount_to_ns(int64_t icount);
|
||||
|
||||
int64_t libafl_get_clock( void );
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
unsigned char buf[32] = "_`abcdefghijklmnopqrstuvwxyz{|}~";
|
||||
unsigned char buf2[32] = "0";
|
||||
unsigned char buf3[32] = "z";
|
||||
unsigned char buf4[32] = "a!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
|
||||
unsigned char buf5[32] = "b!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
|
||||
libafl_qemu_sys_init(argc, argv, envp);
|
||||
int pheader = 0x00006a4c;
|
||||
// libafl_phys_read(0x20000110-0x20000100+pheader, buf,32);
|
||||
// printf("FUZZ_INPUT[0]: %c\n", buf[0]);
|
||||
// Start pre-run
|
||||
libafl_qemu_set_native_breakpoint(0x4ce2);//send 217028
|
||||
libafl_qemu_main_loop();
|
||||
libafl_qemu_remove_native_breakpoint(0x4ce2);
|
||||
// End pre-run
|
||||
libafl_snapshot_save("Start");
|
||||
libafl_qemu_set_native_breakpoint(0x4be0);
|
||||
int64_t tmp = libafl_get_clock();
|
||||
printf("snapshot icount: %ld, %ldns\n",tmp,icount_to_ns(tmp));
|
||||
libafl_snapshot_load("Start");
|
||||
tmp = libafl_get_clock();
|
||||
printf("snapshot icount after load: %ld, %ldns\n",tmp,icount_to_ns(tmp));
|
||||
|
||||
libafl_phys_write(0x20000110-0x20000100+pheader, buf,32);
|
||||
libafl_qemu_main_loop();
|
||||
printf("%ld für %s\n",libafl_get_clock(),buf);
|
||||
libafl_snapshot_load("Start");
|
||||
|
||||
libafl_phys_write(0x20000110-0x20000100+pheader, buf2,32);
|
||||
libafl_qemu_main_loop();
|
||||
printf("%ld für %s\n",libafl_get_clock(),buf2);
|
||||
libafl_snapshot_load("Start");
|
||||
|
||||
libafl_phys_write(0x20000110-0x20000100+pheader, buf3,32);
|
||||
libafl_qemu_main_loop();
|
||||
printf("%ld für %s\n",libafl_get_clock(),buf3);
|
||||
libafl_snapshot_load("Start");
|
||||
/*int counter = 3000;
|
||||
do {
|
||||
libafl_phys_write(0x20000110-0x20000100+pheader, buf,32);
|
||||
libafl_qemu_main_loop();
|
||||
int64_t tmp = libafl_get_clock();
|
||||
printf("%ld, %ldns\n",tmp,icount_to_ns(tmp));
|
||||
libafl_snapshot_load("Start");
|
||||
// puts("Reload has occured");
|
||||
counter--;
|
||||
} while (counter);*/
|
||||
libafl_qemu_cleanup();
|
||||
return 0;
|
||||
}
|
@ -41,7 +41,3 @@ config PVRDMA
|
||||
config MULTIPROCESS_ALLOWED
|
||||
bool
|
||||
imply MULTIPROCESS
|
||||
|
||||
config FUZZ
|
||||
bool
|
||||
select SPARSE_MEM
|
||||
|
280
MAINTAINERS
280
MAINTAINERS
@ -109,12 +109,6 @@ K: ^Subject:.*(?i)s390x?
|
||||
T: git https://gitlab.com/cohuck/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
MIPS general architecture support
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
|
||||
S: Odd Fixes
|
||||
K: ^Subject:.*(?i)mips
|
||||
|
||||
Guest CPU cores (TCG)
|
||||
---------------------
|
||||
Overall TCG CPUs
|
||||
@ -177,7 +171,7 @@ L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/smmu*
|
||||
F: include/hw/arm/smmu*
|
||||
F: tests/avocado/smmu.py
|
||||
F: tests/acceptance/smmu.py
|
||||
|
||||
AVR TCG CPUs
|
||||
M: Michael Rolnik <mrolnik@gmail.com>
|
||||
@ -185,7 +179,7 @@ S: Maintained
|
||||
F: docs/system/target-avr.rst
|
||||
F: gdb-xml/avr-cpu.xml
|
||||
F: target/avr/
|
||||
F: tests/avocado/machine_avr6.py
|
||||
F: tests/acceptance/machine_avr6.py
|
||||
|
||||
CRIS TCG CPUs
|
||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
@ -211,7 +205,10 @@ HPPA (PA-RISC) TCG CPUs
|
||||
M: Richard Henderson <richard.henderson@linaro.org>
|
||||
S: Maintained
|
||||
F: target/hppa/
|
||||
F: hw/hppa/
|
||||
F: disas/hppa.c
|
||||
F: hw/net/*i82596*
|
||||
F: include/hw/net/lasi_82596.h
|
||||
|
||||
M68K TCG CPUs
|
||||
M: Laurent Vivier <laurent@vivier.eu>
|
||||
@ -225,8 +222,6 @@ S: Maintained
|
||||
F: target/microblaze/
|
||||
F: hw/microblaze/
|
||||
F: disas/microblaze.c
|
||||
F: tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh
|
||||
F: tests/tcg/nios2/Makefile.target
|
||||
|
||||
MIPS TCG CPUs
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
@ -235,9 +230,19 @@ R: Jiaxun Yang <jiaxun.yang@flygoat.com>
|
||||
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
|
||||
S: Odd Fixes
|
||||
F: target/mips/
|
||||
F: configs/devices/mips*/*
|
||||
F: disas/mips.c
|
||||
F: docs/system/cpu-models-mips.rst.inc
|
||||
F: hw/intc/mips_gic.c
|
||||
F: hw/mips/
|
||||
F: hw/misc/mips_*
|
||||
F: hw/timer/mips_gictimer.c
|
||||
F: include/hw/intc/mips_gic.h
|
||||
F: include/hw/mips/
|
||||
F: include/hw/misc/mips_*
|
||||
F: include/hw/timer/mips_gictimer.h
|
||||
F: tests/tcg/mips/
|
||||
K: ^Subject:.*(?i)mips
|
||||
|
||||
MIPS TCG CPUs (nanoMIPS ISA)
|
||||
S: Orphan
|
||||
@ -252,7 +257,6 @@ F: target/nios2/
|
||||
F: hw/nios2/
|
||||
F: disas/nios2.c
|
||||
F: configs/devices/nios2-softmmu/default.mak
|
||||
F: tests/docker/dockerfiles/debian-nios2-cross.d/build-toolchain.sh
|
||||
|
||||
OpenRISC TCG CPUs
|
||||
M: Stafford Horne <shorne@gmail.com>
|
||||
@ -262,17 +266,15 @@ F: hw/openrisc/
|
||||
F: tests/tcg/openrisc/
|
||||
|
||||
PowerPC TCG CPUs
|
||||
M: Cédric Le Goater <clg@kaod.org>
|
||||
M: Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
R: Greg Kurz <groug@kaod.org>
|
||||
M: David Gibson <david@gibson.dropbear.id.au>
|
||||
M: Greg Kurz <groug@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Maintained
|
||||
F: target/ppc/
|
||||
F: hw/ppc/ppc.c
|
||||
F: hw/ppc/ppc_booke.c
|
||||
F: include/hw/ppc/ppc.h
|
||||
F: hw/ppc/
|
||||
F: include/hw/ppc/
|
||||
F: disas/ppc.c
|
||||
F: tests/acceptance/machine_ppc.py
|
||||
|
||||
RISC-V TCG CPUs
|
||||
M: Palmer Dabbelt <palmer@dabbelt.com>
|
||||
@ -324,7 +326,7 @@ F: disas/sparc.c
|
||||
X86 TCG CPUs
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
M: Richard Henderson <richard.henderson@linaro.org>
|
||||
M: Eduardo Habkost <eduardo@habkost.net>
|
||||
M: Eduardo Habkost <ehabkost@redhat.com>
|
||||
S: Maintained
|
||||
F: target/i386/tcg/
|
||||
F: tests/tcg/i386/
|
||||
@ -384,15 +386,14 @@ F: target/mips/kvm*
|
||||
F: target/mips/sysemu/
|
||||
|
||||
PPC KVM CPUs
|
||||
M: Cédric Le Goater <clg@kaod.org>
|
||||
M: Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
R: Greg Kurz <groug@kaod.org>
|
||||
M: David Gibson <david@gibson.dropbear.id.au>
|
||||
M: Greg Kurz <groug@kaod.org>
|
||||
S: Maintained
|
||||
F: target/ppc/kvm.c
|
||||
|
||||
S390 KVM CPUs
|
||||
M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Cornelia Huck <cohuck@redhat.com>
|
||||
M: Christian Borntraeger <borntraeger@de.ibm.com>
|
||||
S: Supported
|
||||
F: target/s390x/kvm/
|
||||
@ -407,6 +408,7 @@ F: hw/intc/s390_flic.c
|
||||
F: hw/intc/s390_flic_kvm.c
|
||||
F: include/hw/s390x/s390_flic.h
|
||||
F: gdb-xml/s390*.xml
|
||||
T: git https://gitlab.com/cohuck/qemu.git s390-next
|
||||
T: git https://github.com/borntraeger/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
@ -415,10 +417,7 @@ M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
M: Marcelo Tosatti <mtosatti@redhat.com>
|
||||
L: kvm@vger.kernel.org
|
||||
S: Supported
|
||||
F: docs/amd-memory-encryption.txt
|
||||
F: docs/system/i386/sgx.rst
|
||||
F: target/i386/kvm/
|
||||
F: target/i386/sev*
|
||||
F: scripts/kvm/vmxcap
|
||||
|
||||
Guest CPU Cores (other accelerators)
|
||||
@ -434,11 +433,6 @@ F: accel/accel-*.c
|
||||
F: accel/Makefile.objs
|
||||
F: accel/stubs/Makefile.objs
|
||||
|
||||
Apple Silicon HVF CPUs
|
||||
M: Alexander Graf <agraf@csgraf.de>
|
||||
S: Maintained
|
||||
F: target/arm/hvf/
|
||||
|
||||
X86 HVF CPUs
|
||||
M: Cameron Esfahani <dirty@apple.com>
|
||||
M: Roman Bolshakov <r.bolshakov@yadro.com>
|
||||
@ -623,7 +617,6 @@ F: hw/intc/gic_internal.h
|
||||
F: hw/misc/a9scu.c
|
||||
F: hw/misc/arm11scu.c
|
||||
F: hw/misc/arm_l2x0.c
|
||||
F: hw/misc/armv7m_ras.c
|
||||
F: hw/timer/a9gtimer*
|
||||
F: hw/timer/arm*
|
||||
F: include/hw/arm/arm*.h
|
||||
@ -633,7 +626,6 @@ F: include/hw/misc/arm11scu.h
|
||||
F: include/hw/timer/a9gtimer.h
|
||||
F: include/hw/timer/arm_mptimer.h
|
||||
F: include/hw/timer/armv7m_systick.h
|
||||
F: include/hw/misc/armv7m_ras.h
|
||||
F: tests/qtest/test-arm-mptimer.c
|
||||
|
||||
Exynos
|
||||
@ -661,7 +653,7 @@ S: Odd Fixes
|
||||
F: include/hw/arm/digic.h
|
||||
F: hw/*/digic*
|
||||
F: include/hw/*/digic*
|
||||
F: tests/avocado/machine_arm_canona1100.py
|
||||
F: tests/acceptance/machine_arm_canona1100.py
|
||||
F: docs/system/arm/digic.rst
|
||||
|
||||
Goldfish RTC
|
||||
@ -712,7 +704,7 @@ S: Maintained
|
||||
F: hw/arm/integratorcp.c
|
||||
F: hw/misc/arm_integrator_debug.c
|
||||
F: include/hw/misc/arm_integrator_debug.h
|
||||
F: tests/avocado/machine_arm_integratorcp.py
|
||||
F: tests/acceptance/machine_arm_integratorcp.py
|
||||
F: docs/system/arm/integratorcp.rst
|
||||
|
||||
MCIMX6UL EVK / i.MX6ul
|
||||
@ -809,7 +801,7 @@ F: include/hw/display/blizzard.h
|
||||
F: include/hw/input/lm832x.h
|
||||
F: include/hw/input/tsc2xxx.h
|
||||
F: include/hw/misc/cbus.h
|
||||
F: tests/avocado/machine_arm_n8x0.py
|
||||
F: tests/acceptance/machine_arm_n8x0.py
|
||||
F: docs/system/arm/nseries.rst
|
||||
|
||||
Palm
|
||||
@ -1099,8 +1091,6 @@ R: Helge Deller <deller@gmx.de>
|
||||
S: Odd Fixes
|
||||
F: configs/devices/hppa-softmmu/default.mak
|
||||
F: hw/hppa/
|
||||
F: hw/net/*i82596*
|
||||
F: include/hw/net/lasi_82596.h
|
||||
F: pc-bios/hppa-firmware.img
|
||||
|
||||
M68K Machines
|
||||
@ -1163,7 +1153,7 @@ M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
S: Maintained
|
||||
F: hw/microblaze/petalogix_s3adsp1800_mmu.c
|
||||
F: include/hw/char/xilinx_uartlite.h
|
||||
F: tests/avocado/machine_microblaze.py
|
||||
F: tests/acceptance/machine_microblaze.py
|
||||
|
||||
petalogix_ml605
|
||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
@ -1172,13 +1162,6 @@ F: hw/microblaze/petalogix_ml605_mmu.c
|
||||
|
||||
MIPS Machines
|
||||
-------------
|
||||
Overall MIPS Machines
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
S: Odd Fixes
|
||||
F: configs/devices/mips*/*
|
||||
F: hw/mips/
|
||||
F: include/hw/mips/
|
||||
|
||||
Jazz
|
||||
M: Hervé Poussineau <hpoussin@reactos.org>
|
||||
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
|
||||
@ -1196,8 +1179,8 @@ F: hw/acpi/piix4.c
|
||||
F: hw/mips/malta.c
|
||||
F: hw/mips/gt64xxx_pci.c
|
||||
F: include/hw/southbridge/piix.h
|
||||
F: tests/avocado/linux_ssh_mips_malta.py
|
||||
F: tests/avocado/machine_mips_malta.py
|
||||
F: tests/acceptance/linux_ssh_mips_malta.py
|
||||
F: tests/acceptance/machine_mips_malta.py
|
||||
|
||||
Mipssim
|
||||
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
|
||||
@ -1215,7 +1198,7 @@ F: hw/isa/vt82c686.c
|
||||
F: hw/pci-host/bonito.c
|
||||
F: hw/usb/vt82c686-uhci-pci.c
|
||||
F: include/hw/isa/vt82c686.h
|
||||
F: tests/avocado/machine_mips_fuloong2e.py
|
||||
F: tests/acceptance/machine_mips_fuloong2e.py
|
||||
|
||||
Loongson-3 virtual platforms
|
||||
M: Huacai Chen <chenhuacai@kernel.org>
|
||||
@ -1225,7 +1208,7 @@ F: hw/intc/loongson_liointc.c
|
||||
F: hw/mips/loongson3_bootp.c
|
||||
F: hw/mips/loongson3_bootp.h
|
||||
F: hw/mips/loongson3_virt.c
|
||||
F: tests/avocado/machine_mips_loongson3v.py
|
||||
F: tests/acceptance/machine_mips_loongson3v.py
|
||||
|
||||
Boston
|
||||
M: Paul Burton <paulburton@kernel.org>
|
||||
@ -1246,19 +1229,24 @@ F: hw/openrisc/openrisc_sim.c
|
||||
PowerPC Machines
|
||||
----------------
|
||||
405
|
||||
M: David Gibson <david@gibson.dropbear.id.au>
|
||||
M: Greg Kurz <groug@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Orphan
|
||||
S: Odd Fixes
|
||||
F: hw/ppc/ppc405_boards.c
|
||||
|
||||
Bamboo
|
||||
M: David Gibson <david@gibson.dropbear.id.au>
|
||||
M: Greg Kurz <groug@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Orphan
|
||||
S: Odd Fixes
|
||||
F: hw/ppc/ppc440_bamboo.c
|
||||
F: tests/avocado/ppc_bamboo.py
|
||||
|
||||
e500
|
||||
M: David Gibson <david@gibson.dropbear.id.au>
|
||||
M: Greg Kurz <groug@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Orphan
|
||||
S: Odd Fixes
|
||||
F: hw/ppc/e500*
|
||||
F: hw/gpio/mpc8xxx.c
|
||||
F: hw/i2c/mpc_i2c.c
|
||||
@ -1267,18 +1255,19 @@ F: hw/pci-host/ppce500.c
|
||||
F: include/hw/ppc/ppc_e500.h
|
||||
F: include/hw/pci-host/ppce500.h
|
||||
F: pc-bios/u-boot.e500
|
||||
F: hw/intc/openpic_kvm.h
|
||||
F: include/hw/ppc/openpic_kvm.h
|
||||
|
||||
mpc8544ds
|
||||
M: David Gibson <david@gibson.dropbear.id.au>
|
||||
M: Greg Kurz <groug@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Orphan
|
||||
S: Odd Fixes
|
||||
F: hw/ppc/mpc8544ds.c
|
||||
F: hw/ppc/mpc8544_guts.c
|
||||
F: tests/avocado/ppc_mpc8544ds.py
|
||||
|
||||
New World (mac99)
|
||||
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
R: Greg Kurz <groug@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/ppc/mac_newworld.c
|
||||
@ -1297,6 +1286,8 @@ F: pc-bios/qemu_vga.ndrv
|
||||
|
||||
Old World (g3beige)
|
||||
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
R: Greg Kurz <groug@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/ppc/mac_oldworld.c
|
||||
@ -1310,6 +1301,8 @@ F: pc-bios/qemu_vga.ndrv
|
||||
|
||||
PReP
|
||||
M: Hervé Poussineau <hpoussin@reactos.org>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
R: Greg Kurz <groug@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/ppc/prep.c
|
||||
@ -1322,15 +1315,13 @@ F: hw/dma/i82374.c
|
||||
F: hw/rtc/m48t59-isa.c
|
||||
F: include/hw/isa/pc87312.h
|
||||
F: include/hw/rtc/m48t59.h
|
||||
F: tests/avocado/ppc_prep_40p.py
|
||||
F: tests/acceptance/ppc_prep_40p.py
|
||||
|
||||
sPAPR
|
||||
M: Cédric Le Goater <clg@kaod.org>
|
||||
M: Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
R: Greg Kurz <groug@kaod.org>
|
||||
M: David Gibson <david@gibson.dropbear.id.au>
|
||||
M: Greg Kurz <groug@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Maintained
|
||||
S: Supported
|
||||
F: hw/*/spapr*
|
||||
F: include/hw/*/spapr*
|
||||
F: hw/*/xics*
|
||||
@ -1342,10 +1333,11 @@ F: tests/qtest/spapr*
|
||||
F: tests/qtest/libqos/*spapr*
|
||||
F: tests/qtest/rtas*
|
||||
F: tests/qtest/libqos/rtas*
|
||||
F: tests/avocado/ppc_pseries.py
|
||||
|
||||
PowerNV (Non-Virtualized)
|
||||
M: Cédric Le Goater <clg@kaod.org>
|
||||
M: David Gibson <david@gibson.dropbear.id.au>
|
||||
M: Greg Kurz <groug@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/ppc/pnv*
|
||||
@ -1362,10 +1354,11 @@ M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/ppc/virtex_ml507.c
|
||||
F: tests/avocado/ppc_virtex_ml507.py
|
||||
|
||||
sam460ex
|
||||
M: BALATON Zoltan <balaton@eik.bme.hu>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
R: Greg Kurz <groug@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/ppc/sam460ex.c
|
||||
@ -1379,6 +1372,7 @@ F: roms/u-boot-sam460ex
|
||||
|
||||
pegasos2
|
||||
M: BALATON Zoltan <balaton@eik.bme.hu>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/ppc/pegasos2.c
|
||||
@ -1388,8 +1382,6 @@ F: include/hw/pci-host/mv64361.h
|
||||
|
||||
Virtual Open Firmware (VOF)
|
||||
M: Alexey Kardashevskiy <aik@ozlabs.ru>
|
||||
R: Cédric Le Goater <clg@kaod.org>
|
||||
R: Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
R: Greg Kurz <groug@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
@ -1451,7 +1443,7 @@ R: Yoshinori Sato <ysato@users.sourceforge.jp>
|
||||
S: Orphan
|
||||
F: docs/system/target-rx.rst
|
||||
F: hw/rx/rx-gdbsim.c
|
||||
F: tests/avocado/machine_rx_gdbsim.py
|
||||
F: tests/acceptance/machine_rx_gdbsim.py
|
||||
|
||||
SH4 Machines
|
||||
------------
|
||||
@ -1505,7 +1497,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/avocado/machine_sparc64_sun4u.py
|
||||
F: tests/acceptance/machine_sparc64_sun4u.py
|
||||
|
||||
Sun4v
|
||||
M: Artyom Tarasenko <atar4qemu@gmail.com>
|
||||
@ -1521,11 +1513,12 @@ S: Maintained
|
||||
F: hw/sparc/leon3.c
|
||||
F: hw/*/grlib*
|
||||
F: include/hw/*/grlib*
|
||||
F: tests/avocado/machine_sparc_leon3.py
|
||||
F: tests/acceptance/machine_sparc_leon3.py
|
||||
|
||||
S390 Machines
|
||||
-------------
|
||||
S390 Virtio-ccw
|
||||
M: Cornelia Huck <cohuck@redhat.com>
|
||||
M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@de.ibm.com>
|
||||
S: Supported
|
||||
@ -1536,7 +1529,8 @@ F: include/hw/s390x/
|
||||
F: hw/watchdog/wdt_diag288.c
|
||||
F: include/hw/watchdog/wdt_diag288.h
|
||||
F: configs/devices/s390x-softmmu/default.mak
|
||||
F: tests/avocado/machine_s390_ccw_virtio.py
|
||||
F: tests/acceptance/machine_s390_ccw_virtio.py
|
||||
T: git https://gitlab.com/cohuck/qemu.git s390-next
|
||||
T: git https://github.com/borntraeger/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
@ -1622,21 +1616,19 @@ microvm
|
||||
M: Sergio Lopez <slp@redhat.com>
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
S: Maintained
|
||||
F: docs/system/i386/microvm.rst
|
||||
F: docs/microvm.rst
|
||||
F: hw/i386/microvm.c
|
||||
F: include/hw/i386/microvm.h
|
||||
F: pc-bios/bios-microvm.bin
|
||||
|
||||
Machine core
|
||||
M: Eduardo Habkost <eduardo@habkost.net>
|
||||
M: Eduardo Habkost <ehabkost@redhat.com>
|
||||
M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
|
||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
S: Supported
|
||||
F: cpu.c
|
||||
F: hw/core/cpu.c
|
||||
F: hw/core/machine-qmp-cmds.c
|
||||
F: hw/core/machine.c
|
||||
F: hw/core/machine-smp.c
|
||||
F: hw/core/null-machine.c
|
||||
F: hw/core/numa.c
|
||||
F: hw/cpu/cluster.c
|
||||
@ -1646,7 +1638,6 @@ F: include/hw/boards.h
|
||||
F: include/hw/core/cpu.h
|
||||
F: include/hw/cpu/cluster.h
|
||||
F: include/sysemu/numa.h
|
||||
F: tests/unit/test-smp-parse.c
|
||||
T: git https://gitlab.com/ehabkost/qemu.git machine-next
|
||||
|
||||
Xtensa Machines
|
||||
@ -1669,16 +1660,6 @@ F: hw/net/opencores_eth.c
|
||||
|
||||
Devices
|
||||
-------
|
||||
Overall Audio frontends
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: hw/audio/
|
||||
F: include/hw/audio/
|
||||
F: tests/qtest/ac97-test.c
|
||||
F: tests/qtest/es1370-test.c
|
||||
F: tests/qtest/intel-hda-test.c
|
||||
F: tests/qtest/fuzz-sb16-test.c
|
||||
|
||||
Xilinx CAN
|
||||
M: Vikram Garhwal <fnu.vikram@xilinx.com>
|
||||
M: Francisco Iglesias <francisco.iglesias@xilinx.com>
|
||||
@ -1758,7 +1739,6 @@ F: docs/specs/*pci*
|
||||
ACPI/SMBIOS
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
M: Igor Mammedov <imammedo@redhat.com>
|
||||
R: Ani Sinha <ani@anisinha.ca>
|
||||
S: Supported
|
||||
F: include/hw/acpi/*
|
||||
F: include/hw/firmware/smbios.h
|
||||
@ -1771,10 +1751,6 @@ F: qapi/acpi.json
|
||||
F: tests/qtest/bios-tables-test*
|
||||
F: tests/qtest/acpi-utils.[hc]
|
||||
F: tests/data/acpi/
|
||||
F: docs/specs/acpi_cpu_hotplug.rst
|
||||
F: docs/specs/acpi_mem_hotplug.rst
|
||||
F: docs/specs/acpi_pci_hotplug.rst
|
||||
F: docs/specs/acpi_hw_reduced_hotplug.rst
|
||||
|
||||
ACPI/HEST/GHES
|
||||
R: Dongjiu Geng <gengdongjiu1@gmail.com>
|
||||
@ -1785,8 +1761,9 @@ 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
|
||||
S: Orphan
|
||||
S: Odd Fixes
|
||||
F: hw/ppc/ppc4*.c
|
||||
F: hw/i2c/ppc4xx_i2c.c
|
||||
F: include/hw/ppc/ppc4xx.h
|
||||
@ -1878,6 +1855,7 @@ F: docs/igd-assign.txt
|
||||
F: docs/devel/vfio-migration.rst
|
||||
|
||||
vfio-ccw
|
||||
M: Cornelia Huck <cohuck@redhat.com>
|
||||
M: Eric Farman <farman@linux.ibm.com>
|
||||
M: Matthew Rosato <mjrosato@linux.ibm.com>
|
||||
S: Supported
|
||||
@ -1885,6 +1863,7 @@ F: hw/vfio/ccw.c
|
||||
F: hw/s390x/s390-ccw.c
|
||||
F: include/hw/s390x/s390-ccw.h
|
||||
F: include/hw/s390x/vfio-ccw.h
|
||||
T: git https://gitlab.com/cohuck/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
vfio-ap
|
||||
@ -2078,7 +2057,6 @@ F: hw/acpi/nvdimm.c
|
||||
F: hw/mem/nvdimm.c
|
||||
F: include/hw/mem/nvdimm.h
|
||||
F: docs/nvdimm.txt
|
||||
F: docs/specs/acpi_nvdimm.rst
|
||||
|
||||
e1000x
|
||||
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
|
||||
@ -2120,7 +2098,7 @@ M: Alex Bennée <alex.bennee@linaro.org>
|
||||
S: Maintained
|
||||
F: hw/core/guest-loader.c
|
||||
F: docs/system/guest-loader.rst
|
||||
F: tests/avocado/boot_xen.py
|
||||
F: tests/acceptance/boot_xen.py
|
||||
|
||||
Intel Hexadecimal Object File Loader
|
||||
M: Su Hang <suhang16@mails.ucas.ac.cn>
|
||||
@ -2239,6 +2217,8 @@ T: git https://github.com/philmd/qemu.git fw_cfg-next
|
||||
|
||||
XIVE
|
||||
M: Cédric Le Goater <clg@kaod.org>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
R: Greg Kurz <groug@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Supported
|
||||
F: hw/*/*xive*
|
||||
@ -2274,80 +2254,19 @@ F: net/can/*
|
||||
F: hw/net/can/*
|
||||
F: include/net/can_*.h
|
||||
|
||||
OpenPIC interrupt controller
|
||||
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
|
||||
S: Odd Fixes
|
||||
F: hw/intc/openpic.c
|
||||
F: include/hw/ppc/openpic.h
|
||||
|
||||
MIPS CPS
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
S: Odd Fixes
|
||||
F: hw/misc/mips_*
|
||||
F: include/hw/misc/mips_*
|
||||
|
||||
MIPS GIC
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
S: Odd Fixes
|
||||
F: hw/intc/mips_gic.c
|
||||
F: hw/timer/mips_gictimer.c
|
||||
F: include/hw/intc/mips_gic.h
|
||||
F: include/hw/timer/mips_gictimer.h
|
||||
|
||||
Subsystems
|
||||
----------
|
||||
Overall Audio backends
|
||||
Audio
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: audio/
|
||||
X: audio/alsaaudio.c
|
||||
X: audio/coreaudio.c
|
||||
X: audio/dsound*
|
||||
X: audio/jackaudio.c
|
||||
X: audio/ossaudio.c
|
||||
X: audio/paaudio.c
|
||||
X: audio/sdlaudio.c
|
||||
X: audio/spiceaudio.c
|
||||
F: hw/audio/
|
||||
F: include/hw/audio/
|
||||
F: qapi/audio.json
|
||||
|
||||
ALSA Audio backend
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
R: Christian Schoenebeck <qemu_oss@crudebyte.com>
|
||||
S: Odd Fixes
|
||||
F: audio/alsaaudio.c
|
||||
|
||||
Core Audio framework backend
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
R: Christian Schoenebeck <qemu_oss@crudebyte.com>
|
||||
S: Odd Fixes
|
||||
F: audio/coreaudio.c
|
||||
|
||||
DSound Audio backend
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: audio/dsound*
|
||||
|
||||
JACK Audio Connection Kit backend
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
R: Christian Schoenebeck <qemu_oss@crudebyte.com>
|
||||
S: Odd Fixes
|
||||
F: audio/jackaudio.c
|
||||
|
||||
Open Sound System (OSS) Audio backend
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: audio/ossaudio.c
|
||||
|
||||
PulseAudio backend
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: audio/paaudio.c
|
||||
|
||||
SDL Audio backend
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
R: Thomas Huth <huth@tuxfamily.org>
|
||||
S: Odd Fixes
|
||||
F: audio/sdlaudio.c
|
||||
F: tests/qtest/ac97-test.c
|
||||
F: tests/qtest/es1370-test.c
|
||||
F: tests/qtest/intel-hda-test.c
|
||||
F: tests/qtest/fuzz-sb16-test.c
|
||||
|
||||
Block layer core
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
@ -2418,8 +2337,8 @@ F: block/mirror.c
|
||||
F: qapi/job.json
|
||||
F: block/block-copy.c
|
||||
F: include/block/block-copy.c
|
||||
F: block/copy-before-write.h
|
||||
F: block/copy-before-write.c
|
||||
F: block/backup-top.h
|
||||
F: block/backup-top.c
|
||||
F: include/block/aio_task.h
|
||||
F: block/aio_task.c
|
||||
F: util/qemu-co-shared-resource.c
|
||||
@ -2534,7 +2453,6 @@ Memory API
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
M: Peter Xu <peterx@redhat.com>
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
S: Supported
|
||||
F: include/exec/ioport.h
|
||||
F: include/exec/memop.h
|
||||
@ -2648,13 +2566,13 @@ F: backends/cryptodev*.c
|
||||
Python library
|
||||
M: John Snow <jsnow@redhat.com>
|
||||
M: Cleber Rosa <crosa@redhat.com>
|
||||
R: Eduardo Habkost <eduardo@habkost.net>
|
||||
R: Eduardo Habkost <ehabkost@redhat.com>
|
||||
S: Maintained
|
||||
F: python/
|
||||
T: git https://gitlab.com/jsnow/qemu.git python
|
||||
|
||||
Python scripts
|
||||
M: Eduardo Habkost <eduardo@habkost.net>
|
||||
M: Eduardo Habkost <ehabkost@redhat.com>
|
||||
M: Cleber Rosa <crosa@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: scripts/*.py
|
||||
@ -2730,7 +2648,7 @@ T: git https://github.com/mdroth/qemu.git qga
|
||||
QOM
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
R: Daniel P. Berrange <berrange@redhat.com>
|
||||
R: Eduardo Habkost <eduardo@habkost.net>
|
||||
R: Eduardo Habkost <ehabkost@redhat.com>
|
||||
S: Supported
|
||||
F: docs/qdev-device-use.txt
|
||||
F: hw/core/qdev*
|
||||
@ -2750,7 +2668,7 @@ F: tests/unit/check-qom-proplist.c
|
||||
F: tests/unit/test-qdev-global-props.c
|
||||
|
||||
QOM boilerplate conversion script
|
||||
M: Eduardo Habkost <eduardo@habkost.net>
|
||||
M: Eduardo Habkost <ehabkost@redhat.com>
|
||||
S: Maintained
|
||||
F: scripts/codeconverter/
|
||||
|
||||
@ -2788,8 +2706,6 @@ R: Paolo Bonzini <pbonzini@redhat.com>
|
||||
R: Bandan Das <bsd@redhat.com>
|
||||
R: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
R: Thomas Huth <thuth@redhat.com>
|
||||
R: Darren Kenny <darren.kenny@oracle.com>
|
||||
R: Qiuhao Li <Qiuhao.Li@outlook.com>
|
||||
S: Maintained
|
||||
F: tests/qtest/fuzz/
|
||||
F: tests/qtest/fuzz-*test.c
|
||||
@ -2994,9 +2910,8 @@ F: net/filter-replay.c
|
||||
F: include/sysemu/replay.h
|
||||
F: docs/replay.txt
|
||||
F: stubs/replay.c
|
||||
F: tests/avocado/replay_kernel.py
|
||||
F: tests/avocado/replay_linux.py
|
||||
F: tests/avocado/reverse_debugging.py
|
||||
F: tests/acceptance/replay_kernel.py
|
||||
F: tests/acceptance/reverse_debugging.py
|
||||
F: qapi/replay.json
|
||||
|
||||
IOVA Tree
|
||||
@ -3113,7 +3028,7 @@ S: Maintained
|
||||
F: docs/devel/tcg-plugins.rst
|
||||
F: plugins/
|
||||
F: tests/plugin/
|
||||
F: tests/avocado/tcg_plugins.py
|
||||
F: tests/acceptance/tcg_plugins.py
|
||||
F: contrib/plugins/
|
||||
|
||||
AArch64 TCG target
|
||||
@ -3469,7 +3384,7 @@ M: Alex Bennée <alex.bennee@linaro.org>
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
M: Thomas Huth <thuth@redhat.com>
|
||||
R: Wainer dos Santos Moschetta <wainersm@redhat.com>
|
||||
R: Beraldo Leal <bleal@redhat.com>
|
||||
R: Willian Rampazzo <willianr@redhat.com>
|
||||
S: Maintained
|
||||
F: .github/lockdown.yml
|
||||
F: .gitlab-ci.yml
|
||||
@ -3502,20 +3417,13 @@ S: Maintained
|
||||
F: tests/tcg/Makefile
|
||||
F: tests/tcg/Makefile.include
|
||||
|
||||
Integration Testing with the Avocado framework
|
||||
Acceptance (Integration) Testing with the Avocado framework
|
||||
W: https://trello.com/b/6Qi1pxVn/avocado-qemu
|
||||
R: Cleber Rosa <crosa@redhat.com>
|
||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
R: Wainer dos Santos Moschetta <wainersm@redhat.com>
|
||||
R: Beraldo Leal <bleal@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: tests/avocado/
|
||||
|
||||
GitLab custom runner (Works On Arm Sponsored)
|
||||
M: Alex Bennée <alex.bennee@linaro.org>
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
S: Maintained
|
||||
F: .gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml
|
||||
F: tests/acceptance/
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
13
Makefile
13
Makefile
@ -87,7 +87,7 @@ x := $(shell rm -rf meson-private meson-info meson-logs)
|
||||
endif
|
||||
|
||||
# 1. ensure config-host.mak is up-to-date
|
||||
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/scripts/meson-buildoptions.sh $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
|
||||
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
|
||||
@echo config-host.mak is out-of-date, running configure
|
||||
@if test -f meson-private/coredata.dat; then \
|
||||
./config.status --skip-meson; \
|
||||
@ -124,12 +124,6 @@ ifneq ($(MESON),)
|
||||
Makefile.mtest: build.ninja scripts/mtest2make.py
|
||||
$(MESON) introspect --targets --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@
|
||||
-include Makefile.mtest
|
||||
|
||||
.PHONY: update-buildoptions
|
||||
all update-buildoptions: $(SRC_PATH)/scripts/meson-buildoptions.sh
|
||||
$(SRC_PATH)/scripts/meson-buildoptions.sh: $(SRC_PATH)/meson_options.txt
|
||||
$(MESON) introspect --buildoptions $(SRC_PATH)/meson.build | $(PYTHON) \
|
||||
scripts/meson-buildoptions.py > $@.tmp && mv $@.tmp $@
|
||||
endif
|
||||
|
||||
# 4. Rules to bridge to other makefiles
|
||||
@ -235,8 +229,7 @@ distclean: clean
|
||||
rm -f linux-headers/asm
|
||||
rm -Rf .sdk
|
||||
|
||||
find-src-path = find "$(SRC_PATH)" -path "$(SRC_PATH)/meson" -prune -o \
|
||||
-type l -prune -o \( -name "*.[chsS]" -o -name "*.[ch].inc" \)
|
||||
find-src-path = find "$(SRC_PATH)/" -path "$(SRC_PATH)/meson" -prune -o \( -name "*.[chsS]" -o -name "*.[ch].inc" \)
|
||||
|
||||
.PHONY: ctags
|
||||
ctags:
|
||||
@ -257,7 +250,7 @@ gtags:
|
||||
"GTAGS", "Remove old $@ files")
|
||||
$(call quiet-command, \
|
||||
(cd $(SRC_PATH) && \
|
||||
$(find-src-path) -print | gtags -f -), \
|
||||
$(find-src-path) | gtags -f -), \
|
||||
"GTAGS", "Re-index $(SRC_PATH)")
|
||||
|
||||
.PHONY: TAGS
|
||||
|
13
README.md
Normal file
13
README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# QEMU LibAFL Bridge
|
||||
|
||||
This is a patched QEMU that exposes an interface for LibAFL-based fuzzers.
|
||||
|
||||
This raw interface is used in `libafl_qemu` that expose a more Rusty API.
|
||||
|
||||
#### License
|
||||
|
||||
<sup>
|
||||
This project extends the QEMU emulator, and our contributions to previously existing files adopt those files' respective licenses; the files that we have added are made available under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
|
||||
</sup>
|
||||
|
||||
<br>
|
14
README.rst
14
README.rst
@ -59,9 +59,9 @@ of other UNIX targets. The simple steps to build QEMU are:
|
||||
|
||||
Additional information can also be found online via the QEMU website:
|
||||
|
||||
* `<https://wiki.qemu.org/Hosts/Linux>`_
|
||||
* `<https://wiki.qemu.org/Hosts/Mac>`_
|
||||
* `<https://wiki.qemu.org/Hosts/W32>`_
|
||||
* `<https://qemu.org/Hosts/Linux>`_
|
||||
* `<https://qemu.org/Hosts/Mac>`_
|
||||
* `<https://qemu.org/Hosts/W32>`_
|
||||
|
||||
|
||||
Submitting patches
|
||||
@ -84,8 +84,8 @@ the Developers Guide.
|
||||
Additional information on submitting patches can be found online via
|
||||
the QEMU website
|
||||
|
||||
* `<https://wiki.qemu.org/Contribute/SubmitAPatch>`_
|
||||
* `<https://wiki.qemu.org/Contribute/TrivialPatches>`_
|
||||
* `<https://qemu.org/Contribute/SubmitAPatch>`_
|
||||
* `<https://qemu.org/Contribute/TrivialPatches>`_
|
||||
|
||||
The QEMU website is also maintained under source control.
|
||||
|
||||
@ -144,7 +144,7 @@ reported via GitLab.
|
||||
|
||||
For additional information on bug reporting consult:
|
||||
|
||||
* `<https://wiki.qemu.org/Contribute/ReportABug>`_
|
||||
* `<https://qemu.org/Contribute/ReportABug>`_
|
||||
|
||||
|
||||
ChangeLog
|
||||
@ -168,4 +168,4 @@ main methods being email and IRC
|
||||
Information on additional methods of contacting the community can be
|
||||
found online via the QEMU website:
|
||||
|
||||
* `<https://wiki.qemu.org/Contribute/StartHere>`_
|
||||
* `<https://qemu.org/Contribute/StartHere>`_
|
||||
|
@ -60,10 +60,6 @@
|
||||
|
||||
HVFState *hvf_state;
|
||||
|
||||
#ifdef __aarch64__
|
||||
#define HV_VM_DEFAULT NULL
|
||||
#endif
|
||||
|
||||
/* Memory slots */
|
||||
|
||||
hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size)
|
||||
@ -122,7 +118,6 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
|
||||
MemoryRegion *area = section->mr;
|
||||
bool writeable = !area->readonly && !area->rom_device;
|
||||
hv_memory_flags_t flags;
|
||||
uint64_t page_size = qemu_real_host_page_size;
|
||||
|
||||
if (!memory_region_is_ram(area)) {
|
||||
if (writeable) {
|
||||
@ -136,12 +131,6 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
|
||||
}
|
||||
}
|
||||
|
||||
if (!QEMU_IS_ALIGNED(int128_get64(section->size), page_size) ||
|
||||
!QEMU_IS_ALIGNED(section->offset_within_address_space, page_size)) {
|
||||
/* Not page aligned, so we can not map as RAM */
|
||||
add = false;
|
||||
}
|
||||
|
||||
mem = hvf_find_overlap_slot(
|
||||
section->offset_within_address_space,
|
||||
int128_get64(section->size));
|
||||
@ -250,12 +239,12 @@ static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on)
|
||||
if (on) {
|
||||
slot->flags |= HVF_SLOT_LOG;
|
||||
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
|
||||
HV_MEMORY_READ | HV_MEMORY_EXEC);
|
||||
HV_MEMORY_READ);
|
||||
/* stop tracking region*/
|
||||
} else {
|
||||
slot->flags &= ~HVF_SLOT_LOG;
|
||||
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
|
||||
HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC);
|
||||
HV_MEMORY_READ | HV_MEMORY_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -302,7 +291,6 @@ static void hvf_region_del(MemoryListener *listener,
|
||||
}
|
||||
|
||||
static MemoryListener hvf_memory_listener = {
|
||||
.name = "hvf",
|
||||
.priority = 10,
|
||||
.region_add = hvf_region_add,
|
||||
.region_del = hvf_region_del,
|
||||
@ -328,7 +316,7 @@ static int hvf_accel_init(MachineState *ms)
|
||||
|
||||
s = g_new0(HVFState, 1);
|
||||
|
||||
s->num_slots = ARRAY_SIZE(s->slots);
|
||||
s->num_slots = 32;
|
||||
for (x = 0; x < s->num_slots; ++x) {
|
||||
s->slots[x].size = 0;
|
||||
s->slots[x].slot_id = x;
|
||||
@ -336,8 +324,7 @@ static int hvf_accel_init(MachineState *ms)
|
||||
|
||||
hvf_state = s;
|
||||
memory_listener_register(&hvf_memory_listener, &address_space_memory);
|
||||
|
||||
return hvf_arch_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hvf_accel_class_init(ObjectClass *oc, void *data)
|
||||
@ -378,20 +365,17 @@ static int hvf_init_vcpu(CPUState *cpu)
|
||||
cpu->hvf = g_malloc0(sizeof(*cpu->hvf));
|
||||
|
||||
/* init cpu signals */
|
||||
sigset_t set;
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_handler = dummy_signal;
|
||||
sigaction(SIG_IPI, &sigact, NULL);
|
||||
|
||||
pthread_sigmask(SIG_BLOCK, NULL, &cpu->hvf->unblock_ipi_mask);
|
||||
sigdelset(&cpu->hvf->unblock_ipi_mask, SIG_IPI);
|
||||
pthread_sigmask(SIG_BLOCK, NULL, &set);
|
||||
sigdelset(&set, SIG_IPI);
|
||||
|
||||
#ifdef __aarch64__
|
||||
r = hv_vcpu_create(&cpu->hvf->fd, (hv_vcpu_exit_t **)&cpu->hvf->exit, NULL);
|
||||
#else
|
||||
r = hv_vcpu_create((hv_vcpuid_t *)&cpu->hvf->fd, HV_VCPU_DEFAULT);
|
||||
#endif
|
||||
cpu->vcpu_dirty = 1;
|
||||
assert_hvf_ok(r);
|
||||
|
||||
@ -467,7 +451,6 @@ static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
|
||||
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
|
||||
|
||||
ops->create_vcpu_thread = hvf_start_vcpu_thread;
|
||||
ops->kick_vcpu_thread = hvf_kick_vcpu_thread;
|
||||
|
||||
ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
|
||||
ops->synchronize_post_init = hvf_cpu_synchronize_post_init;
|
||||
|
@ -469,7 +469,6 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
|
||||
cpu->kvm_fd = ret;
|
||||
cpu->kvm_state = s;
|
||||
cpu->vcpu_dirty = true;
|
||||
cpu->dirty_pages = 0;
|
||||
|
||||
mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);
|
||||
if (mmap_size < 0) {
|
||||
@ -744,7 +743,6 @@ static uint32_t kvm_dirty_ring_reap_one(KVMState *s, CPUState *cpu)
|
||||
count++;
|
||||
}
|
||||
cpu->kvm_fetch_index = fetch;
|
||||
cpu->dirty_pages += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -1131,7 +1129,6 @@ static void kvm_coalesce_pio_del(MemoryListener *listener,
|
||||
}
|
||||
|
||||
static MemoryListener kvm_coalesced_pio_listener = {
|
||||
.name = "kvm-coalesced-pio",
|
||||
.coalesced_io_add = kvm_coalesce_pio_add,
|
||||
.coalesced_io_del = kvm_coalesce_pio_del,
|
||||
};
|
||||
@ -1636,7 +1633,7 @@ static void kvm_io_ioeventfd_del(MemoryListener *listener,
|
||||
}
|
||||
|
||||
void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
|
||||
AddressSpace *as, int as_id, const char *name)
|
||||
AddressSpace *as, int as_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -1652,7 +1649,6 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
|
||||
kml->listener.log_start = kvm_log_start;
|
||||
kml->listener.log_stop = kvm_log_stop;
|
||||
kml->listener.priority = 10;
|
||||
kml->listener.name = name;
|
||||
|
||||
if (s->kvm_dirty_ring_size) {
|
||||
kml->listener.log_sync_global = kvm_log_sync_global;
|
||||
@ -1673,7 +1669,6 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
|
||||
}
|
||||
|
||||
static MemoryListener kvm_io_listener = {
|
||||
.name = "kvm-io",
|
||||
.eventfd_add = kvm_io_ioeventfd_add,
|
||||
.eventfd_del = kvm_io_ioeventfd_del,
|
||||
.priority = 10,
|
||||
@ -2298,11 +2293,6 @@ bool kvm_vcpu_id_is_valid(int vcpu_id)
|
||||
return vcpu_id >= 0 && vcpu_id < kvm_max_vcpu_id(s);
|
||||
}
|
||||
|
||||
bool kvm_dirty_ring_enabled(void)
|
||||
{
|
||||
return kvm_state->kvm_dirty_ring_size ? true : false;
|
||||
}
|
||||
|
||||
static int kvm_init(MachineState *ms)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||
@ -2479,7 +2469,7 @@ static int kvm_init(MachineState *ms)
|
||||
ret = kvm_vm_enable_cap(s, KVM_CAP_DIRTY_LOG_RING, 0, ring_bytes);
|
||||
if (ret) {
|
||||
error_report("Enabling of KVM dirty ring failed: %s. "
|
||||
"Suggested minimum value is 1024.", strerror(-ret));
|
||||
"Suggested mininum value is 1024.", strerror(-ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -2589,7 +2579,7 @@ static int kvm_init(MachineState *ms)
|
||||
s->memory_listener.listener.coalesced_io_del = kvm_uncoalesce_mmio_region;
|
||||
|
||||
kvm_memory_listener_register(s, &s->memory_listener,
|
||||
&address_space_memory, 0, "kvm-memory");
|
||||
&address_space_memory, 0);
|
||||
if (kvm_eventfds_allowed) {
|
||||
memory_listener_register(&kvm_io_listener,
|
||||
&address_space_io);
|
||||
|
@ -3,5 +3,6 @@ kvm_ss.add(files(
|
||||
'kvm-all.c',
|
||||
'kvm-accel-ops.c',
|
||||
))
|
||||
kvm_ss.add(when: 'CONFIG_SEV', if_false: files('sev-stub.c'))
|
||||
|
||||
specific_ss.add_all(when: 'CONFIG_KVM', if_true: kvm_ss)
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "sev.h"
|
||||
#include "sysemu/sev.h"
|
||||
|
||||
int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
|
||||
{
|
@ -147,9 +147,4 @@ bool kvm_arm_supports_user_irq(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool kvm_dirty_ring_enabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
@ -13,43 +13,56 @@
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
static void atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
static uint16_t atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi)
|
||||
{
|
||||
CPUState *cpu = env_cpu(env);
|
||||
uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), false);
|
||||
|
||||
trace_guest_rmw_before_exec(cpu, addr, oi);
|
||||
trace_guest_mem_before_exec(cpu, addr, info);
|
||||
trace_guest_mem_before_exec(cpu, addr, info | TRACE_MEM_ST);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void atomic_trace_rmw_post(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
uint16_t info)
|
||||
{
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_RW);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info | TRACE_MEM_ST);
|
||||
}
|
||||
|
||||
#if HAVE_ATOMIC128
|
||||
static void atomic_trace_ld_pre(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
static uint16_t atomic_trace_ld_pre(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi)
|
||||
{
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), addr, info);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void atomic_trace_ld_post(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
uint16_t info)
|
||||
{
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
|
||||
}
|
||||
|
||||
static void atomic_trace_st_pre(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
static uint16_t atomic_trace_st_pre(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi)
|
||||
{
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), addr, info);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void atomic_trace_st_post(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
uint16_t info)
|
||||
{
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/plugin.h"
|
||||
#include "trace/mem.h"
|
||||
|
||||
#if DATA_SIZE == 16
|
||||
# define SUFFIX o
|
||||
@ -71,77 +72,77 @@
|
||||
|
||||
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
ABI_TYPE cmpv, ABI_TYPE newv,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_READ | PAGE_WRITE, retaddr);
|
||||
DATA_TYPE ret;
|
||||
uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, oi);
|
||||
#if DATA_SIZE == 16
|
||||
ret = atomic16_cmpxchg(haddr, cmpv, newv);
|
||||
#else
|
||||
ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv);
|
||||
#endif
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, oi);
|
||||
atomic_trace_rmw_post(env, addr, info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if DATA_SIZE >= 16
|
||||
#if HAVE_ATOMIC128
|
||||
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_READ, retaddr);
|
||||
DATA_TYPE val;
|
||||
uint16_t info = atomic_trace_ld_pre(env, addr, oi);
|
||||
|
||||
atomic_trace_ld_pre(env, addr, oi);
|
||||
val = atomic16_read(haddr);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_ld_post(env, addr, oi);
|
||||
atomic_trace_ld_post(env, addr, info);
|
||||
return val;
|
||||
}
|
||||
|
||||
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_WRITE, retaddr);
|
||||
uint16_t info = atomic_trace_st_pre(env, addr, oi);
|
||||
|
||||
atomic_trace_st_pre(env, addr, oi);
|
||||
atomic16_set(haddr, val);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_st_post(env, addr, oi);
|
||||
atomic_trace_st_post(env, addr, info);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_READ | PAGE_WRITE, retaddr);
|
||||
DATA_TYPE ret;
|
||||
uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, oi);
|
||||
ret = qatomic_xchg__nocheck(haddr, val);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, oi);
|
||||
atomic_trace_rmw_post(env, addr, info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define GEN_ATOMIC_HELPER(X) \
|
||||
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
|
||||
ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \
|
||||
{ \
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||
DATA_TYPE ret; \
|
||||
atomic_trace_rmw_pre(env, addr, oi); \
|
||||
uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
|
||||
ret = qatomic_##X(haddr, val); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, oi); \
|
||||
atomic_trace_rmw_post(env, addr, info); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
@ -166,12 +167,12 @@ GEN_ATOMIC_HELPER(xor_fetch)
|
||||
*/
|
||||
#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
|
||||
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
|
||||
ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \
|
||||
{ \
|
||||
XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||
XDATA_TYPE cmp, old, new, val = xval; \
|
||||
atomic_trace_rmw_pre(env, addr, oi); \
|
||||
uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
|
||||
smp_mb(); \
|
||||
cmp = qatomic_read__nocheck(haddr); \
|
||||
do { \
|
||||
@ -179,7 +180,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
cmp = qatomic_cmpxchg__nocheck(haddr, old, new); \
|
||||
} while (cmp != old); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, oi); \
|
||||
atomic_trace_rmw_post(env, addr, info); \
|
||||
return RET; \
|
||||
}
|
||||
|
||||
@ -210,78 +211,78 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
|
||||
|
||||
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
ABI_TYPE cmpv, ABI_TYPE newv,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_READ | PAGE_WRITE, retaddr);
|
||||
DATA_TYPE ret;
|
||||
uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, oi);
|
||||
#if DATA_SIZE == 16
|
||||
ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
|
||||
#else
|
||||
ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
|
||||
#endif
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, oi);
|
||||
atomic_trace_rmw_post(env, addr, info);
|
||||
return BSWAP(ret);
|
||||
}
|
||||
|
||||
#if DATA_SIZE >= 16
|
||||
#if HAVE_ATOMIC128
|
||||
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_READ, retaddr);
|
||||
DATA_TYPE val;
|
||||
uint16_t info = atomic_trace_ld_pre(env, addr, oi);
|
||||
|
||||
atomic_trace_ld_pre(env, addr, oi);
|
||||
val = atomic16_read(haddr);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_ld_post(env, addr, oi);
|
||||
atomic_trace_ld_post(env, addr, info);
|
||||
return BSWAP(val);
|
||||
}
|
||||
|
||||
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_WRITE, retaddr);
|
||||
uint16_t info = atomic_trace_st_pre(env, addr, oi);
|
||||
|
||||
atomic_trace_st_pre(env, addr, oi);
|
||||
val = BSWAP(val);
|
||||
atomic16_set(haddr, val);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_st_post(env, addr, oi);
|
||||
atomic_trace_st_post(env, addr, info);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_READ | PAGE_WRITE, retaddr);
|
||||
ABI_TYPE ret;
|
||||
uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, oi);
|
||||
ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, oi);
|
||||
atomic_trace_rmw_post(env, addr, info);
|
||||
return BSWAP(ret);
|
||||
}
|
||||
|
||||
#define GEN_ATOMIC_HELPER(X) \
|
||||
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
|
||||
ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \
|
||||
{ \
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||
DATA_TYPE ret; \
|
||||
atomic_trace_rmw_pre(env, addr, oi); \
|
||||
uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
|
||||
ret = qatomic_##X(haddr, BSWAP(val)); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, oi); \
|
||||
atomic_trace_rmw_post(env, addr, info); \
|
||||
return BSWAP(ret); \
|
||||
}
|
||||
|
||||
@ -303,12 +304,12 @@ GEN_ATOMIC_HELPER(xor_fetch)
|
||||
*/
|
||||
#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
|
||||
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
|
||||
ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \
|
||||
{ \
|
||||
XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||
XDATA_TYPE ldo, ldn, old, new, val = xval; \
|
||||
atomic_trace_rmw_pre(env, addr, oi); \
|
||||
uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
|
||||
smp_mb(); \
|
||||
ldn = qatomic_read__nocheck(haddr); \
|
||||
do { \
|
||||
@ -316,7 +317,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \
|
||||
} while (ldo != ldn); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, oi); \
|
||||
atomic_trace_rmw_post(env, addr, info); \
|
||||
return RET; \
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-machine.h"
|
||||
#include "qapi/type-helpers.h"
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
#include "trace.h"
|
||||
#include "disas/disas.h"
|
||||
@ -41,7 +38,6 @@
|
||||
#include "exec/cpu-all.h"
|
||||
#include "sysemu/cpu-timers.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "sysemu/tcg.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "tb-hash.h"
|
||||
#include "tb-context.h"
|
||||
@ -387,17 +383,6 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
|
||||
cc->set_pc(cpu, last_tb->pc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If gdb single-step, and we haven't raised another exception,
|
||||
* raise a debug exception. Single-step with another exception
|
||||
* is handled in cpu_handle_exception.
|
||||
*/
|
||||
if (unlikely(cpu->singlestep_enabled) && cpu->exception_index == -1) {
|
||||
cpu->exception_index = EXCP_DEBUG;
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
|
||||
return last_tb;
|
||||
}
|
||||
|
||||
@ -466,7 +451,6 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
||||
* memory.
|
||||
*/
|
||||
#ifndef CONFIG_SOFTMMU
|
||||
clear_helper_retaddr();
|
||||
tcg_debug_assert(!have_mmap_lock());
|
||||
#endif
|
||||
if (qemu_mutex_iothread_locked()) {
|
||||
@ -476,6 +460,7 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
||||
qemu_plugin_disable_mem_helpers(cpu);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* As we start the exclusive region before codegen we must still
|
||||
* be in the region if we longjump out of either the codegen or
|
||||
@ -603,9 +588,8 @@ static inline void tb_add_jump(TranslationBlock *tb, int n,
|
||||
|
||||
static inline bool cpu_handle_halt(CPUState *cpu)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (cpu->halted) {
|
||||
#if defined(TARGET_I386)
|
||||
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
|
||||
if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
|
||||
X86CPU *x86_cpu = X86_CPU(cpu);
|
||||
qemu_mutex_lock_iothread();
|
||||
@ -613,14 +597,13 @@ static inline bool cpu_handle_halt(CPUState *cpu)
|
||||
cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
#endif /* TARGET_I386 */
|
||||
#endif
|
||||
if (!cpu_has_work(cpu)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cpu->halted = 0;
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -643,6 +626,18 @@ static inline void cpu_handle_debug_exception(CPUState *cpu)
|
||||
|
||||
static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
||||
{
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
#define EXCP_LIBAFL_BP 0xf4775747
|
||||
|
||||
if (cpu->exception_index == EXCP_LIBAFL_BP) {
|
||||
*ret = cpu->exception_index;
|
||||
cpu->exception_index = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
if (cpu->exception_index < 0) {
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (replay_has_exception()
|
||||
@ -668,8 +663,8 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
||||
loop */
|
||||
#if defined(TARGET_I386)
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
cc->tcg_ops->fake_user_interrupt(cpu);
|
||||
#endif /* TARGET_I386 */
|
||||
cc->tcg_ops->do_interrupt(cpu);
|
||||
#endif
|
||||
*ret = cpu->exception_index;
|
||||
cpu->exception_index = -1;
|
||||
return true;
|
||||
@ -702,7 +697,6 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/*
|
||||
* CPU_INTERRUPT_POLL is a virtual event which gets converted into a
|
||||
* "real" interrupt event later. It does not need to be recorded for
|
||||
@ -716,19 +710,11 @@ static inline bool need_replay_interrupt(int interrupt_request)
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||
TranslationBlock **last_tb)
|
||||
{
|
||||
/*
|
||||
* If we have requested custom cflags with CF_NOIRQ we should
|
||||
* skip checking here. Any pending interrupts will get picked up
|
||||
* by the next TB we execute under normal cflags.
|
||||
*/
|
||||
if (cpu->cflags_next_tb != -1 && cpu->cflags_next_tb & CF_NOIRQ) {
|
||||
return false;
|
||||
}
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
/* Clear the interrupt flag now since we're processing
|
||||
* cpu->interrupt_request and cpu->exit_request.
|
||||
@ -751,7 +737,6 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||
qemu_mutex_unlock_iothread();
|
||||
return true;
|
||||
}
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (replay_mode == REPLAY_MODE_PLAY && !replay_has_interrupt()) {
|
||||
/* Do nothing */
|
||||
} else if (interrupt_request & CPU_INTERRUPT_HALT) {
|
||||
@ -780,14 +765,12 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||
qemu_mutex_unlock_iothread();
|
||||
return true;
|
||||
}
|
||||
#endif /* !TARGET_I386 */
|
||||
#endif
|
||||
/* The target hook has 3 exit conditions:
|
||||
False when the interrupt isn't processed,
|
||||
True when it is, and we should restart on a new TB,
|
||||
and via longjmp via cpu_loop_exit. */
|
||||
else {
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
if (cc->tcg_ops->cpu_exec_interrupt &&
|
||||
cc->tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) {
|
||||
if (need_replay_interrupt(interrupt_request)) {
|
||||
@ -806,7 +789,6 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||
* reload the 'interrupt_request' value */
|
||||
interrupt_request = cpu->interrupt_request;
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
if (interrupt_request & CPU_INTERRUPT_EXITTB) {
|
||||
cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
|
||||
/* ensure that no TB jump will be modified as
|
||||
@ -881,6 +863,15 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
#endif
|
||||
}
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
|
||||
target_ulong dst_block, target_ulong cs_base,
|
||||
uint32_t flags, int cflags);
|
||||
void libafl_exec_edge_one_off(target_ulong src_block, target_ulong dst_block);
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
/* main execution loop */
|
||||
|
||||
int cpu_exec(CPUState *cpu)
|
||||
@ -929,7 +920,6 @@ int cpu_exec(CPUState *cpu)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SOFTMMU
|
||||
clear_helper_retaddr();
|
||||
tcg_debug_assert(!have_mmap_lock());
|
||||
#endif
|
||||
if (qemu_mutex_iothread_locked()) {
|
||||
@ -981,6 +971,12 @@ int cpu_exec(CPUState *cpu)
|
||||
*/
|
||||
qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb);
|
||||
}
|
||||
//// --- Begin LibAFL code ---
|
||||
// This will save an edge (0,pc) after interrupts
|
||||
// if (!last_tb) {
|
||||
// libafl_exec_edge_one_off(0, tb->pc);
|
||||
// }
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/*
|
||||
@ -995,8 +991,28 @@ int cpu_exec(CPUState *cpu)
|
||||
#endif
|
||||
/* See if we can patch the calling TB. */
|
||||
if (last_tb) {
|
||||
// tb_add_jump(last_tb, tb_exit, tb);
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
if (last_tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) {
|
||||
mmap_lock();
|
||||
TranslationBlock *edge = libafl_gen_edge(cpu, last_tb->pc, tb->pc,
|
||||
cs_base, flags, cflags);
|
||||
mmap_unlock();
|
||||
|
||||
if (edge) {
|
||||
tb_add_jump(last_tb, tb_exit, edge);
|
||||
tb_add_jump(edge, 0, tb);
|
||||
} else {
|
||||
tb_add_jump(last_tb, tb_exit, tb);
|
||||
}
|
||||
} else {
|
||||
tb_add_jump(last_tb, tb_exit, tb);
|
||||
}
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
}
|
||||
|
||||
cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit);
|
||||
|
||||
@ -1042,52 +1058,23 @@ void tcg_exec_unrealizefn(CPUState *cpu)
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
void dump_drift_info(GString *buf)
|
||||
void dump_drift_info(void)
|
||||
{
|
||||
if (!icount_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_string_append_printf(buf, "Host - Guest clock %"PRIi64" ms\n",
|
||||
qemu_printf("Host - Guest clock %"PRIi64" ms\n",
|
||||
(cpu_get_clock() - icount_get()) / SCALE_MS);
|
||||
if (icount_align_option) {
|
||||
g_string_append_printf(buf, "Max guest delay %"PRIi64" ms\n",
|
||||
qemu_printf("Max guest delay %"PRIi64" ms\n",
|
||||
-max_delay / SCALE_MS);
|
||||
g_string_append_printf(buf, "Max guest advance %"PRIi64" ms\n",
|
||||
qemu_printf("Max guest advance %"PRIi64" ms\n",
|
||||
max_advance / SCALE_MS);
|
||||
} else {
|
||||
g_string_append_printf(buf, "Max guest delay NA\n");
|
||||
g_string_append_printf(buf, "Max guest advance NA\n");
|
||||
qemu_printf("Max guest delay NA\n");
|
||||
qemu_printf("Max guest advance NA\n");
|
||||
}
|
||||
}
|
||||
|
||||
HumanReadableText *qmp_x_query_jit(Error **errp)
|
||||
{
|
||||
g_autoptr(GString) buf = g_string_new("");
|
||||
|
||||
if (!tcg_enabled()) {
|
||||
error_setg(errp, "JIT information is only available with accel=tcg");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dump_exec_info(buf);
|
||||
dump_drift_info(buf);
|
||||
|
||||
return human_readable_text_from_str(buf);
|
||||
}
|
||||
|
||||
HumanReadableText *qmp_x_query_opcount(Error **errp)
|
||||
{
|
||||
g_autoptr(GString) buf = g_string_new("");
|
||||
|
||||
if (!tcg_enabled()) {
|
||||
error_setg(errp, "Opcode count information is only available with accel=tcg");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dump_opcount_info(buf);
|
||||
|
||||
return human_readable_text_from_str(buf);
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
@ -34,12 +34,12 @@
|
||||
#include "qemu/atomic128.h"
|
||||
#include "exec/translate-all.h"
|
||||
#include "trace/trace-root.h"
|
||||
#include "trace/mem.h"
|
||||
#include "tb-hash.h"
|
||||
#include "internal.h"
|
||||
#ifdef CONFIG_PLUGIN
|
||||
#include "qemu/plugin-memory.h"
|
||||
#endif
|
||||
#include "tcg/tcg-ldst.h"
|
||||
|
||||
/* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */
|
||||
/* #define DEBUG_TLB */
|
||||
@ -1749,7 +1749,7 @@ bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx,
|
||||
* @prot may be PAGE_READ, PAGE_WRITE, or PAGE_READ|PAGE_WRITE.
|
||||
*/
|
||||
static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, int size, int prot,
|
||||
TCGMemOpIdx oi, int size, int prot,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
size_t mmu_idx = get_mmuidx(oi);
|
||||
@ -1840,25 +1840,6 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
|
||||
cpu_loop_exit_atomic(env_cpu(env), retaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that we have passed the correct MemOp to the correct function.
|
||||
*
|
||||
* In the case of the helper_*_mmu functions, we will have done this by
|
||||
* using the MemOp to look up the helper during code generation.
|
||||
*
|
||||
* In the case of the cpu_*_mmu functions, this is up to the caller.
|
||||
* We could present one function to target code, and dispatch based on
|
||||
* the MemOp, but so far we have worked hard to avoid an indirect function
|
||||
* call along the memory path.
|
||||
*/
|
||||
static void validate_memop(MemOpIdx oi, MemOp expected)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_TCG
|
||||
MemOp have = get_memop(oi) & (MO_SIZE | MO_BSWAP);
|
||||
assert(have == expected);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Load Helpers
|
||||
*
|
||||
@ -1869,7 +1850,7 @@ static void validate_memop(MemOpIdx oi, MemOp expected)
|
||||
*/
|
||||
|
||||
typedef uint64_t FullLoadHelper(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr);
|
||||
TCGMemOpIdx oi, uintptr_t retaddr);
|
||||
|
||||
static inline uint64_t QEMU_ALWAYS_INLINE
|
||||
load_memop(const void *haddr, MemOp op)
|
||||
@ -1895,7 +1876,7 @@ load_memop(const void *haddr, MemOp op)
|
||||
}
|
||||
|
||||
static inline uint64_t QEMU_ALWAYS_INLINE
|
||||
load_helper(CPUArchState *env, target_ulong addr, MemOpIdx oi,
|
||||
load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
|
||||
uintptr_t retaddr, MemOp op, bool code_read,
|
||||
FullLoadHelper *full_load)
|
||||
{
|
||||
@ -2010,86 +1991,79 @@ load_helper(CPUArchState *env, target_ulong addr, MemOpIdx oi,
|
||||
*/
|
||||
|
||||
static uint64_t full_ldub_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_UB);
|
||||
return load_helper(env, addr, oi, retaddr, MO_UB, false, full_ldub_mmu);
|
||||
}
|
||||
|
||||
tcg_target_ulong helper_ret_ldub_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return full_ldub_mmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
static uint64_t full_le_lduw_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_LEUW);
|
||||
return load_helper(env, addr, oi, retaddr, MO_LEUW, false,
|
||||
full_le_lduw_mmu);
|
||||
}
|
||||
|
||||
tcg_target_ulong helper_le_lduw_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return full_le_lduw_mmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
static uint64_t full_be_lduw_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_BEUW);
|
||||
return load_helper(env, addr, oi, retaddr, MO_BEUW, false,
|
||||
full_be_lduw_mmu);
|
||||
}
|
||||
|
||||
tcg_target_ulong helper_be_lduw_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return full_be_lduw_mmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
static uint64_t full_le_ldul_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_LEUL);
|
||||
return load_helper(env, addr, oi, retaddr, MO_LEUL, false,
|
||||
full_le_ldul_mmu);
|
||||
}
|
||||
|
||||
tcg_target_ulong helper_le_ldul_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return full_le_ldul_mmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
static uint64_t full_be_ldul_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_BEUL);
|
||||
return load_helper(env, addr, oi, retaddr, MO_BEUL, false,
|
||||
full_be_ldul_mmu);
|
||||
}
|
||||
|
||||
tcg_target_ulong helper_be_ldul_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return full_be_ldul_mmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
uint64_t helper_le_ldq_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_LEQ);
|
||||
return load_helper(env, addr, oi, retaddr, MO_LEQ, false,
|
||||
helper_le_ldq_mmu);
|
||||
}
|
||||
|
||||
uint64_t helper_be_ldq_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_BEQ);
|
||||
return load_helper(env, addr, oi, retaddr, MO_BEQ, false,
|
||||
helper_be_ldq_mmu);
|
||||
}
|
||||
@ -2101,31 +2075,31 @@ uint64_t helper_be_ldq_mmu(CPUArchState *env, target_ulong addr,
|
||||
|
||||
|
||||
tcg_target_ulong helper_ret_ldsb_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return (int8_t)helper_ret_ldub_mmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
tcg_target_ulong helper_le_ldsw_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return (int16_t)helper_le_lduw_mmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
tcg_target_ulong helper_be_ldsw_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return (int16_t)helper_be_lduw_mmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
tcg_target_ulong helper_le_ldsl_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return (int32_t)helper_le_ldul_mmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
tcg_target_ulong helper_be_ldsl_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return (int32_t)helper_be_ldul_mmu(env, addr, oi, retaddr);
|
||||
}
|
||||
@ -2135,56 +2109,193 @@ tcg_target_ulong helper_be_ldsl_mmu(CPUArchState *env, target_ulong addr,
|
||||
*/
|
||||
|
||||
static inline uint64_t cpu_load_helper(CPUArchState *env, abi_ptr addr,
|
||||
MemOpIdx oi, uintptr_t retaddr,
|
||||
FullLoadHelper *full_load)
|
||||
int mmu_idx, uintptr_t retaddr,
|
||||
MemOp op, FullLoadHelper *full_load)
|
||||
{
|
||||
uint16_t meminfo;
|
||||
TCGMemOpIdx oi;
|
||||
uint64_t ret;
|
||||
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
meminfo = trace_mem_get_info(op, mmu_idx, false);
|
||||
trace_guest_mem_before_exec(env_cpu(env), addr, meminfo);
|
||||
|
||||
op &= ~MO_SIGN;
|
||||
oi = make_memop_idx(op, mmu_idx);
|
||||
ret = full_load(env, addr, oi, retaddr);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
|
||||
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, meminfo);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra)
|
||||
uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return cpu_load_helper(env, addr, oi, ra, full_ldub_mmu);
|
||||
return cpu_load_helper(env, addr, mmu_idx, ra, MO_UB, full_ldub_mmu);
|
||||
}
|
||||
|
||||
uint16_t cpu_ldw_be_mmu(CPUArchState *env, abi_ptr addr,
|
||||
MemOpIdx oi, uintptr_t ra)
|
||||
int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return cpu_load_helper(env, addr, oi, ra, full_be_lduw_mmu);
|
||||
return (int8_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_SB,
|
||||
full_ldub_mmu);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_be_mmu(CPUArchState *env, abi_ptr addr,
|
||||
MemOpIdx oi, 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, oi, ra, full_be_ldul_mmu);
|
||||
return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEUW, full_be_lduw_mmu);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_be_mmu(CPUArchState *env, abi_ptr addr,
|
||||
MemOpIdx oi, uintptr_t ra)
|
||||
int cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return cpu_load_helper(env, addr, oi, MO_BEQ, helper_be_ldq_mmu);
|
||||
return (int16_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_BESW,
|
||||
full_be_lduw_mmu);
|
||||
}
|
||||
|
||||
uint16_t cpu_ldw_le_mmu(CPUArchState *env, abi_ptr addr,
|
||||
MemOpIdx oi, 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, oi, ra, full_le_lduw_mmu);
|
||||
return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEUL, full_be_ldul_mmu);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_le_mmu(CPUArchState *env, abi_ptr addr,
|
||||
MemOpIdx oi, 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, oi, ra, full_le_ldul_mmu);
|
||||
return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEQ, helper_be_ldq_mmu);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_le_mmu(CPUArchState *env, abi_ptr addr,
|
||||
MemOpIdx oi, uintptr_t ra)
|
||||
uint32_t cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return cpu_load_helper(env, addr, oi, ra, helper_le_ldq_mmu);
|
||||
return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEUW, full_le_lduw_mmu);
|
||||
}
|
||||
|
||||
int cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return (int16_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_LESW,
|
||||
full_le_lduw_mmu);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEUL, full_le_ldul_mmu);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEQ, helper_le_ldq_mmu);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldub_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
return cpu_ldub_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
int cpu_ldsb_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
|
||||
{
|
||||
return cpu_ldsb_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_be_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
return cpu_lduw_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
int cpu_ldsw_be_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
|
||||
{
|
||||
return cpu_ldsw_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_be_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
return cpu_ldl_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_be_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
return cpu_ldq_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_le_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
return cpu_lduw_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
int cpu_ldsw_le_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
|
||||
{
|
||||
return cpu_ldsw_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_le_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
return cpu_ldl_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_le_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
return cpu_ldq_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldub_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_ldub_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
int cpu_ldsb_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_ldsb_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_be_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_lduw_be_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
int cpu_ldsw_be_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_ldsw_be_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_be_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_ldl_be_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_be_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_ldq_be_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_le_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_lduw_le_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
int cpu_ldsw_le_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_ldsw_le_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_le_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_ldl_le_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_le_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_ldq_le_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2221,9 +2332,6 @@ store_memop(void *haddr, uint64_t val, MemOp op)
|
||||
}
|
||||
}
|
||||
|
||||
static void full_stb_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr);
|
||||
|
||||
static void __attribute__((noinline))
|
||||
store_helper_unaligned(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
uintptr_t retaddr, size_t size, uintptr_t mmu_idx,
|
||||
@ -2233,7 +2341,7 @@ store_helper_unaligned(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
uintptr_t index, index2;
|
||||
CPUTLBEntry *entry, *entry2;
|
||||
target_ulong page2, tlb_addr, tlb_addr2;
|
||||
MemOpIdx oi;
|
||||
TCGMemOpIdx oi;
|
||||
size_t size2;
|
||||
int i;
|
||||
|
||||
@ -2287,20 +2395,20 @@ store_helper_unaligned(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
for (i = 0; i < size; ++i) {
|
||||
/* Big-endian extract. */
|
||||
uint8_t val8 = val >> (((size - 1) * 8) - (i * 8));
|
||||
full_stb_mmu(env, addr + i, val8, oi, retaddr);
|
||||
helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < size; ++i) {
|
||||
/* Little-endian extract. */
|
||||
uint8_t val8 = val >> (i * 8);
|
||||
full_stb_mmu(env, addr + i, val8, oi, retaddr);
|
||||
helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void QEMU_ALWAYS_INLINE
|
||||
store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr, MemOp op)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr, MemOp op)
|
||||
{
|
||||
uintptr_t mmu_idx = get_mmuidx(oi);
|
||||
uintptr_t index = tlb_index(env, mmu_idx, addr);
|
||||
@ -2396,83 +2504,46 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
store_memop(haddr, val, op);
|
||||
}
|
||||
|
||||
static void __attribute__((noinline))
|
||||
full_stb_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
void __attribute__((noinline))
|
||||
helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_UB);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_UB);
|
||||
}
|
||||
|
||||
void helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
void helper_le_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
full_stb_mmu(env, addr, val, oi, retaddr);
|
||||
}
|
||||
|
||||
static void full_le_stw_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_LEUW);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_LEUW);
|
||||
}
|
||||
|
||||
void helper_le_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
void helper_be_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
full_le_stw_mmu(env, addr, val, oi, retaddr);
|
||||
}
|
||||
|
||||
static void full_be_stw_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_BEUW);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_BEUW);
|
||||
}
|
||||
|
||||
void helper_be_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
void helper_le_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
full_be_stw_mmu(env, addr, val, oi, retaddr);
|
||||
}
|
||||
|
||||
static void full_le_stl_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_LEUL);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_LEUL);
|
||||
}
|
||||
|
||||
void helper_le_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
void helper_be_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
full_le_stl_mmu(env, addr, val, oi, retaddr);
|
||||
}
|
||||
|
||||
static void full_be_stl_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_BEUL);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_BEUL);
|
||||
}
|
||||
|
||||
void helper_be_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
full_be_stl_mmu(env, addr, val, oi, retaddr);
|
||||
}
|
||||
|
||||
void helper_le_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_LEQ);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_LEQ);
|
||||
}
|
||||
|
||||
void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_BEQ);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_BEQ);
|
||||
}
|
||||
|
||||
@ -2480,61 +2551,140 @@ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
* Store Helpers for cpu_ldst.h
|
||||
*/
|
||||
|
||||
typedef void FullStoreHelper(CPUArchState *env, target_ulong addr,
|
||||
uint64_t val, MemOpIdx oi, uintptr_t retaddr);
|
||||
|
||||
static inline void cpu_store_helper(CPUArchState *env, target_ulong addr,
|
||||
uint64_t val, MemOpIdx oi, uintptr_t ra,
|
||||
FullStoreHelper *full_store)
|
||||
static inline void QEMU_ALWAYS_INLINE
|
||||
cpu_store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
int mmu_idx, uintptr_t retaddr, MemOp op)
|
||||
{
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
full_store(env, addr, val, oi, ra);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W);
|
||||
TCGMemOpIdx oi;
|
||||
uint16_t meminfo;
|
||||
|
||||
meminfo = trace_mem_get_info(op, mmu_idx, true);
|
||||
trace_guest_mem_before_exec(env_cpu(env), addr, meminfo);
|
||||
|
||||
oi = make_memop_idx(op, mmu_idx);
|
||||
store_helper(env, addr, val, oi, retaddr, op);
|
||||
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, meminfo);
|
||||
}
|
||||
|
||||
void cpu_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
void cpu_stb_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
cpu_store_helper(env, addr, val, oi, retaddr, full_stb_mmu);
|
||||
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_UB);
|
||||
}
|
||||
|
||||
void cpu_stw_be_mmu(CPUArchState *env, target_ulong addr, uint16_t val,
|
||||
MemOpIdx oi, 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, oi, retaddr, full_be_stw_mmu);
|
||||
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEUW);
|
||||
}
|
||||
|
||||
void cpu_stl_be_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
|
||||
MemOpIdx oi, 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, oi, retaddr, full_be_stl_mmu);
|
||||
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEUL);
|
||||
}
|
||||
|
||||
void cpu_stq_be_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, 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, oi, retaddr, helper_be_stq_mmu);
|
||||
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEQ);
|
||||
}
|
||||
|
||||
void cpu_stw_le_mmu(CPUArchState *env, target_ulong addr, uint16_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
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, oi, retaddr, full_le_stw_mmu);
|
||||
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEUW);
|
||||
}
|
||||
|
||||
void cpu_stl_le_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
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, oi, retaddr, full_le_stl_mmu);
|
||||
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEUL);
|
||||
}
|
||||
|
||||
void cpu_stq_le_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
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, oi, retaddr, helper_le_stq_mmu);
|
||||
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEQ);
|
||||
}
|
||||
|
||||
#include "ldst_common.c.inc"
|
||||
void cpu_stb_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
cpu_stb_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
void cpu_stw_be_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
cpu_stw_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
void cpu_stl_be_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
cpu_stl_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
void cpu_stq_be_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uint64_t val, uintptr_t retaddr)
|
||||
{
|
||||
cpu_stq_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
void cpu_stw_le_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
cpu_stw_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
void cpu_stl_le_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
cpu_stl_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
void cpu_stq_le_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uint64_t val, uintptr_t retaddr)
|
||||
{
|
||||
cpu_stq_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
void cpu_stb_data(CPUArchState *env, target_ulong ptr, uint32_t val)
|
||||
{
|
||||
cpu_stb_data_ra(env, ptr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stw_be_data(CPUArchState *env, target_ulong ptr, uint32_t val)
|
||||
{
|
||||
cpu_stw_be_data_ra(env, ptr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stl_be_data(CPUArchState *env, target_ulong ptr, uint32_t val)
|
||||
{
|
||||
cpu_stl_be_data_ra(env, ptr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stq_be_data(CPUArchState *env, target_ulong ptr, uint64_t val)
|
||||
{
|
||||
cpu_stq_be_data_ra(env, ptr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stw_le_data(CPUArchState *env, target_ulong ptr, uint32_t val)
|
||||
{
|
||||
cpu_stw_le_data_ra(env, ptr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stl_le_data(CPUArchState *env, target_ulong ptr, uint32_t val)
|
||||
{
|
||||
cpu_stl_le_data_ra(env, ptr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stq_le_data(CPUArchState *env, target_ulong ptr, uint64_t val)
|
||||
{
|
||||
cpu_stq_le_data_ra(env, ptr, val, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* First set of functions passes in OI and RETADDR.
|
||||
@ -2571,49 +2721,49 @@ void cpu_stq_le_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
/* Code access functions. */
|
||||
|
||||
static uint64_t full_ldub_code(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_8, true, full_ldub_code);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_UB, cpu_mmu_index(env, true));
|
||||
TCGMemOpIdx oi = make_memop_idx(MO_UB, cpu_mmu_index(env, true));
|
||||
return full_ldub_code(env, addr, oi, 0);
|
||||
}
|
||||
|
||||
static uint64_t full_lduw_code(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_TEUW, true, full_lduw_code);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_TEUW, cpu_mmu_index(env, true));
|
||||
TCGMemOpIdx oi = make_memop_idx(MO_TEUW, cpu_mmu_index(env, true));
|
||||
return full_lduw_code(env, addr, oi, 0);
|
||||
}
|
||||
|
||||
static uint64_t full_ldl_code(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_TEUL, true, full_ldl_code);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_TEUL, cpu_mmu_index(env, true));
|
||||
TCGMemOpIdx oi = make_memop_idx(MO_TEUL, cpu_mmu_index(env, true));
|
||||
return full_ldl_code(env, addr, oi, 0);
|
||||
}
|
||||
|
||||
static uint64_t full_ldq_code(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_TEQ, true, full_ldq_code);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_TEQ, cpu_mmu_index(env, true));
|
||||
TCGMemOpIdx oi = make_memop_idx(MO_TEQ, cpu_mmu_index(env, true));
|
||||
return full_ldq_code(env, addr, oi, 0);
|
||||
}
|
||||
|
@ -1,15 +1,29 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-machine.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "sysemu/tcg.h"
|
||||
|
||||
static void hmp_info_jit(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
if (!tcg_enabled()) {
|
||||
error_report("JIT information is only available with accel=tcg");
|
||||
return;
|
||||
}
|
||||
|
||||
dump_exec_info();
|
||||
dump_drift_info();
|
||||
}
|
||||
|
||||
static void hmp_info_opcount(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
dump_opcount_info();
|
||||
}
|
||||
|
||||
static void hmp_tcg_register(void)
|
||||
{
|
||||
monitor_register_hmp_info_hrt("jit", qmp_x_query_jit);
|
||||
monitor_register_hmp_info_hrt("opcount", qmp_x_query_opcount);
|
||||
monitor_register_hmp("jit", true, hmp_info_jit);
|
||||
monitor_register_hmp("opcount", true, hmp_info_opcount);
|
||||
}
|
||||
|
||||
type_init(hmp_tcg_register);
|
||||
|
@ -1,307 +0,0 @@
|
||||
/*
|
||||
* Routines common to user and system emulation of load/store.
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
|
||||
return cpu_ldb_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return (int8_t)cpu_ldub_mmuidx_ra(env, addr, mmu_idx, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx);
|
||||
return cpu_ldw_be_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
int cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return (int16_t)cpu_lduw_be_mmuidx_ra(env, addr, mmu_idx, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx);
|
||||
return cpu_ldl_be_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEQ | MO_UNALN, mmu_idx);
|
||||
return cpu_ldq_be_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx);
|
||||
return cpu_ldw_le_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
int cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return (int16_t)cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx);
|
||||
return cpu_ldl_le_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEQ | MO_UNALN, mmu_idx);
|
||||
return cpu_ldq_le_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stb_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
|
||||
cpu_stb_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx);
|
||||
cpu_stw_be_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx);
|
||||
cpu_stl_be_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEQ | MO_UNALN, mmu_idx);
|
||||
cpu_stq_be_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx);
|
||||
cpu_stw_le_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx);
|
||||
cpu_stl_le_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEQ | MO_UNALN, mmu_idx);
|
||||
cpu_stq_le_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
/*--------------------------*/
|
||||
|
||||
uint32_t cpu_ldub_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_ldub_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
int cpu_ldsb_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return (int8_t)cpu_ldub_data_ra(env, addr, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_lduw_be_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
int cpu_ldsw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return (int16_t)cpu_lduw_be_data_ra(env, addr, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_ldl_be_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_ldq_be_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_lduw_le_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
int cpu_ldsw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return (int16_t)cpu_lduw_le_data_ra(env, addr, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_ldl_le_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_ldq_le_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stb_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint32_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stb_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stw_be_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint32_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stw_be_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stl_be_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint32_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stl_be_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stq_be_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint64_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stq_be_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stw_le_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint32_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stw_le_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stl_le_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint32_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stl_le_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stq_le_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint64_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stq_le_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
/*--------------------------*/
|
||||
|
||||
uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_ldub_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
int cpu_ldsb_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return (int8_t)cpu_ldub_data(env, addr);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_be_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_lduw_be_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
int cpu_ldsw_be_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return (int16_t)cpu_lduw_be_data(env, addr);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_be_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_ldl_be_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_be_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_ldq_be_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_le_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_lduw_le_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
int cpu_ldsw_le_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return (int16_t)cpu_lduw_le_data(env, addr);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_le_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_ldl_le_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_le_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_ldq_le_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
void cpu_stb_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
||||
{
|
||||
cpu_stb_data_ra(env, addr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stw_be_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
||||
{
|
||||
cpu_stw_be_data_ra(env, addr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stl_be_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
||||
{
|
||||
cpu_stl_be_data_ra(env, addr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stq_be_data(CPUArchState *env, abi_ptr addr, uint64_t val)
|
||||
{
|
||||
cpu_stq_be_data_ra(env, addr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stw_le_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
||||
{
|
||||
cpu_stw_le_data_ra(env, addr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stl_le_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
||||
{
|
||||
cpu_stl_le_data_ra(env, addr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stq_le_data(CPUArchState *env, abi_ptr addr, uint64_t val)
|
||||
{
|
||||
cpu_stq_le_data_ra(env, addr, val, 0);
|
||||
}
|
@ -10,7 +10,7 @@ tcg_ss.add(files(
|
||||
))
|
||||
tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c'))
|
||||
tcg_ss.add(when: 'CONFIG_SOFTMMU', if_false: files('user-exec-stub.c'))
|
||||
tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c')])
|
||||
tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c'), libdl])
|
||||
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
|
||||
|
||||
specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "trace/mem.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/plugin-gen.h"
|
||||
#include "exec/translator.h"
|
||||
@ -162,7 +163,11 @@ static void gen_empty_mem_helper(void)
|
||||
static void gen_plugin_cb_start(enum plugin_gen_from from,
|
||||
enum plugin_gen_cb type, unsigned wr)
|
||||
{
|
||||
TCGOp *op;
|
||||
|
||||
tcg_gen_plugin_cb_start(from, type, wr);
|
||||
op = tcg_last_op();
|
||||
QSIMPLEQ_INSERT_TAIL(&tcg_ctx->plugin_ops, op, plugin_link);
|
||||
}
|
||||
|
||||
static void gen_wrapped(enum plugin_gen_from from,
|
||||
@ -206,9 +211,9 @@ static void gen_mem_wrapped(enum plugin_gen_cb type,
|
||||
const union mem_gen_fn *f, TCGv addr,
|
||||
uint32_t info, bool is_mem)
|
||||
{
|
||||
enum qemu_plugin_mem_rw rw = get_plugin_meminfo_rw(info);
|
||||
int wr = !!(info & TRACE_MEM_ST);
|
||||
|
||||
gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, type, rw);
|
||||
gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, type, wr);
|
||||
if (is_mem) {
|
||||
f->mem_fn(addr, info);
|
||||
} else {
|
||||
@ -702,6 +707,62 @@ static void plugin_gen_disable_mem_helper(const struct qemu_plugin_tb *ptb,
|
||||
inject_mem_disable_helper(insn, begin_op);
|
||||
}
|
||||
|
||||
static void plugin_inject_cb(const struct qemu_plugin_tb *ptb, TCGOp *begin_op,
|
||||
int insn_idx)
|
||||
{
|
||||
enum plugin_gen_from from = begin_op->args[0];
|
||||
enum plugin_gen_cb type = begin_op->args[1];
|
||||
|
||||
switch (from) {
|
||||
case PLUGIN_GEN_FROM_TB:
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_CB_UDATA:
|
||||
plugin_gen_tb_udata(ptb, begin_op);
|
||||
return;
|
||||
case PLUGIN_GEN_CB_INLINE:
|
||||
plugin_gen_tb_inline(ptb, begin_op);
|
||||
return;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
case PLUGIN_GEN_FROM_INSN:
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_CB_UDATA:
|
||||
plugin_gen_insn_udata(ptb, begin_op, insn_idx);
|
||||
return;
|
||||
case PLUGIN_GEN_CB_INLINE:
|
||||
plugin_gen_insn_inline(ptb, begin_op, insn_idx);
|
||||
return;
|
||||
case PLUGIN_GEN_ENABLE_MEM_HELPER:
|
||||
plugin_gen_enable_mem_helper(ptb, begin_op, insn_idx);
|
||||
return;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
case PLUGIN_GEN_FROM_MEM:
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_CB_MEM:
|
||||
plugin_gen_mem_regular(ptb, begin_op, insn_idx);
|
||||
return;
|
||||
case PLUGIN_GEN_CB_INLINE:
|
||||
plugin_gen_mem_inline(ptb, begin_op, insn_idx);
|
||||
return;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
case PLUGIN_GEN_AFTER_INSN:
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_DISABLE_MEM_HELPER:
|
||||
plugin_gen_disable_mem_helper(ptb, begin_op, insn_idx);
|
||||
return;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
/* #define DEBUG_PLUGIN_GEN_OPS */
|
||||
static void pr_ops(void)
|
||||
{
|
||||
@ -759,95 +820,21 @@ static void pr_ops(void)
|
||||
static void plugin_gen_inject(const struct qemu_plugin_tb *plugin_tb)
|
||||
{
|
||||
TCGOp *op;
|
||||
int insn_idx = -1;
|
||||
int insn_idx;
|
||||
|
||||
pr_ops();
|
||||
|
||||
QTAILQ_FOREACH(op, &tcg_ctx->ops, link) {
|
||||
switch (op->opc) {
|
||||
case INDEX_op_insn_start:
|
||||
insn_idx++;
|
||||
break;
|
||||
case INDEX_op_plugin_cb_start:
|
||||
{
|
||||
insn_idx = -1;
|
||||
QSIMPLEQ_FOREACH(op, &tcg_ctx->plugin_ops, plugin_link) {
|
||||
enum plugin_gen_from from = op->args[0];
|
||||
enum plugin_gen_cb type = op->args[1];
|
||||
|
||||
switch (from) {
|
||||
case PLUGIN_GEN_FROM_TB:
|
||||
{
|
||||
g_assert(insn_idx == -1);
|
||||
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_CB_UDATA:
|
||||
plugin_gen_tb_udata(plugin_tb, op);
|
||||
break;
|
||||
case PLUGIN_GEN_CB_INLINE:
|
||||
plugin_gen_tb_inline(plugin_tb, op);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PLUGIN_GEN_FROM_INSN:
|
||||
{
|
||||
g_assert(insn_idx >= 0);
|
||||
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_CB_UDATA:
|
||||
plugin_gen_insn_udata(plugin_tb, op, insn_idx);
|
||||
break;
|
||||
case PLUGIN_GEN_CB_INLINE:
|
||||
plugin_gen_insn_inline(plugin_tb, op, insn_idx);
|
||||
break;
|
||||
case PLUGIN_GEN_ENABLE_MEM_HELPER:
|
||||
plugin_gen_enable_mem_helper(plugin_tb, op, insn_idx);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PLUGIN_GEN_FROM_MEM:
|
||||
{
|
||||
g_assert(insn_idx >= 0);
|
||||
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_CB_MEM:
|
||||
plugin_gen_mem_regular(plugin_tb, op, insn_idx);
|
||||
break;
|
||||
case PLUGIN_GEN_CB_INLINE:
|
||||
plugin_gen_mem_inline(plugin_tb, op, insn_idx);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PLUGIN_GEN_AFTER_INSN:
|
||||
{
|
||||
g_assert(insn_idx >= 0);
|
||||
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_DISABLE_MEM_HELPER:
|
||||
plugin_gen_disable_mem_helper(plugin_tb, op, insn_idx);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* plugins don't care about any other ops */
|
||||
break;
|
||||
tcg_debug_assert(op->opc == INDEX_op_plugin_cb_start);
|
||||
/* ENABLE_MEM_HELPER is the first callback of an instruction */
|
||||
if (from == PLUGIN_GEN_FROM_INSN &&
|
||||
type == PLUGIN_GEN_ENABLE_MEM_HELPER) {
|
||||
insn_idx++;
|
||||
}
|
||||
plugin_inject_cb(plugin_tb, op, insn_idx);
|
||||
}
|
||||
pr_ops();
|
||||
}
|
||||
@ -860,6 +847,7 @@ bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool mem_onl
|
||||
if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_mask)) {
|
||||
ret = true;
|
||||
|
||||
QSIMPLEQ_INIT(&tcg_ctx->plugin_ops);
|
||||
ptb->vaddr = tb->pc;
|
||||
ptb->vaddr2 = -1;
|
||||
get_page_addr_code_hostp(cpu->env_ptr, tb->pc, &ptb->haddr1);
|
||||
@ -876,8 +864,9 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
|
||||
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
||||
struct qemu_plugin_insn *pinsn;
|
||||
|
||||
pinsn = qemu_plugin_tb_insn_get(ptb, db->pc_next);
|
||||
pinsn = qemu_plugin_tb_insn_get(ptb);
|
||||
tcg_ctx->plugin_insn = pinsn;
|
||||
pinsn->vaddr = db->pc_next;
|
||||
plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN);
|
||||
|
||||
/*
|
||||
|
@ -61,6 +61,8 @@ void rr_kick_vcpu_thread(CPUState *unused)
|
||||
static QEMUTimer *rr_kick_vcpu_timer;
|
||||
static CPUState *rr_current_cpu;
|
||||
|
||||
#define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10)
|
||||
|
||||
static inline int64_t rr_next_kick_time(void)
|
||||
{
|
||||
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + TCG_KICK_PERIOD;
|
||||
|
@ -31,6 +31,19 @@
|
||||
#include "exec/log.h"
|
||||
#include "tcg/tcg.h"
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
#define EXCP_LIBAFL_BP 0xf4775747
|
||||
|
||||
void HELPER(libafl_qemu_handle_breakpoint)(CPUArchState *env)
|
||||
{
|
||||
CPUState* cpu = env_cpu(env);
|
||||
cpu->exception_index = EXCP_LIBAFL_BP;
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
/* 32-bit helpers */
|
||||
|
||||
int32_t HELPER(div_i32)(int32_t arg1, int32_t arg2)
|
||||
|
@ -285,3 +285,9 @@ DEF_HELPER_FLAGS_4(gvec_leu32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_5(gvec_bitsel, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
DEF_HELPER_FLAGS_1(libafl_qemu_handle_breakpoint, TCG_CALL_NO_RWG, void, env)
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
@ -61,6 +61,386 @@
|
||||
#include "tb-context.h"
|
||||
#include "internal.h"
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "tcg/tcg-internal.h"
|
||||
#include "exec/helper-head.h"
|
||||
|
||||
void libafl_helper_table_add(TCGHelperInfo* info);
|
||||
void libafl_gen_jmp(target_ulong src, target_ulong dst);
|
||||
void libafl_exec_edge_one_off(target_ulong src_block, target_ulong dst_block);
|
||||
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
|
||||
target_ulong dst_block, target_ulong cs_base,
|
||||
uint32_t flags, int cflags);
|
||||
void libafl_gen_read(TCGv addr, MemOp ot);
|
||||
void libafl_gen_read_N(TCGv addr, uint32_t size);
|
||||
void libafl_gen_write(TCGv addr, MemOp ot);
|
||||
void libafl_gen_write_N(TCGv addr, uint32_t size);
|
||||
void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot);
|
||||
|
||||
void (*libafl_exec_edge_hook)(uint64_t id);
|
||||
uint64_t (*libafl_gen_edge_hook)(uint64_t src, uint64_t dst);
|
||||
void (*libafl_exec_jmp_hook)(uint64_t src, uint64_t dst, uint64_t id);
|
||||
uint64_t (*libafl_gen_jmp_hook)(uint64_t src, uint64_t dst);
|
||||
|
||||
static TCGHelperInfo libafl_exec_edge_hook_info = {
|
||||
.func = NULL, .name = "libafl_exec_edge_hook", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1)
|
||||
};
|
||||
static int exec_edge_hook_added = 0;
|
||||
|
||||
static TCGHelperInfo libafl_exec_jmp_hook_info = {
|
||||
.func = NULL, .name = "libafl_exec_jmp_hook", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 3)
|
||||
};
|
||||
static int exec_jmp_hook_added = 0;
|
||||
|
||||
void (*libafl_exec_block_hook)(uint64_t id);
|
||||
uint64_t (*libafl_gen_block_hook)(uint64_t pc);
|
||||
|
||||
static TCGHelperInfo libafl_exec_block_hook_info = {
|
||||
.func = NULL, .name = "libafl_exec_block_hook", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1)
|
||||
};
|
||||
static int exec_block_hook_added = 0;
|
||||
|
||||
void (*libafl_exec_read_hook1)(uint64_t id, uint64_t addr);
|
||||
void (*libafl_exec_read_hook2)(uint64_t id, uint64_t addr);
|
||||
void (*libafl_exec_read_hook4)(uint64_t id, uint64_t addr);
|
||||
void (*libafl_exec_read_hook8)(uint64_t id, uint64_t addr);
|
||||
void (*libafl_exec_read_hookN)(uint64_t id, uint64_t addr, uint32_t size);
|
||||
uint64_t (*libafl_gen_read_hook)(uint32_t size);
|
||||
|
||||
static TCGHelperInfo libafl_exec_read_hook1_info = {
|
||||
.func = NULL, .name = "libafl_exec_read_hook1", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
|
||||
};
|
||||
static TCGHelperInfo libafl_exec_read_hook2_info = {
|
||||
.func = NULL, .name = "libafl_exec_read_hook2", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
|
||||
};
|
||||
static TCGHelperInfo libafl_exec_read_hook4_info = {
|
||||
.func = NULL, .name = "libafl_exec_read_hook4", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
|
||||
};
|
||||
static TCGHelperInfo libafl_exec_read_hook8_info = {
|
||||
.func = NULL, .name = "libafl_exec_read_hook8", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
|
||||
};
|
||||
static TCGHelperInfo libafl_exec_read_hookN_info = {
|
||||
.func = NULL, .name = "libafl_exec_read_hookN", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) | dh_typemask(i32, 2)
|
||||
};
|
||||
static int exec_read_hook_added = 0;
|
||||
|
||||
void libafl_gen_read(TCGv addr, MemOp ot)
|
||||
{
|
||||
uint32_t size = 0;
|
||||
void* func = NULL;
|
||||
switch (ot & MO_SIZE) {
|
||||
case MO_64:
|
||||
size = 8;
|
||||
func = libafl_exec_read_hook8;
|
||||
break;
|
||||
case MO_32:
|
||||
size = 4;
|
||||
func = libafl_exec_read_hook4;
|
||||
break;
|
||||
case MO_16:
|
||||
size = 2;
|
||||
func = libafl_exec_read_hook2;
|
||||
break;
|
||||
case MO_8:
|
||||
size = 1;
|
||||
func = libafl_exec_read_hook1;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t libafl_id = 0;
|
||||
if (libafl_gen_read_hook)
|
||||
libafl_id = libafl_gen_read_hook(size);
|
||||
if (func && libafl_id != (uint32_t)-1) {
|
||||
if (!exec_read_hook_added) {
|
||||
exec_read_hook_added = 1;
|
||||
libafl_exec_read_hook1_info.func = libafl_exec_read_hook1;
|
||||
libafl_helper_table_add(&libafl_exec_read_hook1_info);
|
||||
libafl_exec_read_hook2_info.func = libafl_exec_read_hook2;
|
||||
libafl_helper_table_add(&libafl_exec_read_hook2_info);
|
||||
libafl_exec_read_hook4_info.func = libafl_exec_read_hook4;
|
||||
libafl_helper_table_add(&libafl_exec_read_hook4_info);
|
||||
libafl_exec_read_hook8_info.func = libafl_exec_read_hook8;
|
||||
libafl_helper_table_add(&libafl_exec_read_hook8_info);
|
||||
libafl_exec_read_hookN_info.func = libafl_exec_read_hookN;
|
||||
libafl_helper_table_add(&libafl_exec_read_hookN_info);
|
||||
}
|
||||
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
|
||||
TCGTemp *tmp1[2] = { tcgv_i64_temp(tmp0),
|
||||
#if TARGET_LONG_BITS == 32
|
||||
tcgv_i32_temp(addr) };
|
||||
#else
|
||||
tcgv_i64_temp(addr) };
|
||||
#endif
|
||||
tcg_gen_callN(func, NULL, 2, tmp1);
|
||||
tcg_temp_free_i64(tmp0);
|
||||
}
|
||||
}
|
||||
|
||||
void libafl_gen_read_N(TCGv addr, uint32_t size)
|
||||
{
|
||||
uint32_t libafl_id = 0;
|
||||
if (libafl_gen_read_hook)
|
||||
libafl_id = libafl_gen_read_hook(size);
|
||||
if (libafl_id != (uint32_t)-1) {
|
||||
if (!exec_read_hook_added) {
|
||||
exec_read_hook_added = 1;
|
||||
libafl_exec_read_hook1_info.func = libafl_exec_read_hook1;
|
||||
libafl_helper_table_add(&libafl_exec_read_hook1_info);
|
||||
libafl_exec_read_hook2_info.func = libafl_exec_read_hook2;
|
||||
libafl_helper_table_add(&libafl_exec_read_hook2_info);
|
||||
libafl_exec_read_hook4_info.func = libafl_exec_read_hook4;
|
||||
libafl_helper_table_add(&libafl_exec_read_hook4_info);
|
||||
libafl_exec_read_hook8_info.func = libafl_exec_read_hook8;
|
||||
libafl_helper_table_add(&libafl_exec_read_hook8_info);
|
||||
libafl_exec_read_hookN_info.func = libafl_exec_read_hookN;
|
||||
libafl_helper_table_add(&libafl_exec_read_hookN_info);
|
||||
}
|
||||
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
|
||||
TCGv_i32 tmp1 = tcg_const_i32(size);
|
||||
TCGTemp *tmp2[3] = { tcgv_i64_temp(tmp0),
|
||||
#if TARGET_LONG_BITS == 32
|
||||
tcgv_i32_temp(addr),
|
||||
#else
|
||||
tcgv_i64_temp(addr),
|
||||
#endif
|
||||
tcgv_i32_temp(tmp1)
|
||||
};
|
||||
tcg_gen_callN(libafl_exec_read_hookN, NULL, 3, tmp2);
|
||||
tcg_temp_free_i32(tmp1);
|
||||
tcg_temp_free_i64(tmp0);
|
||||
}
|
||||
}
|
||||
|
||||
void (*libafl_exec_write_hook1)(uint64_t id, uint64_t addr);
|
||||
void (*libafl_exec_write_hook2)(uint64_t id, uint64_t addr);
|
||||
void (*libafl_exec_write_hook4)(uint64_t id, uint64_t addr);
|
||||
void (*libafl_exec_write_hook8)(uint64_t id, uint64_t addr);
|
||||
void (*libafl_exec_write_hookN)(uint64_t id, uint64_t addr, uint32_t size);
|
||||
uint64_t (*libafl_gen_write_hook)(uint32_t size);
|
||||
|
||||
static TCGHelperInfo libafl_exec_write_hook1_info = {
|
||||
.func = NULL, .name = "libafl_exec_write_hook1", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
|
||||
};
|
||||
static TCGHelperInfo libafl_exec_write_hook2_info = {
|
||||
.func = NULL, .name = "libafl_exec_write_hook2", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
|
||||
};
|
||||
static TCGHelperInfo libafl_exec_write_hook4_info = {
|
||||
.func = NULL, .name = "libafl_exec_write_hook4", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
|
||||
};
|
||||
static TCGHelperInfo libafl_exec_write_hook8_info = {
|
||||
.func = NULL, .name = "libafl_exec_write_hook8", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
|
||||
};
|
||||
static TCGHelperInfo libafl_exec_write_hookN_info = {
|
||||
.func = NULL, .name = "libafl_exec_write_hookN", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) | dh_typemask(i32, 2)
|
||||
};
|
||||
static int exec_write_hook_added = 0;
|
||||
|
||||
void libafl_gen_write(TCGv addr, MemOp ot)
|
||||
{
|
||||
uint32_t size = 0;
|
||||
void* func = NULL;
|
||||
switch (ot & MO_SIZE) {
|
||||
case MO_64:
|
||||
size = 8;
|
||||
func = libafl_exec_write_hook8;
|
||||
break;
|
||||
case MO_32:
|
||||
size = 4;
|
||||
func = libafl_exec_write_hook4;
|
||||
break;
|
||||
case MO_16:
|
||||
size = 2;
|
||||
func = libafl_exec_write_hook2;
|
||||
break;
|
||||
case MO_8:
|
||||
size = 1;
|
||||
func = libafl_exec_write_hook1;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t libafl_id = 0;
|
||||
if (libafl_gen_write_hook)
|
||||
libafl_id = libafl_gen_write_hook(size);
|
||||
if (func && libafl_id != (uint32_t)-1) {
|
||||
if (!exec_write_hook_added) {
|
||||
exec_write_hook_added = 1;
|
||||
libafl_exec_write_hook1_info.func = libafl_exec_write_hook1;
|
||||
libafl_helper_table_add(&libafl_exec_write_hook1_info);
|
||||
libafl_exec_write_hook2_info.func = libafl_exec_write_hook2;
|
||||
libafl_helper_table_add(&libafl_exec_write_hook2_info);
|
||||
libafl_exec_write_hook4_info.func = libafl_exec_write_hook4;
|
||||
libafl_helper_table_add(&libafl_exec_write_hook4_info);
|
||||
libafl_exec_write_hook8_info.func = libafl_exec_write_hook8;
|
||||
libafl_helper_table_add(&libafl_exec_write_hook8_info);
|
||||
libafl_exec_write_hookN_info.func = libafl_exec_write_hookN;
|
||||
libafl_helper_table_add(&libafl_exec_write_hookN_info);
|
||||
}
|
||||
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
|
||||
TCGTemp *tmp1[2] = { tcgv_i64_temp(tmp0),
|
||||
#if TARGET_LONG_BITS == 32
|
||||
tcgv_i32_temp(addr) };
|
||||
#else
|
||||
tcgv_i64_temp(addr) };
|
||||
#endif
|
||||
tcg_gen_callN(func, NULL, 2, tmp1);
|
||||
tcg_temp_free_i64(tmp0);
|
||||
}
|
||||
}
|
||||
|
||||
void libafl_gen_write_N(TCGv addr, uint32_t size)
|
||||
{
|
||||
uint32_t libafl_id = 0;
|
||||
if (libafl_gen_write_hook)
|
||||
libafl_id = libafl_gen_write_hook(size);
|
||||
if (libafl_id != (uint32_t)-1) {
|
||||
if (!exec_write_hook_added) {
|
||||
exec_write_hook_added = 1;
|
||||
libafl_exec_write_hook1_info.func = libafl_exec_write_hook1;
|
||||
libafl_helper_table_add(&libafl_exec_write_hook1_info);
|
||||
libafl_exec_write_hook2_info.func = libafl_exec_write_hook2;
|
||||
libafl_helper_table_add(&libafl_exec_write_hook2_info);
|
||||
libafl_exec_write_hook4_info.func = libafl_exec_write_hook4;
|
||||
libafl_helper_table_add(&libafl_exec_write_hook4_info);
|
||||
libafl_exec_write_hook8_info.func = libafl_exec_write_hook8;
|
||||
libafl_helper_table_add(&libafl_exec_write_hook8_info);
|
||||
libafl_exec_write_hookN_info.func = libafl_exec_write_hookN;
|
||||
libafl_helper_table_add(&libafl_exec_write_hookN_info);
|
||||
}
|
||||
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
|
||||
TCGv_i32 tmp1 = tcg_const_i32(size);
|
||||
TCGTemp *tmp2[3] = { tcgv_i64_temp(tmp0),
|
||||
#if TARGET_LONG_BITS == 32
|
||||
tcgv_i32_temp(addr),
|
||||
#else
|
||||
tcgv_i64_temp(addr),
|
||||
#endif
|
||||
tcgv_i32_temp(tmp1)
|
||||
};
|
||||
tcg_gen_callN(libafl_exec_write_hookN, NULL, 3, tmp2);
|
||||
tcg_temp_free_i32(tmp1);
|
||||
tcg_temp_free_i64(tmp0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void (*libafl_exec_cmp_hook1)(uint64_t id, uint8_t v0, uint8_t v1);
|
||||
void (*libafl_exec_cmp_hook2)(uint64_t id, uint16_t v0, uint16_t v1);
|
||||
void (*libafl_exec_cmp_hook4)(uint64_t id, uint32_t v0, uint32_t v1);
|
||||
void (*libafl_exec_cmp_hook8)(uint64_t id, uint64_t v0, uint64_t v1);
|
||||
uint64_t (*libafl_gen_cmp_hook)(uint64_t pc, uint32_t size);
|
||||
|
||||
static TCGHelperInfo libafl_exec_cmp_hook1_info = {
|
||||
.func = NULL, .name = "libafl_exec_cmp_hook1", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(i32, 1)
|
||||
| dh_typemask(tl, 2) | dh_typemask(tl, 3)
|
||||
};
|
||||
static TCGHelperInfo libafl_exec_cmp_hook2_info = {
|
||||
.func = NULL, .name = "libafl_exec_cmp_hook2", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(i32, 1)
|
||||
| dh_typemask(tl, 2) | dh_typemask(tl, 3)
|
||||
};
|
||||
static TCGHelperInfo libafl_exec_cmp_hook4_info = {
|
||||
.func = NULL, .name = "libafl_exec_cmp_hook4", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(i32, 1)
|
||||
| dh_typemask(tl, 2) | dh_typemask(tl, 3)
|
||||
};
|
||||
static TCGHelperInfo libafl_exec_cmp_hook8_info = {
|
||||
.func = NULL, .name = "libafl_exec_cmp_hook8", \
|
||||
.flags = dh_callflag(void), \
|
||||
.typemask = dh_typemask(void, 0) | dh_typemask(i32, 1)
|
||||
| dh_typemask(tl, 2) | dh_typemask(tl, 3)
|
||||
};
|
||||
static int exec_cmp_hook_added = 0;
|
||||
|
||||
void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot)
|
||||
{
|
||||
uint32_t size = 0;
|
||||
void* func = NULL;
|
||||
switch (ot & MO_SIZE) {
|
||||
case MO_64:
|
||||
size = 8;
|
||||
func = libafl_exec_cmp_hook8;
|
||||
break;
|
||||
case MO_32:
|
||||
size = 4;
|
||||
func = libafl_exec_cmp_hook4;
|
||||
break;
|
||||
case MO_16:
|
||||
size = 2;
|
||||
func = libafl_exec_cmp_hook2;
|
||||
break;
|
||||
case MO_8:
|
||||
size = 1;
|
||||
func = libafl_exec_cmp_hook1;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t libafl_id = 0;
|
||||
if (libafl_gen_cmp_hook)
|
||||
libafl_id = libafl_gen_cmp_hook((uint64_t)pc, size);
|
||||
if (func && libafl_id != (uint32_t)-1) {
|
||||
if (!exec_cmp_hook_added) {
|
||||
exec_cmp_hook_added = 1;
|
||||
libafl_exec_cmp_hook1_info.func = libafl_exec_cmp_hook1;
|
||||
libafl_helper_table_add(&libafl_exec_cmp_hook1_info);
|
||||
libafl_exec_cmp_hook2_info.func = libafl_exec_cmp_hook2;
|
||||
libafl_helper_table_add(&libafl_exec_cmp_hook2_info);
|
||||
libafl_exec_cmp_hook4_info.func = libafl_exec_cmp_hook4;
|
||||
libafl_helper_table_add(&libafl_exec_cmp_hook4_info);
|
||||
libafl_exec_cmp_hook8_info.func = libafl_exec_cmp_hook8;
|
||||
libafl_helper_table_add(&libafl_exec_cmp_hook8_info);
|
||||
}
|
||||
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
|
||||
TCGTemp *tmp1[3] = { tcgv_i64_temp(tmp0),
|
||||
#if TARGET_LONG_BITS == 32
|
||||
tcgv_i32_temp(op0), tcgv_i32_temp(op1) };
|
||||
#else
|
||||
tcgv_i64_temp(op0), tcgv_i64_temp(op1) };
|
||||
#endif
|
||||
tcg_gen_callN(func, NULL, 3, tmp1);
|
||||
tcg_temp_free_i64(tmp0);
|
||||
}
|
||||
}
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
/* #define DEBUG_TB_INVALIDATE */
|
||||
/* #define DEBUG_TB_FLUSH */
|
||||
/* make various TB consistency checks */
|
||||
@ -1297,8 +1677,31 @@ static inline void tb_page_add(PageDesc *p, TranslationBlock *tb,
|
||||
invalidate_page_bitmap(p);
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
/* translator_loop() must have made all TB pages non-writable */
|
||||
assert(!(p->flags & PAGE_WRITE));
|
||||
if (p->flags & PAGE_WRITE) {
|
||||
target_ulong addr;
|
||||
PageDesc *p2;
|
||||
int prot;
|
||||
|
||||
/* force the host page as non writable (writes will have a
|
||||
page fault + mprotect overhead) */
|
||||
page_addr &= qemu_host_page_mask;
|
||||
prot = 0;
|
||||
for (addr = page_addr; addr < page_addr + qemu_host_page_size;
|
||||
addr += TARGET_PAGE_SIZE) {
|
||||
|
||||
p2 = page_find(addr >> TARGET_PAGE_BITS);
|
||||
if (!p2) {
|
||||
continue;
|
||||
}
|
||||
prot |= p2->flags;
|
||||
p2->flags &= ~PAGE_WRITE;
|
||||
}
|
||||
mprotect(g2h_untagged(page_addr), qemu_host_page_size,
|
||||
(prot & PAGE_BITS) & ~PAGE_WRITE);
|
||||
if (DEBUG_TB_INVALIDATE_GATE) {
|
||||
printf("protecting code page: 0x" TB_PAGE_ADDR_FMT "\n", page_addr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* if some code is already present, then the pages are already
|
||||
protected. So we handle the case where only the first TB is
|
||||
@ -1377,6 +1780,157 @@ tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
|
||||
return tb;
|
||||
}
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
void libafl_exec_edge_one_off(target_ulong src_block, target_ulong dst_block)
|
||||
{
|
||||
uint32_t libafl_id = 0;
|
||||
if (libafl_gen_edge_hook)
|
||||
libafl_id = libafl_gen_edge_hook((uint64_t)src_block, (uint64_t)dst_block);
|
||||
if (!libafl_exec_edge_hook || libafl_id == (uint32_t)-1)
|
||||
return;
|
||||
if (!exec_edge_hook_added) {
|
||||
exec_edge_hook_added = 1;
|
||||
libafl_exec_edge_hook_info.func = libafl_exec_edge_hook;
|
||||
libafl_helper_table_add(&libafl_exec_edge_hook_info);
|
||||
}
|
||||
libafl_exec_edge_hook(libafl_id);
|
||||
}
|
||||
|
||||
void libafl_gen_jmp(target_ulong src, target_ulong dst)
|
||||
{
|
||||
uint32_t libafl_id = 0;
|
||||
if (libafl_gen_jmp_hook)
|
||||
libafl_id = libafl_gen_jmp_hook((uint64_t)src, (uint64_t)dst);
|
||||
if (!libafl_exec_jmp_hook || libafl_id == (uint32_t)-1)
|
||||
return;
|
||||
if (!exec_jmp_hook_added) {
|
||||
exec_jmp_hook_added = 1;
|
||||
libafl_exec_jmp_hook_info.func = libafl_exec_jmp_hook;
|
||||
libafl_helper_table_add(&libafl_exec_jmp_hook_info);
|
||||
}
|
||||
TCGv_i64 tmp0 = tcg_const_i64(src);
|
||||
TCGv_i64 tmp1 = tcg_const_i64(dst);
|
||||
TCGv_i64 tmp2 = tcg_const_i64(libafl_id);
|
||||
TCGTemp *tmp3[3] = { tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1), tcgv_i64_temp(tmp2) };
|
||||
tcg_gen_callN(libafl_exec_jmp_hook, NULL, 3, tmp3);
|
||||
tcg_temp_free_i64(tmp0);
|
||||
}
|
||||
|
||||
/* Called with mmap_lock held for user mode emulation. */
|
||||
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
|
||||
target_ulong dst_block, target_ulong cs_base,
|
||||
uint32_t flags, int cflags)
|
||||
{
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
TranslationBlock *tb;
|
||||
tcg_insn_unit *gen_code_buf;
|
||||
int gen_code_size, search_size;
|
||||
|
||||
assert_memory_lock();
|
||||
|
||||
uint32_t libafl_id = 0;
|
||||
if (libafl_gen_edge_hook)
|
||||
libafl_id = libafl_gen_edge_hook((uint64_t)src_block, (uint64_t)dst_block);
|
||||
if (!libafl_exec_edge_hook || libafl_id == (uint32_t)-1)
|
||||
return NULL;
|
||||
|
||||
if (!exec_edge_hook_added) {
|
||||
exec_edge_hook_added = 1;
|
||||
libafl_exec_edge_hook_info.func = libafl_exec_edge_hook;
|
||||
libafl_helper_table_add(&libafl_exec_edge_hook_info);
|
||||
}
|
||||
|
||||
buffer_overflow1:
|
||||
tb = tcg_tb_alloc(tcg_ctx);
|
||||
if (unlikely(!tb)) {
|
||||
/* flush must be done */
|
||||
tb_flush(cpu);
|
||||
mmap_unlock();
|
||||
/* Make the execution loop process the flush as soon as possible. */
|
||||
cpu->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
|
||||
libafl_exec_edge_hook(libafl_id);
|
||||
|
||||
gen_code_buf = tcg_ctx->code_gen_ptr;
|
||||
tb->tc.ptr = gen_code_buf;
|
||||
tb->pc = 0;
|
||||
tb->cs_base = cs_base;
|
||||
tb->flags = flags;
|
||||
tb->cflags = cflags;
|
||||
tb->trace_vcpu_dstate = *cpu->trace_dstate;
|
||||
tb->icount = 0;
|
||||
tcg_ctx->tb_cflags = 0;
|
||||
|
||||
tcg_func_start(tcg_ctx);
|
||||
|
||||
tcg_ctx->cpu = env_cpu(env);
|
||||
|
||||
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
|
||||
TCGTemp *tmp1[1] = { tcgv_i64_temp(tmp0) };
|
||||
tcg_gen_callN(libafl_exec_edge_hook, NULL, 1, tmp1);
|
||||
tcg_temp_free_i64(tmp0);
|
||||
|
||||
tcg_gen_goto_tb(0);
|
||||
tcg_gen_exit_tb(tb, 0);
|
||||
|
||||
tcg_ctx->cpu = NULL;
|
||||
|
||||
trace_translate_block(tb, tb->pc, tb->tc.ptr);
|
||||
|
||||
/* generate machine code */
|
||||
tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID;
|
||||
tb->jmp_reset_offset[1] = TB_JMP_RESET_OFFSET_INVALID;
|
||||
tcg_ctx->tb_jmp_reset_offset = tb->jmp_reset_offset;
|
||||
if (TCG_TARGET_HAS_direct_jump) {
|
||||
tcg_ctx->tb_jmp_insn_offset = tb->jmp_target_arg;
|
||||
tcg_ctx->tb_jmp_target_addr = NULL;
|
||||
} else {
|
||||
tcg_ctx->tb_jmp_insn_offset = NULL;
|
||||
tcg_ctx->tb_jmp_target_addr = tb->jmp_target_arg;
|
||||
}
|
||||
|
||||
/* ??? Overflow could be handled better here. In particular, we
|
||||
don't need to re-do gen_intermediate_code, nor should we re-do
|
||||
the tcg optimization currently hidden inside tcg_gen_code. All
|
||||
that should be required is to flush the TBs, allocate a new TB,
|
||||
re-initialize it per above, and re-do the actual code generation. */
|
||||
gen_code_size = tcg_gen_code(tcg_ctx, tb);
|
||||
if (unlikely(gen_code_size < 0)) {
|
||||
goto buffer_overflow1;
|
||||
}
|
||||
search_size = encode_search(tb, (void *)gen_code_buf + gen_code_size);
|
||||
if (unlikely(search_size < 0)) {
|
||||
goto buffer_overflow1;
|
||||
}
|
||||
tb->tc.size = gen_code_size;
|
||||
|
||||
qatomic_set(&tcg_ctx->code_gen_ptr, (void *)
|
||||
ROUND_UP((uintptr_t)gen_code_buf + gen_code_size + search_size,
|
||||
CODE_GEN_ALIGN));
|
||||
|
||||
/* init jump list */
|
||||
qemu_spin_init(&tb->jmp_lock);
|
||||
tb->jmp_list_head = (uintptr_t)NULL;
|
||||
tb->jmp_list_next[0] = (uintptr_t)NULL;
|
||||
tb->jmp_list_next[1] = (uintptr_t)NULL;
|
||||
tb->jmp_dest[0] = (uintptr_t)NULL;
|
||||
tb->jmp_dest[1] = (uintptr_t)NULL;
|
||||
|
||||
/* init original jump addresses which have been set during tcg_gen_code() */
|
||||
if (tb->jmp_reset_offset[0] != TB_JMP_RESET_OFFSET_INVALID) {
|
||||
tb_reset_jump(tb, 0);
|
||||
}
|
||||
if (tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) {
|
||||
tb_reset_jump(tb, 1);
|
||||
}
|
||||
|
||||
return tb;
|
||||
}
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
/* Called with mmap_lock held for user mode emulation. */
|
||||
TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
target_ulong pc, target_ulong cs_base,
|
||||
@ -1427,6 +1981,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
tb->flags = flags;
|
||||
tb->cflags = cflags;
|
||||
tb->trace_vcpu_dstate = *cpu->trace_dstate;
|
||||
tb->icount = 0;
|
||||
tcg_ctx->tb_cflags = cflags;
|
||||
tb_overflow:
|
||||
|
||||
@ -1444,6 +1999,26 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
tcg_func_start(tcg_ctx);
|
||||
|
||||
tcg_ctx->cpu = env_cpu(env);
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
uint32_t libafl_id = 0;
|
||||
if (libafl_gen_block_hook)
|
||||
libafl_id = libafl_gen_block_hook((uint64_t)pc);
|
||||
if (libafl_exec_block_hook && libafl_id != (uint32_t)-1) {
|
||||
if (!exec_block_hook_added) {
|
||||
exec_block_hook_added = 1;
|
||||
libafl_exec_block_hook_info.func = libafl_exec_block_hook;
|
||||
libafl_helper_table_add(&libafl_exec_block_hook_info);
|
||||
}
|
||||
TCGv_i64 tmp0 = tcg_const_i64((uint64_t)pc);
|
||||
TCGTemp *tmp1[1] = { tcgv_i64_temp(tmp0) };
|
||||
tcg_gen_callN(libafl_exec_block_hook, NULL, 1, tmp1);
|
||||
tcg_temp_free_i64(tmp0);
|
||||
}
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
gen_intermediate_code(cpu, tb, max_insns);
|
||||
assert(tb->size != 0);
|
||||
tcg_ctx->cpu = NULL;
|
||||
@ -1738,7 +2313,7 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
||||
if (current_tb_modified) {
|
||||
page_collection_unlock(pages);
|
||||
/* Force execution of one insn next time. */
|
||||
cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu);
|
||||
cpu->cflags_next_tb = 1 | curr_cflags(cpu);
|
||||
mmap_unlock();
|
||||
cpu_loop_exit_noexc(cpu);
|
||||
}
|
||||
@ -1906,7 +2481,7 @@ static bool tb_invalidate_phys_page(tb_page_addr_t addr, uintptr_t pc)
|
||||
#ifdef TARGET_HAS_PRECISE_SMC
|
||||
if (current_tb_modified) {
|
||||
/* Force execution of one insn next time. */
|
||||
cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu);
|
||||
cpu->cflags_next_tb = 1 | curr_cflags(cpu);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@ -1991,7 +2566,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
|
||||
cpu_loop_exit_noexc(cpu);
|
||||
}
|
||||
|
||||
static void print_qht_statistics(struct qht_stats hst, GString *buf)
|
||||
static void print_qht_statistics(struct qht_stats hst)
|
||||
{
|
||||
uint32_t hgram_opts;
|
||||
size_t hgram_bins;
|
||||
@ -2000,11 +2575,9 @@ static void print_qht_statistics(struct qht_stats hst, GString *buf)
|
||||
if (!hst.head_buckets) {
|
||||
return;
|
||||
}
|
||||
g_string_append_printf(buf, "TB hash buckets %zu/%zu "
|
||||
"(%0.2f%% head buckets used)\n",
|
||||
qemu_printf("TB hash buckets %zu/%zu (%0.2f%% head buckets used)\n",
|
||||
hst.used_head_buckets, hst.head_buckets,
|
||||
(double)hst.used_head_buckets /
|
||||
hst.head_buckets * 100);
|
||||
(double)hst.used_head_buckets / hst.head_buckets * 100);
|
||||
|
||||
hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
|
||||
hgram_opts |= QDIST_PR_100X | QDIST_PR_PERCENT;
|
||||
@ -2012,8 +2585,7 @@ static void print_qht_statistics(struct qht_stats hst, GString *buf)
|
||||
hgram_opts |= QDIST_PR_NODECIMAL;
|
||||
}
|
||||
hgram = qdist_pr(&hst.occupancy, 10, hgram_opts);
|
||||
g_string_append_printf(buf, "TB hash occupancy %0.2f%% avg chain occ. "
|
||||
"Histogram: %s\n",
|
||||
qemu_printf("TB hash occupancy %0.2f%% avg chain occ. Histogram: %s\n",
|
||||
qdist_avg(&hst.occupancy) * 100, hgram);
|
||||
g_free(hgram);
|
||||
|
||||
@ -2026,8 +2598,7 @@ static void print_qht_statistics(struct qht_stats hst, GString *buf)
|
||||
hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE;
|
||||
}
|
||||
hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts);
|
||||
g_string_append_printf(buf, "TB hash avg chain %0.3f buckets. "
|
||||
"Histogram: %s\n",
|
||||
qemu_printf("TB hash avg chain %0.3f buckets. Histogram: %s\n",
|
||||
qdist_avg(&hst.chain), hgram);
|
||||
g_free(hgram);
|
||||
}
|
||||
@ -2065,7 +2636,7 @@ static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data)
|
||||
return false;
|
||||
}
|
||||
|
||||
void dump_exec_info(GString *buf)
|
||||
void dump_exec_info(void)
|
||||
{
|
||||
struct tb_tree_stats tst = {};
|
||||
struct qht_stats hst;
|
||||
@ -2074,53 +2645,49 @@ void dump_exec_info(GString *buf)
|
||||
tcg_tb_foreach(tb_tree_stats_iter, &tst);
|
||||
nb_tbs = tst.nb_tbs;
|
||||
/* XXX: avoid using doubles ? */
|
||||
g_string_append_printf(buf, "Translation buffer state:\n");
|
||||
qemu_printf("Translation buffer state:\n");
|
||||
/*
|
||||
* Report total code size including the padding and TB structs;
|
||||
* otherwise users might think "-accel tcg,tb-size" is not honoured.
|
||||
* For avg host size we use the precise numbers from tb_tree_stats though.
|
||||
*/
|
||||
g_string_append_printf(buf, "gen code size %zu/%zu\n",
|
||||
qemu_printf("gen code size %zu/%zu\n",
|
||||
tcg_code_size(), tcg_code_capacity());
|
||||
g_string_append_printf(buf, "TB count %zu\n", nb_tbs);
|
||||
g_string_append_printf(buf, "TB avg target size %zu max=%zu bytes\n",
|
||||
qemu_printf("TB count %zu\n", nb_tbs);
|
||||
qemu_printf("TB avg target size %zu max=%zu bytes\n",
|
||||
nb_tbs ? tst.target_size / nb_tbs : 0,
|
||||
tst.max_target_size);
|
||||
g_string_append_printf(buf, "TB avg host size %zu bytes "
|
||||
"(expansion ratio: %0.1f)\n",
|
||||
qemu_printf("TB avg host size %zu bytes (expansion ratio: %0.1f)\n",
|
||||
nb_tbs ? tst.host_size / nb_tbs : 0,
|
||||
tst.target_size ?
|
||||
(double)tst.host_size / tst.target_size : 0);
|
||||
g_string_append_printf(buf, "cross page TB count %zu (%zu%%)\n",
|
||||
tst.cross_page,
|
||||
tst.target_size ? (double)tst.host_size / tst.target_size : 0);
|
||||
qemu_printf("cross page TB count %zu (%zu%%)\n", tst.cross_page,
|
||||
nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
|
||||
g_string_append_printf(buf, "direct jump count %zu (%zu%%) "
|
||||
"(2 jumps=%zu %zu%%)\n",
|
||||
qemu_printf("direct jump count %zu (%zu%%) (2 jumps=%zu %zu%%)\n",
|
||||
tst.direct_jmp_count,
|
||||
nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0,
|
||||
tst.direct_jmp2_count,
|
||||
nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0);
|
||||
|
||||
qht_statistics_init(&tb_ctx.htable, &hst);
|
||||
print_qht_statistics(hst, buf);
|
||||
print_qht_statistics(hst);
|
||||
qht_statistics_destroy(&hst);
|
||||
|
||||
g_string_append_printf(buf, "\nStatistics:\n");
|
||||
g_string_append_printf(buf, "TB flush count %u\n",
|
||||
qemu_printf("\nStatistics:\n");
|
||||
qemu_printf("TB flush count %u\n",
|
||||
qatomic_read(&tb_ctx.tb_flush_count));
|
||||
g_string_append_printf(buf, "TB invalidate count %u\n",
|
||||
qemu_printf("TB invalidate count %u\n",
|
||||
qatomic_read(&tb_ctx.tb_phys_invalidate_count));
|
||||
|
||||
tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
|
||||
g_string_append_printf(buf, "TLB full flushes %zu\n", flush_full);
|
||||
g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part);
|
||||
g_string_append_printf(buf, "TLB elided flushes %zu\n", flush_elide);
|
||||
tcg_dump_info(buf);
|
||||
qemu_printf("TLB full flushes %zu\n", flush_full);
|
||||
qemu_printf("TLB partial flushes %zu\n", flush_part);
|
||||
qemu_printf("TLB elided flushes %zu\n", flush_elide);
|
||||
tcg_dump_info();
|
||||
}
|
||||
|
||||
void dump_opcount_info(GString *buf)
|
||||
void dump_opcount_info(void)
|
||||
{
|
||||
tcg_dump_op_count(buf);
|
||||
tcg_dump_op_count();
|
||||
}
|
||||
|
||||
#else /* CONFIG_USER_ONLY */
|
||||
@ -2379,38 +2946,6 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void page_protect(tb_page_addr_t page_addr)
|
||||
{
|
||||
target_ulong addr;
|
||||
PageDesc *p;
|
||||
int prot;
|
||||
|
||||
p = page_find(page_addr >> TARGET_PAGE_BITS);
|
||||
if (p && (p->flags & PAGE_WRITE)) {
|
||||
/*
|
||||
* Force the host page as non writable (writes will have a page fault +
|
||||
* mprotect overhead).
|
||||
*/
|
||||
page_addr &= qemu_host_page_mask;
|
||||
prot = 0;
|
||||
for (addr = page_addr; addr < page_addr + qemu_host_page_size;
|
||||
addr += TARGET_PAGE_SIZE) {
|
||||
|
||||
p = page_find(addr >> TARGET_PAGE_BITS);
|
||||
if (!p) {
|
||||
continue;
|
||||
}
|
||||
prot |= p->flags;
|
||||
p->flags &= ~PAGE_WRITE;
|
||||
}
|
||||
mprotect(g2h_untagged(page_addr), qemu_host_page_size,
|
||||
(prot & PAGE_BITS) & ~PAGE_WRITE);
|
||||
if (DEBUG_TB_INVALIDATE_GATE) {
|
||||
printf("protecting code page: 0x" TB_PAGE_ADDR_FMT "\n", page_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* called from signal handler: invalidate the code and unprotect the
|
||||
* page. Return 0 if the fault was not handled, 1 if it was handled,
|
||||
* and 2 if it was handled but the caller must cause the TB to be
|
||||
|
@ -18,6 +18,29 @@
|
||||
#include "exec/plugin-gen.h"
|
||||
#include "sysemu/replay.h"
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
#include "tcg/tcg-internal.h"
|
||||
|
||||
struct libafl_breakpoint {
|
||||
target_ulong addr;
|
||||
struct libafl_breakpoint* next;
|
||||
};
|
||||
|
||||
extern struct libafl_breakpoint* libafl_qemu_breakpoints;
|
||||
|
||||
struct libafl_hook {
|
||||
target_ulong addr;
|
||||
void (*callback)(uint64_t);
|
||||
uint64_t value;
|
||||
TCGHelperInfo helper_info;
|
||||
struct libafl_hook* next;
|
||||
};
|
||||
|
||||
extern struct libafl_hook* libafl_qemu_hooks;
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
/* Pairs with tcg_clear_temp_count.
|
||||
To be called by #TranslatorOps.{translate_insn,tb_stop} if
|
||||
(1) the target is sufficiently clean to support reporting,
|
||||
@ -42,15 +65,6 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest)
|
||||
return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0;
|
||||
}
|
||||
|
||||
static inline void translator_page_protect(DisasContextBase *dcbase,
|
||||
target_ulong pc)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
dcbase->page_protect_end = pc | ~TARGET_PAGE_MASK;
|
||||
page_protect(pc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
CPUState *cpu, TranslationBlock *tb, int max_insns)
|
||||
{
|
||||
@ -65,7 +79,6 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
db->num_insns = 0;
|
||||
db->max_insns = max_insns;
|
||||
db->singlestep_enabled = cflags & CF_SINGLE_STEP;
|
||||
translator_page_protect(db, db->pc_next);
|
||||
|
||||
ops->init_disas_context(db, cpu);
|
||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||
@ -89,6 +102,29 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
plugin_gen_insn_start(cpu, db);
|
||||
}
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
struct libafl_hook* hk = libafl_qemu_hooks;
|
||||
while (hk) {
|
||||
if (hk->addr == db->pc_next) {
|
||||
TCGv_i64 tmp0 = tcg_const_i64(hk->value);
|
||||
TCGTemp *tmp1[1] = { tcgv_i64_temp(tmp0) };
|
||||
tcg_gen_callN(hk->callback, NULL, 1, tmp1);
|
||||
tcg_temp_free_i64(tmp0);
|
||||
}
|
||||
hk = hk->next;
|
||||
}
|
||||
|
||||
struct libafl_breakpoint* bp = libafl_qemu_breakpoints;
|
||||
while (bp) {
|
||||
if (bp->addr == db->pc_next) {
|
||||
gen_helper_libafl_qemu_handle_breakpoint(cpu_env);
|
||||
}
|
||||
bp = bp->next;
|
||||
}
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
/* Disassemble one instruction. The translate_insn hook should
|
||||
update db->pc_next and db->is_jmp to indicate what should be
|
||||
done next -- either exiting this loop or locate the start of
|
||||
@ -147,32 +183,3 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void translator_maybe_page_protect(DisasContextBase *dcbase,
|
||||
target_ulong pc, size_t len)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
target_ulong end = pc + len - 1;
|
||||
|
||||
if (end > dcbase->page_protect_end) {
|
||||
translator_page_protect(dcbase, end);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define GEN_TRANSLATOR_LD(fullname, type, load_fn, swap_fn) \
|
||||
type fullname ## _swap(CPUArchState *env, DisasContextBase *dcbase, \
|
||||
abi_ptr pc, bool do_swap) \
|
||||
{ \
|
||||
translator_maybe_page_protect(dcbase, pc, sizeof(type)); \
|
||||
type ret = load_fn(env, pc); \
|
||||
if (do_swap) { \
|
||||
ret = swap_fn(ret); \
|
||||
} \
|
||||
plugin_insn_append(pc, &ret, sizeof(ret)); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD)
|
||||
|
||||
#undef GEN_TRANSLATOR_LD
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,22 +7,23 @@ softmmu_ss.add(files(
|
||||
'wavcapture.c',
|
||||
))
|
||||
|
||||
softmmu_ss.add(when: coreaudio, if_true: files('coreaudio.c'))
|
||||
softmmu_ss.add(when: dsound, if_true: files('dsoundaudio.c', 'audio_win_int.c'))
|
||||
softmmu_ss.add(when: [coreaudio, 'CONFIG_AUDIO_COREAUDIO'], if_true: files('coreaudio.c'))
|
||||
softmmu_ss.add(when: [dsound, 'CONFIG_AUDIO_DSOUND'], if_true: files('dsoundaudio.c'))
|
||||
softmmu_ss.add(when: ['CONFIG_AUDIO_WIN_INT'], if_true: files('audio_win_int.c'))
|
||||
|
||||
audio_modules = {}
|
||||
foreach m : [
|
||||
['alsa', alsa, files('alsaaudio.c')],
|
||||
['oss', oss, files('ossaudio.c')],
|
||||
['pa', pulse, files('paaudio.c')],
|
||||
['sdl', sdl, files('sdlaudio.c')],
|
||||
['jack', jack, files('jackaudio.c')],
|
||||
['spice', spice, files('spiceaudio.c')]
|
||||
['CONFIG_AUDIO_ALSA', 'alsa', alsa, 'alsaaudio.c'],
|
||||
['CONFIG_AUDIO_OSS', 'oss', oss, 'ossaudio.c'],
|
||||
['CONFIG_AUDIO_PA', 'pa', pulse, 'paaudio.c'],
|
||||
['CONFIG_AUDIO_SDL', 'sdl', sdl, 'sdlaudio.c'],
|
||||
['CONFIG_AUDIO_JACK', 'jack', jack, 'jackaudio.c'],
|
||||
['CONFIG_SPICE', 'spice', spice, 'spiceaudio.c']
|
||||
]
|
||||
if m[1].found()
|
||||
if config_host.has_key(m[0])
|
||||
module_ss = ss.source_set()
|
||||
module_ss.add(m[1], m[2])
|
||||
audio_modules += {m[0] : module_ss}
|
||||
module_ss.add(when: m[2], if_true: files(m[3]))
|
||||
audio_modules += {m[1] : module_ss}
|
||||
endif
|
||||
endforeach
|
||||
|
||||
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* QEMU host SGX EPC memory backend
|
||||
*
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Sean Christopherson <sean.j.christopherson@intel.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/hostmem.h"
|
||||
#include "hw/i386/hostmem-epc.h"
|
||||
|
||||
static void
|
||||
sgx_epc_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
{
|
||||
uint32_t ram_flags;
|
||||
char *name;
|
||||
int fd;
|
||||
|
||||
if (!backend->size) {
|
||||
error_setg(errp, "can't create backend with size 0");
|
||||
return;
|
||||
}
|
||||
|
||||
fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
|
||||
if (fd < 0) {
|
||||
error_setg_errno(errp, errno,
|
||||
"failed to open /dev/sgx_vepc to alloc SGX EPC");
|
||||
return;
|
||||
}
|
||||
|
||||
name = object_get_canonical_path(OBJECT(backend));
|
||||
ram_flags = (backend->share ? RAM_SHARED : 0) | RAM_PROTECTED;
|
||||
memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
|
||||
name, backend->size, ram_flags,
|
||||
fd, 0, errp);
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
static void sgx_epc_backend_instance_init(Object *obj)
|
||||
{
|
||||
HostMemoryBackend *m = MEMORY_BACKEND(obj);
|
||||
|
||||
m->share = true;
|
||||
m->merge = false;
|
||||
m->dump = false;
|
||||
}
|
||||
|
||||
static void sgx_epc_backend_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
|
||||
|
||||
bc->alloc = sgx_epc_backend_memory_alloc;
|
||||
}
|
||||
|
||||
static const TypeInfo sgx_epc_backed_info = {
|
||||
.name = TYPE_MEMORY_BACKEND_EPC,
|
||||
.parent = TYPE_MEMORY_BACKEND,
|
||||
.instance_init = sgx_epc_backend_instance_init,
|
||||
.class_init = sgx_epc_backend_class_init,
|
||||
.instance_size = sizeof(HostMemoryBackendEpc),
|
||||
};
|
||||
|
||||
static void register_types(void)
|
||||
{
|
||||
int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
|
||||
type_register_static(&sgx_epc_backed_info);
|
||||
}
|
||||
}
|
||||
|
||||
type_init(register_types);
|
@ -16,6 +16,5 @@ softmmu_ss.add(when: ['CONFIG_VHOST_USER', 'CONFIG_VIRTIO'], if_true: files('vho
|
||||
softmmu_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('cryptodev-vhost.c'))
|
||||
softmmu_ss.add(when: ['CONFIG_VIRTIO_CRYPTO', 'CONFIG_VHOST_CRYPTO'], if_true: files('cryptodev-vhost-user.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_GIO', if_true: [files('dbus-vmstate.c'), gio])
|
||||
softmmu_ss.add(when: 'CONFIG_SGX', if_true: files('hostmem-epc.c'))
|
||||
|
||||
subdir('tpm')
|
||||
|
@ -492,7 +492,8 @@ static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
|
||||
error_setg(&tpm_emu->migration_blocker,
|
||||
"Migration disabled: TPM emulator does not support "
|
||||
"migration");
|
||||
if (migrate_add_blocker(tpm_emu->migration_blocker, &err) < 0) {
|
||||
migrate_add_blocker(tpm_emu->migration_blocker, &err);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
error_free(tpm_emu->migration_blocker);
|
||||
tpm_emu->migration_blocker = NULL;
|
||||
@ -623,7 +624,7 @@ static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
|
||||
TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
|
||||
TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
|
||||
|
||||
options->type = TPM_TYPE_EMULATOR;
|
||||
options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR;
|
||||
options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options);
|
||||
|
||||
return options;
|
||||
|
@ -321,7 +321,7 @@ static TpmTypeOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb)
|
||||
{
|
||||
TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
|
||||
|
||||
options->type = TPM_TYPE_PASSTHROUGH;
|
||||
options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
|
||||
options->u.passthrough.data = QAPI_CLONE(TPMPassthroughOptions,
|
||||
TPM_PASSTHROUGH(tb)->options);
|
||||
|
||||
|
441
block.c
441
block.c
@ -49,8 +49,6 @@
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/id.h"
|
||||
#include "qemu/range.h"
|
||||
#include "qemu/rcu.h"
|
||||
#include "block/coroutines.h"
|
||||
|
||||
#ifdef CONFIG_BSD
|
||||
@ -84,13 +82,8 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
|
||||
BdrvChildRole child_role,
|
||||
Error **errp);
|
||||
|
||||
static bool bdrv_recurse_has_child(BlockDriverState *bs,
|
||||
BlockDriverState *child);
|
||||
|
||||
static void bdrv_child_free(BdrvChild *child);
|
||||
static void bdrv_replace_child_noperm(BdrvChild **child,
|
||||
BlockDriverState *new_bs,
|
||||
bool free_empty_child);
|
||||
static void bdrv_replace_child_noperm(BdrvChild *child,
|
||||
BlockDriverState *new_bs);
|
||||
static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
|
||||
BdrvChild *child,
|
||||
Transaction *tran);
|
||||
@ -408,9 +401,6 @@ BlockDriverState *bdrv_new(void)
|
||||
|
||||
qemu_co_queue_init(&bs->flush_queue);
|
||||
|
||||
qemu_co_mutex_init(&bs->bsc_modify_lock);
|
||||
bs->block_status_cache = g_new0(BdrvBlockStatusCache, 1);
|
||||
|
||||
for (i = 0; i < bdrv_drain_all_count; i++) {
|
||||
bdrv_drained_begin(bs);
|
||||
}
|
||||
@ -1389,8 +1379,6 @@ static void bdrv_child_cb_attach(BdrvChild *child)
|
||||
{
|
||||
BlockDriverState *bs = child->opaque;
|
||||
|
||||
QLIST_INSERT_HEAD(&bs->children, child, next);
|
||||
|
||||
if (child->role & BDRV_CHILD_COW) {
|
||||
bdrv_backing_attach(child);
|
||||
}
|
||||
@ -1407,8 +1395,6 @@ static void bdrv_child_cb_detach(BdrvChild *child)
|
||||
}
|
||||
|
||||
bdrv_unapply_subtree_drain(child, bs);
|
||||
|
||||
QLIST_REMOVE(child, next);
|
||||
}
|
||||
|
||||
static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base,
|
||||
@ -1613,26 +1599,16 @@ open_failed:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create and open a block node.
|
||||
*
|
||||
* @options is a QDict of options to pass to the block drivers, or NULL for an
|
||||
* empty set of options. The reference to the QDict belongs to the block layer
|
||||
* after the call (even on failure), so if the caller intends to reuse the
|
||||
* dictionary, it needs to use qobject_ref() before calling bdrv_open.
|
||||
*/
|
||||
BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv,
|
||||
const char *node_name,
|
||||
QDict *options, int flags,
|
||||
Error **errp)
|
||||
BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
|
||||
int flags, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
int ret;
|
||||
|
||||
bs = bdrv_new();
|
||||
bs->open_flags = flags;
|
||||
bs->options = options ?: qdict_new();
|
||||
bs->explicit_options = qdict_clone_shallow(bs->options);
|
||||
bs->explicit_options = qdict_new();
|
||||
bs->options = qdict_new();
|
||||
bs->opaque = NULL;
|
||||
|
||||
update_options_from_flags(bs->options, flags);
|
||||
@ -1650,13 +1626,6 @@ BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv,
|
||||
return bs;
|
||||
}
|
||||
|
||||
/* Create and open a block node. */
|
||||
BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
|
||||
int flags, Error **errp)
|
||||
{
|
||||
return bdrv_new_open_driver_opts(drv, node_name, NULL, flags, errp);
|
||||
}
|
||||
|
||||
QemuOptsList bdrv_runtime_opts = {
|
||||
.name = "bdrv_common",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head),
|
||||
@ -2256,18 +2225,13 @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm,
|
||||
|
||||
typedef struct BdrvReplaceChildState {
|
||||
BdrvChild *child;
|
||||
BdrvChild **childp;
|
||||
BlockDriverState *old_bs;
|
||||
bool free_empty_child;
|
||||
} BdrvReplaceChildState;
|
||||
|
||||
static void bdrv_replace_child_commit(void *opaque)
|
||||
{
|
||||
BdrvReplaceChildState *s = opaque;
|
||||
|
||||
if (s->free_empty_child && !s->child->bs) {
|
||||
bdrv_child_free(s->child);
|
||||
}
|
||||
bdrv_unref(s->old_bs);
|
||||
}
|
||||
|
||||
@ -2276,34 +2240,8 @@ static void bdrv_replace_child_abort(void *opaque)
|
||||
BdrvReplaceChildState *s = opaque;
|
||||
BlockDriverState *new_bs = s->child->bs;
|
||||
|
||||
/*
|
||||
* old_bs reference is transparently moved from @s to s->child.
|
||||
*
|
||||
* Pass &s->child here instead of s->childp, because:
|
||||
* (1) s->old_bs must be non-NULL, so bdrv_replace_child_noperm() will not
|
||||
* modify the BdrvChild * pointer we indirectly pass to it, i.e. it
|
||||
* will not modify s->child. From that perspective, it does not matter
|
||||
* whether we pass s->childp or &s->child.
|
||||
* (2) If new_bs is not NULL, s->childp will be NULL. We then cannot use
|
||||
* it here.
|
||||
* (3) If new_bs is NULL, *s->childp will have been NULLed by
|
||||
* bdrv_replace_child_tran()'s bdrv_replace_child_noperm() call, and we
|
||||
* must not pass a NULL *s->childp here.
|
||||
*
|
||||
* So whether new_bs was NULL or not, we cannot pass s->childp here; and in
|
||||
* any case, there is no reason to pass it anyway.
|
||||
*/
|
||||
bdrv_replace_child_noperm(&s->child, s->old_bs, true);
|
||||
/*
|
||||
* The child was pre-existing, so s->old_bs must be non-NULL, and
|
||||
* s->child thus must not have been freed
|
||||
*/
|
||||
assert(s->child != NULL);
|
||||
if (!new_bs) {
|
||||
/* As described above, *s->childp was cleared, so restore it */
|
||||
assert(s->childp != NULL);
|
||||
*s->childp = s->child;
|
||||
}
|
||||
/* old_bs reference is transparently moved from @s to @s->child */
|
||||
bdrv_replace_child_noperm(s->child, s->old_bs);
|
||||
bdrv_unref(new_bs);
|
||||
}
|
||||
|
||||
@ -2319,46 +2257,22 @@ static TransactionActionDrv bdrv_replace_child_drv = {
|
||||
* Note: real unref of old_bs is done only on commit.
|
||||
*
|
||||
* The function doesn't update permissions, caller is responsible for this.
|
||||
*
|
||||
* (*childp)->bs must not be NULL.
|
||||
*
|
||||
* Note that if new_bs == NULL, @childp is stored in a state object attached
|
||||
* to @tran, so that the old child can be reinstated in the abort handler.
|
||||
* Therefore, if @new_bs can be NULL, @childp must stay valid until the
|
||||
* transaction is committed or aborted.
|
||||
*
|
||||
* If @free_empty_child is true and @new_bs is NULL, the BdrvChild is
|
||||
* freed (on commit). @free_empty_child should only be false if the
|
||||
* caller will free the BDrvChild themselves (which may be important
|
||||
* if this is in turn called in another transactional context).
|
||||
*/
|
||||
static void bdrv_replace_child_tran(BdrvChild **childp,
|
||||
BlockDriverState *new_bs,
|
||||
Transaction *tran,
|
||||
bool free_empty_child)
|
||||
static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
|
||||
Transaction *tran)
|
||||
{
|
||||
BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
|
||||
*s = (BdrvReplaceChildState) {
|
||||
.child = *childp,
|
||||
.childp = new_bs == NULL ? childp : NULL,
|
||||
.old_bs = (*childp)->bs,
|
||||
.free_empty_child = free_empty_child,
|
||||
.child = child,
|
||||
.old_bs = child->bs,
|
||||
};
|
||||
tran_add(tran, &bdrv_replace_child_drv, s);
|
||||
|
||||
/* The abort handler relies on this */
|
||||
assert(s->old_bs != NULL);
|
||||
|
||||
if (new_bs) {
|
||||
bdrv_ref(new_bs);
|
||||
}
|
||||
/*
|
||||
* Pass free_empty_child=false, we will free the child (if
|
||||
* necessary) in bdrv_replace_child_commit() (if our
|
||||
* @free_empty_child parameter was true).
|
||||
*/
|
||||
bdrv_replace_child_noperm(childp, new_bs, false);
|
||||
/* old_bs reference is transparently moved from *childp to @s */
|
||||
bdrv_replace_child_noperm(child, new_bs);
|
||||
/* old_bs reference is transparently moved from @child to @s */
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2729,30 +2643,14 @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
|
||||
return permissions[qapi_perm];
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace (*childp)->bs by @new_bs.
|
||||
*
|
||||
* If @new_bs is NULL, *childp will be set to NULL, too: BDS parents
|
||||
* generally cannot handle a BdrvChild with .bs == NULL, so clearing
|
||||
* BdrvChild.bs should generally immediately be followed by the
|
||||
* BdrvChild pointer being cleared as well.
|
||||
*
|
||||
* If @free_empty_child is true and @new_bs is NULL, the BdrvChild is
|
||||
* freed. @free_empty_child should only be false if the caller will
|
||||
* free the BdrvChild themselves (this may be important in a
|
||||
* transactional context, where it may only be freed on commit).
|
||||
*/
|
||||
static void bdrv_replace_child_noperm(BdrvChild **childp,
|
||||
BlockDriverState *new_bs,
|
||||
bool free_empty_child)
|
||||
static void bdrv_replace_child_noperm(BdrvChild *child,
|
||||
BlockDriverState *new_bs)
|
||||
{
|
||||
BdrvChild *child = *childp;
|
||||
BlockDriverState *old_bs = child->bs;
|
||||
int new_bs_quiesce_counter;
|
||||
int drain_saldo;
|
||||
|
||||
assert(!child->frozen);
|
||||
assert(old_bs != new_bs);
|
||||
|
||||
if (old_bs && new_bs) {
|
||||
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
|
||||
@ -2781,9 +2679,6 @@ static void bdrv_replace_child_noperm(BdrvChild **childp,
|
||||
}
|
||||
|
||||
child->bs = new_bs;
|
||||
if (!new_bs) {
|
||||
*childp = NULL;
|
||||
}
|
||||
|
||||
if (new_bs) {
|
||||
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
|
||||
@ -2813,25 +2708,21 @@ static void bdrv_replace_child_noperm(BdrvChild **childp,
|
||||
bdrv_parent_drained_end_single(child);
|
||||
drain_saldo++;
|
||||
}
|
||||
|
||||
if (free_empty_child && !child->bs) {
|
||||
bdrv_child_free(child);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the given @child.
|
||||
*
|
||||
* The child must be empty (i.e. `child->bs == NULL`) and it must be
|
||||
* unused (i.e. not in a children list).
|
||||
*/
|
||||
static void bdrv_child_free(BdrvChild *child)
|
||||
static void bdrv_child_free(void *opaque)
|
||||
{
|
||||
BdrvChild *c = opaque;
|
||||
|
||||
g_free(c->name);
|
||||
g_free(c);
|
||||
}
|
||||
|
||||
static void bdrv_remove_empty_child(BdrvChild *child)
|
||||
{
|
||||
assert(!child->bs);
|
||||
assert(!child->next.le_prev); /* not in children list */
|
||||
|
||||
g_free(child->name);
|
||||
g_free(child);
|
||||
QLIST_SAFE_REMOVE(child, next);
|
||||
bdrv_child_free(child);
|
||||
}
|
||||
|
||||
typedef struct BdrvAttachChildCommonState {
|
||||
@ -2846,35 +2737,27 @@ static void bdrv_attach_child_common_abort(void *opaque)
|
||||
BdrvChild *child = *s->child;
|
||||
BlockDriverState *bs = child->bs;
|
||||
|
||||
/*
|
||||
* Pass free_empty_child=false, because we still need the child
|
||||
* for the AioContext operations on the parent below; those
|
||||
* BdrvChildClass methods all work on a BdrvChild object, so we
|
||||
* need to keep it as an empty shell (after this function, it will
|
||||
* not be attached to any parent, and it will not have a .bs).
|
||||
*/
|
||||
bdrv_replace_child_noperm(s->child, NULL, false);
|
||||
bdrv_replace_child_noperm(child, NULL);
|
||||
|
||||
if (bdrv_get_aio_context(bs) != s->old_child_ctx) {
|
||||
bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort);
|
||||
}
|
||||
|
||||
if (bdrv_child_get_parent_aio_context(child) != s->old_parent_ctx) {
|
||||
GSList *ignore;
|
||||
GSList *ignore = g_slist_prepend(NULL, child);
|
||||
|
||||
/* No need to ignore `child`, because it has been detached already */
|
||||
ignore = NULL;
|
||||
child->klass->can_set_aio_ctx(child, s->old_parent_ctx, &ignore,
|
||||
&error_abort);
|
||||
g_slist_free(ignore);
|
||||
|
||||
ignore = NULL;
|
||||
ignore = g_slist_prepend(NULL, child);
|
||||
child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore);
|
||||
|
||||
g_slist_free(ignore);
|
||||
}
|
||||
|
||||
bdrv_unref(bs);
|
||||
bdrv_child_free(child);
|
||||
bdrv_remove_empty_child(child);
|
||||
*s->child = NULL;
|
||||
}
|
||||
|
||||
static TransactionActionDrv bdrv_attach_child_common_drv = {
|
||||
@ -2946,15 +2829,13 @@ static int bdrv_attach_child_common(BlockDriverState *child_bs,
|
||||
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
bdrv_child_free(new_child);
|
||||
bdrv_remove_empty_child(new_child);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_ref(child_bs);
|
||||
bdrv_replace_child_noperm(&new_child, child_bs, true);
|
||||
/* child_bs was non-NULL, so new_child must not have been freed */
|
||||
assert(new_child != NULL);
|
||||
bdrv_replace_child_noperm(new_child, child_bs);
|
||||
|
||||
*child = new_child;
|
||||
|
||||
@ -2989,12 +2870,6 @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
|
||||
|
||||
assert(parent_bs->drv);
|
||||
|
||||
if (bdrv_recurse_has_child(child_bs, parent_bs)) {
|
||||
error_setg(errp, "Making '%s' a %s child of '%s' would create a cycle",
|
||||
child_bs->node_name, child_name, parent_bs->node_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm);
|
||||
bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL,
|
||||
perm, shared_perm, &perm, &shared_perm);
|
||||
@ -3006,14 +2881,21 @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
|
||||
return ret;
|
||||
}
|
||||
|
||||
QLIST_INSERT_HEAD(&parent_bs->children, *child, next);
|
||||
/*
|
||||
* child is removed in bdrv_attach_child_common_abort(), so don't care to
|
||||
* abort this change separately.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bdrv_detach_child(BdrvChild **childp)
|
||||
static void bdrv_detach_child(BdrvChild *child)
|
||||
{
|
||||
BlockDriverState *old_bs = (*childp)->bs;
|
||||
BlockDriverState *old_bs = child->bs;
|
||||
|
||||
bdrv_replace_child_noperm(childp, NULL, true);
|
||||
bdrv_replace_child_noperm(child, NULL);
|
||||
bdrv_remove_empty_child(child);
|
||||
|
||||
if (old_bs) {
|
||||
/*
|
||||
@ -3119,7 +3001,7 @@ void bdrv_root_unref_child(BdrvChild *child)
|
||||
BlockDriverState *child_bs;
|
||||
|
||||
child_bs = child->bs;
|
||||
bdrv_detach_child(&child);
|
||||
bdrv_detach_child(child);
|
||||
bdrv_unref(child_bs);
|
||||
}
|
||||
|
||||
@ -4812,8 +4694,6 @@ static void bdrv_close(BlockDriverState *bs)
|
||||
bs->explicit_options = NULL;
|
||||
qobject_unref(bs->full_open_options);
|
||||
bs->full_open_options = NULL;
|
||||
g_free(bs->block_status_cache);
|
||||
bs->block_status_cache = NULL;
|
||||
|
||||
bdrv_release_named_dirty_bitmaps(bs);
|
||||
assert(QLIST_EMPTY(&bs->dirty_bitmaps));
|
||||
@ -4929,7 +4809,6 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to)
|
||||
|
||||
typedef struct BdrvRemoveFilterOrCowChild {
|
||||
BdrvChild *child;
|
||||
BlockDriverState *bs;
|
||||
bool is_backing;
|
||||
} BdrvRemoveFilterOrCowChild;
|
||||
|
||||
@ -4938,6 +4817,7 @@ static void bdrv_remove_filter_or_cow_child_abort(void *opaque)
|
||||
BdrvRemoveFilterOrCowChild *s = opaque;
|
||||
BlockDriverState *parent_bs = s->child->opaque;
|
||||
|
||||
QLIST_INSERT_HEAD(&parent_bs->children, s->child, next);
|
||||
if (s->is_backing) {
|
||||
parent_bs->backing = s->child;
|
||||
} else {
|
||||
@ -4959,19 +4839,10 @@ static void bdrv_remove_filter_or_cow_child_commit(void *opaque)
|
||||
bdrv_child_free(s->child);
|
||||
}
|
||||
|
||||
static void bdrv_remove_filter_or_cow_child_clean(void *opaque)
|
||||
{
|
||||
BdrvRemoveFilterOrCowChild *s = opaque;
|
||||
|
||||
/* Drop the bs reference after the transaction is done */
|
||||
bdrv_unref(s->bs);
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = {
|
||||
.abort = bdrv_remove_filter_or_cow_child_abort,
|
||||
.commit = bdrv_remove_filter_or_cow_child_commit,
|
||||
.clean = bdrv_remove_filter_or_cow_child_clean,
|
||||
.clean = g_free,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -4982,41 +4853,31 @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
|
||||
BdrvChild *child,
|
||||
Transaction *tran)
|
||||
{
|
||||
BdrvChild **childp;
|
||||
BdrvRemoveFilterOrCowChild *s;
|
||||
|
||||
assert(child == bs->backing || child == bs->file);
|
||||
|
||||
if (!child) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep a reference to @bs so @childp will stay valid throughout the
|
||||
* transaction (required by bdrv_replace_child_tran())
|
||||
*/
|
||||
bdrv_ref(bs);
|
||||
if (child == bs->backing) {
|
||||
childp = &bs->backing;
|
||||
} else if (child == bs->file) {
|
||||
childp = &bs->file;
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (child->bs) {
|
||||
/*
|
||||
* Pass free_empty_child=false, we will free the child in
|
||||
* bdrv_remove_filter_or_cow_child_commit()
|
||||
*/
|
||||
bdrv_replace_child_tran(childp, NULL, tran, false);
|
||||
bdrv_replace_child_tran(child, NULL, tran);
|
||||
}
|
||||
|
||||
s = g_new(BdrvRemoveFilterOrCowChild, 1);
|
||||
*s = (BdrvRemoveFilterOrCowChild) {
|
||||
.child = child,
|
||||
.bs = bs,
|
||||
.is_backing = (childp == &bs->backing),
|
||||
.is_backing = (child == bs->backing),
|
||||
};
|
||||
tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s);
|
||||
|
||||
QLIST_SAFE_REMOVE(child, next);
|
||||
if (s->is_backing) {
|
||||
bs->backing = NULL;
|
||||
} else {
|
||||
bs->file = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5037,8 +4898,6 @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
|
||||
{
|
||||
BdrvChild *c, *next;
|
||||
|
||||
assert(to != NULL);
|
||||
|
||||
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
|
||||
assert(c->bs == from);
|
||||
if (!should_update_child(c, to)) {
|
||||
@ -5054,12 +4913,7 @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
|
||||
c->name, from->node_name);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Passing a pointer to the local variable @c is fine here, because
|
||||
* @to is not NULL, and so &c will not be attached to the transaction.
|
||||
*/
|
||||
bdrv_replace_child_tran(&c, to, tran, true);
|
||||
bdrv_replace_child_tran(c, to, tran);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -5074,8 +4928,6 @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
|
||||
*
|
||||
* With @detach_subchain=true @to must be in a backing chain of @from. In this
|
||||
* case backing link of the cow-parent of @to is removed.
|
||||
*
|
||||
* @to must not be NULL.
|
||||
*/
|
||||
static int bdrv_replace_node_common(BlockDriverState *from,
|
||||
BlockDriverState *to,
|
||||
@ -5088,8 +4940,6 @@ static int bdrv_replace_node_common(BlockDriverState *from,
|
||||
BlockDriverState *to_cow_parent = NULL;
|
||||
int ret;
|
||||
|
||||
assert(to != NULL);
|
||||
|
||||
if (detach_subchain) {
|
||||
assert(bdrv_chain_contains(from, to));
|
||||
assert(from != to);
|
||||
@ -5145,9 +4995,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace node @from by @to (where neither may be NULL).
|
||||
*/
|
||||
int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
|
||||
Error **errp)
|
||||
{
|
||||
@ -5201,39 +5048,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Not for empty child */
|
||||
int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
|
||||
Error **errp)
|
||||
{
|
||||
int ret;
|
||||
Transaction *tran = tran_new();
|
||||
g_autoptr(GHashTable) found = NULL;
|
||||
g_autoptr(GSList) refresh_list = NULL;
|
||||
BlockDriverState *old_bs = child->bs;
|
||||
|
||||
bdrv_ref(old_bs);
|
||||
bdrv_drained_begin(old_bs);
|
||||
bdrv_drained_begin(new_bs);
|
||||
|
||||
bdrv_replace_child_tran(&child, new_bs, tran, true);
|
||||
/* @new_bs must have been non-NULL, so @child must not have been freed */
|
||||
assert(child != NULL);
|
||||
|
||||
found = g_hash_table_new(NULL, NULL);
|
||||
refresh_list = bdrv_topological_dfs(refresh_list, found, old_bs);
|
||||
refresh_list = bdrv_topological_dfs(refresh_list, found, new_bs);
|
||||
|
||||
ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp);
|
||||
|
||||
tran_finalize(tran, ret);
|
||||
|
||||
bdrv_drained_end(old_bs);
|
||||
bdrv_drained_end(new_bs);
|
||||
bdrv_unref(old_bs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bdrv_delete(BlockDriverState *bs)
|
||||
{
|
||||
assert(bdrv_op_blocker_is_empty(bs));
|
||||
@ -5250,61 +5064,29 @@ static void bdrv_delete(BlockDriverState *bs)
|
||||
g_free(bs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Replace @bs by newly created block node.
|
||||
*
|
||||
* @options is a QDict of options to pass to the block drivers, or NULL for an
|
||||
* empty set of options. The reference to the QDict belongs to the block layer
|
||||
* after the call (even on failure), so if the caller intends to reuse the
|
||||
* dictionary, it needs to use qobject_ref() before calling bdrv_open.
|
||||
*/
|
||||
BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options,
|
||||
BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options,
|
||||
int flags, Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
int ret;
|
||||
BlockDriverState *new_node_bs = NULL;
|
||||
const char *drvname, *node_name;
|
||||
BlockDriver *drv;
|
||||
BlockDriverState *new_node_bs;
|
||||
Error *local_err = NULL;
|
||||
|
||||
drvname = qdict_get_try_str(options, "driver");
|
||||
if (!drvname) {
|
||||
error_setg(errp, "driver is not specified");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
drv = bdrv_find_format(drvname);
|
||||
if (!drv) {
|
||||
error_setg(errp, "Unknown driver: '%s'", drvname);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
node_name = qdict_get_try_str(options, "node-name");
|
||||
|
||||
new_node_bs = bdrv_new_open_driver_opts(drv, node_name, options, flags,
|
||||
errp);
|
||||
options = NULL; /* bdrv_new_open_driver() eats options */
|
||||
if (!new_node_bs) {
|
||||
new_node_bs = bdrv_open(NULL, NULL, node_options, flags, errp);
|
||||
if (new_node_bs == NULL) {
|
||||
error_prepend(errp, "Could not create node: ");
|
||||
goto fail;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bdrv_drained_begin(bs);
|
||||
ret = bdrv_replace_node(bs, new_node_bs, errp);
|
||||
bdrv_replace_node(bs, new_node_bs, &local_err);
|
||||
bdrv_drained_end(bs);
|
||||
|
||||
if (ret < 0) {
|
||||
error_prepend(errp, "Could not replace node: ");
|
||||
goto fail;
|
||||
if (local_err) {
|
||||
bdrv_unref(new_node_bs);
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new_node_bs;
|
||||
|
||||
fail:
|
||||
qobject_unref(options);
|
||||
bdrv_unref(new_node_bs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -6506,7 +6288,6 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs)
|
||||
{
|
||||
BdrvChild *child, *parent;
|
||||
int ret;
|
||||
uint64_t cumulative_perms, cumulative_shared_perms;
|
||||
|
||||
if (!bs->drv) {
|
||||
return -ENOMEDIUM;
|
||||
@ -6537,13 +6318,6 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_get_cumulative_perm(bs, &cumulative_perms,
|
||||
&cumulative_shared_perms);
|
||||
if (cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) {
|
||||
/* Our inactive parents still need write access. Inactivation failed. */
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
bs->open_flags |= BDRV_O_INACTIVE;
|
||||
|
||||
/*
|
||||
@ -7879,76 +7653,3 @@ BlockDriverState *bdrv_backing_chain_next(BlockDriverState *bs)
|
||||
{
|
||||
return bdrv_skip_filters(bdrv_cow_bs(bdrv_skip_filters(bs)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether [offset, offset + bytes) overlaps with the cached
|
||||
* block-status data region.
|
||||
*
|
||||
* If so, and @pnum is not NULL, set *pnum to `bsc.data_end - offset`,
|
||||
* which is what bdrv_bsc_is_data()'s interface needs.
|
||||
* Otherwise, *pnum is not touched.
|
||||
*/
|
||||
static bool bdrv_bsc_range_overlaps_locked(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
int64_t *pnum)
|
||||
{
|
||||
BdrvBlockStatusCache *bsc = qatomic_rcu_read(&bs->block_status_cache);
|
||||
bool overlaps;
|
||||
|
||||
overlaps =
|
||||
qatomic_read(&bsc->valid) &&
|
||||
ranges_overlap(offset, bytes, bsc->data_start,
|
||||
bsc->data_end - bsc->data_start);
|
||||
|
||||
if (overlaps && pnum) {
|
||||
*pnum = bsc->data_end - offset;
|
||||
}
|
||||
|
||||
return overlaps;
|
||||
}
|
||||
|
||||
/**
|
||||
* See block_int.h for this function's documentation.
|
||||
*/
|
||||
bool bdrv_bsc_is_data(BlockDriverState *bs, int64_t offset, int64_t *pnum)
|
||||
{
|
||||
RCU_READ_LOCK_GUARD();
|
||||
|
||||
return bdrv_bsc_range_overlaps_locked(bs, offset, 1, pnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* See block_int.h for this function's documentation.
|
||||
*/
|
||||
void bdrv_bsc_invalidate_range(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes)
|
||||
{
|
||||
RCU_READ_LOCK_GUARD();
|
||||
|
||||
if (bdrv_bsc_range_overlaps_locked(bs, offset, bytes, NULL)) {
|
||||
qatomic_set(&bs->block_status_cache->valid, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See block_int.h for this function's documentation.
|
||||
*/
|
||||
void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes)
|
||||
{
|
||||
BdrvBlockStatusCache *new_bsc = g_new(BdrvBlockStatusCache, 1);
|
||||
BdrvBlockStatusCache *old_bsc;
|
||||
|
||||
*new_bsc = (BdrvBlockStatusCache) {
|
||||
.valid = true,
|
||||
.data_start = offset,
|
||||
.data_end = offset + bytes,
|
||||
};
|
||||
|
||||
QEMU_LOCK_GUARD(&bs->bsc_modify_lock);
|
||||
|
||||
old_bsc = qatomic_rcu_read(&bs->block_status_cache);
|
||||
qatomic_rcu_set(&bs->block_status_cache, new_bsc);
|
||||
if (old_bsc) {
|
||||
g_free_rcu(old_bsc, rcu);
|
||||
}
|
||||
}
|
||||
|
@ -98,8 +98,6 @@ AioTaskPool *coroutine_fn aio_task_pool_new(int max_busy_tasks)
|
||||
{
|
||||
AioTaskPool *pool = g_new0(AioTaskPool, 1);
|
||||
|
||||
assert(max_busy_tasks > 0);
|
||||
|
||||
pool->main_co = qemu_coroutine_self();
|
||||
pool->max_busy_tasks = max_busy_tasks;
|
||||
|
||||
|
253
block/backup-top.c
Normal file
253
block/backup-top.c
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* backup-top filter driver
|
||||
*
|
||||
* The driver performs Copy-Before-Write (CBW) operation: it is injected above
|
||||
* some node, and before each write it copies _old_ data to the target node.
|
||||
*
|
||||
* Copyright (c) 2018-2019 Virtuozzo International GmbH.
|
||||
*
|
||||
* Author:
|
||||
* Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qapi/error.h"
|
||||
#include "block/block_int.h"
|
||||
#include "block/qdict.h"
|
||||
#include "block/block-copy.h"
|
||||
|
||||
#include "block/backup-top.h"
|
||||
|
||||
typedef struct BDRVBackupTopState {
|
||||
BlockCopyState *bcs;
|
||||
BdrvChild *target;
|
||||
int64_t cluster_size;
|
||||
} BDRVBackupTopState;
|
||||
|
||||
static coroutine_fn int backup_top_co_preadv(
|
||||
BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
|
||||
}
|
||||
|
||||
static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
BDRVBackupTopState *s = bs->opaque;
|
||||
uint64_t off, end;
|
||||
|
||||
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
off = QEMU_ALIGN_DOWN(offset, s->cluster_size);
|
||||
end = QEMU_ALIGN_UP(offset + bytes, s->cluster_size);
|
||||
|
||||
return block_copy(s->bcs, off, end - off, true);
|
||||
}
|
||||
|
||||
static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
int ret = backup_top_cbw(bs, offset, bytes, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return bdrv_co_pdiscard(bs->backing, offset, bytes);
|
||||
}
|
||||
|
||||
static int coroutine_fn backup_top_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
int ret = backup_top_cbw(bs, offset, bytes, flags);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return bdrv_co_pwrite_zeroes(bs->backing, offset, bytes, flags);
|
||||
}
|
||||
|
||||
static coroutine_fn int backup_top_co_pwritev(BlockDriverState *bs,
|
||||
uint64_t offset,
|
||||
uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
int ret = backup_top_cbw(bs, offset, bytes, flags);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags);
|
||||
}
|
||||
|
||||
static int coroutine_fn backup_top_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
if (!bs->backing) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bdrv_co_flush(bs->backing->bs);
|
||||
}
|
||||
|
||||
static void backup_top_refresh_filename(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->backing == NULL) {
|
||||
/*
|
||||
* we can be here after failed bdrv_attach_child in
|
||||
* bdrv_set_backing_hd
|
||||
*/
|
||||
return;
|
||||
}
|
||||
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
bs->backing->bs->filename);
|
||||
}
|
||||
|
||||
static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c,
|
||||
BdrvChildRole role,
|
||||
BlockReopenQueue *reopen_queue,
|
||||
uint64_t perm, uint64_t shared,
|
||||
uint64_t *nperm, uint64_t *nshared)
|
||||
{
|
||||
if (!(role & BDRV_CHILD_FILTERED)) {
|
||||
/*
|
||||
* Target child
|
||||
*
|
||||
* Share write to target (child_file), to not interfere
|
||||
* with guest writes to its disk which may be in target backing chain.
|
||||
* Can't resize during a backup block job because we check the size
|
||||
* only upfront.
|
||||
*/
|
||||
*nshared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
|
||||
*nperm = BLK_PERM_WRITE;
|
||||
} else {
|
||||
/* Source child */
|
||||
bdrv_default_perms(bs, c, role, reopen_queue,
|
||||
perm, shared, nperm, nshared);
|
||||
|
||||
if (perm & BLK_PERM_WRITE) {
|
||||
*nperm = *nperm | BLK_PERM_CONSISTENT_READ;
|
||||
}
|
||||
*nshared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
|
||||
}
|
||||
}
|
||||
|
||||
BlockDriver bdrv_backup_top_filter = {
|
||||
.format_name = "backup-top",
|
||||
.instance_size = sizeof(BDRVBackupTopState),
|
||||
|
||||
.bdrv_co_preadv = backup_top_co_preadv,
|
||||
.bdrv_co_pwritev = backup_top_co_pwritev,
|
||||
.bdrv_co_pwrite_zeroes = backup_top_co_pwrite_zeroes,
|
||||
.bdrv_co_pdiscard = backup_top_co_pdiscard,
|
||||
.bdrv_co_flush = backup_top_co_flush,
|
||||
|
||||
.bdrv_refresh_filename = backup_top_refresh_filename,
|
||||
|
||||
.bdrv_child_perm = backup_top_child_perm,
|
||||
|
||||
.is_filter = true,
|
||||
};
|
||||
|
||||
BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
|
||||
BlockDriverState *target,
|
||||
const char *filter_node_name,
|
||||
uint64_t cluster_size,
|
||||
BackupPerf *perf,
|
||||
BdrvRequestFlags write_flags,
|
||||
BlockCopyState **bcs,
|
||||
Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
int ret;
|
||||
BDRVBackupTopState *state;
|
||||
BlockDriverState *top;
|
||||
bool appended = false;
|
||||
|
||||
assert(source->total_sectors == target->total_sectors);
|
||||
|
||||
top = bdrv_new_open_driver(&bdrv_backup_top_filter, filter_node_name,
|
||||
BDRV_O_RDWR, errp);
|
||||
if (!top) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state = top->opaque;
|
||||
top->total_sectors = source->total_sectors;
|
||||
top->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
|
||||
(BDRV_REQ_FUA & source->supported_write_flags);
|
||||
top->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
|
||||
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
|
||||
source->supported_zero_flags);
|
||||
|
||||
bdrv_ref(target);
|
||||
state->target = bdrv_attach_child(top, target, "target", &child_of_bds,
|
||||
BDRV_CHILD_DATA, errp);
|
||||
if (!state->target) {
|
||||
bdrv_unref(target);
|
||||
bdrv_unref(top);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bdrv_drained_begin(source);
|
||||
|
||||
ret = bdrv_append(top, source, errp);
|
||||
if (ret < 0) {
|
||||
error_prepend(errp, "Cannot append backup-top filter: ");
|
||||
goto fail;
|
||||
}
|
||||
appended = true;
|
||||
|
||||
state->cluster_size = cluster_size;
|
||||
state->bcs = block_copy_state_new(top->backing, state->target,
|
||||
cluster_size, perf->use_copy_range,
|
||||
write_flags, errp);
|
||||
if (!state->bcs) {
|
||||
error_prepend(errp, "Cannot create block-copy-state: ");
|
||||
goto fail;
|
||||
}
|
||||
*bcs = state->bcs;
|
||||
|
||||
bdrv_drained_end(source);
|
||||
|
||||
return top;
|
||||
|
||||
fail:
|
||||
if (appended) {
|
||||
bdrv_backup_top_drop(top);
|
||||
} else {
|
||||
bdrv_unref(top);
|
||||
}
|
||||
|
||||
bdrv_drained_end(source);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bdrv_backup_top_drop(BlockDriverState *bs)
|
||||
{
|
||||
BDRVBackupTopState *s = bs->opaque;
|
||||
|
||||
bdrv_drop_filter(bs, &error_abort);
|
||||
|
||||
block_copy_state_free(s->bcs);
|
||||
|
||||
bdrv_unref(bs);
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
/*
|
||||
* copy-before-write filter driver
|
||||
* backup-top filter driver
|
||||
*
|
||||
* The driver performs Copy-Before-Write (CBW) operation: it is injected above
|
||||
* some node, and before each write it copies _old_ data to the target node.
|
||||
*
|
||||
* Copyright (c) 2018-2021 Virtuozzo International GmbH.
|
||||
* Copyright (c) 2018-2019 Virtuozzo International GmbH.
|
||||
*
|
||||
* Author:
|
||||
* Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com>
|
||||
@ -23,17 +23,20 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef COPY_BEFORE_WRITE_H
|
||||
#define COPY_BEFORE_WRITE_H
|
||||
#ifndef BACKUP_TOP_H
|
||||
#define BACKUP_TOP_H
|
||||
|
||||
#include "block/block_int.h"
|
||||
#include "block/block-copy.h"
|
||||
|
||||
BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
|
||||
BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
|
||||
BlockDriverState *target,
|
||||
const char *filter_node_name,
|
||||
uint64_t cluster_size,
|
||||
BackupPerf *perf,
|
||||
BdrvRequestFlags write_flags,
|
||||
BlockCopyState **bcs,
|
||||
Error **errp);
|
||||
void bdrv_cbw_drop(BlockDriverState *bs);
|
||||
void bdrv_backup_top_drop(BlockDriverState *bs);
|
||||
|
||||
#endif /* COPY_BEFORE_WRITE_H */
|
||||
#endif /* BACKUP_TOP_H */
|
113
block/backup.c
113
block/backup.c
@ -27,11 +27,13 @@
|
||||
#include "qemu/bitmap.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#include "block/copy-before-write.h"
|
||||
#include "block/backup-top.h"
|
||||
|
||||
#define BACKUP_CLUSTER_SIZE_DEFAULT (1 << 16)
|
||||
|
||||
typedef struct BackupBlockJob {
|
||||
BlockJob common;
|
||||
BlockDriverState *cbw;
|
||||
BlockDriverState *backup_top;
|
||||
BlockDriverState *source_bs;
|
||||
BlockDriverState *target_bs;
|
||||
|
||||
@ -102,7 +104,7 @@ static void backup_clean(Job *job)
|
||||
{
|
||||
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
|
||||
block_job_remove_all_bdrv(&s->common);
|
||||
bdrv_cbw_drop(s->cbw);
|
||||
bdrv_backup_top_drop(s->backup_top);
|
||||
}
|
||||
|
||||
void backup_do_checkpoint(BlockJob *job, Error **errp)
|
||||
@ -233,17 +235,19 @@ static void backup_init_bcs_bitmap(BackupBlockJob *job)
|
||||
BdrvDirtyBitmap *bcs_bitmap = block_copy_dirty_bitmap(job->bcs);
|
||||
|
||||
if (job->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
|
||||
bdrv_clear_dirty_bitmap(bcs_bitmap, NULL);
|
||||
ret = bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap,
|
||||
NULL, true);
|
||||
assert(ret);
|
||||
} else if (job->sync_mode == MIRROR_SYNC_MODE_TOP) {
|
||||
} else {
|
||||
if (job->sync_mode == MIRROR_SYNC_MODE_TOP) {
|
||||
/*
|
||||
* We can't hog the coroutine to initialize this thoroughly.
|
||||
* Set a flag and resume work when we are able to yield safely.
|
||||
*/
|
||||
block_copy_set_skip_unallocated(job->bcs, true);
|
||||
}
|
||||
bdrv_set_dirty_bitmap(bcs_bitmap, 0, job->len);
|
||||
}
|
||||
|
||||
estimate = bdrv_get_dirty_count(bcs_bitmap);
|
||||
job_progress_set_remaining(&job->common.job, estimate);
|
||||
@ -327,12 +331,11 @@ static void coroutine_fn backup_set_speed(BlockJob *job, int64_t speed)
|
||||
}
|
||||
}
|
||||
|
||||
static bool backup_cancel(Job *job, bool force)
|
||||
static void backup_cancel(Job *job, bool force)
|
||||
{
|
||||
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
|
||||
|
||||
bdrv_cancel_in_flight(s->target_bs);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const BlockJobDriver backup_job_driver = {
|
||||
@ -351,6 +354,43 @@ static const BlockJobDriver backup_job_driver = {
|
||||
.set_speed = backup_set_speed,
|
||||
};
|
||||
|
||||
static int64_t backup_calculate_cluster_size(BlockDriverState *target,
|
||||
Error **errp)
|
||||
{
|
||||
int ret;
|
||||
BlockDriverInfo bdi;
|
||||
bool target_does_cow = bdrv_backing_chain_next(target);
|
||||
|
||||
/*
|
||||
* If there is no backing file on the target, we cannot rely on COW if our
|
||||
* backup cluster size is smaller than the target cluster size. Even for
|
||||
* targets with a backing file, try to avoid COW if possible.
|
||||
*/
|
||||
ret = bdrv_get_info(target, &bdi);
|
||||
if (ret == -ENOTSUP && !target_does_cow) {
|
||||
/* Cluster size is not defined */
|
||||
warn_report("The target block device doesn't provide "
|
||||
"information about the block size and it doesn't have a "
|
||||
"backing file. The default block size of %u bytes is "
|
||||
"used. If the actual block size of the target exceeds "
|
||||
"this default, the backup may be unusable",
|
||||
BACKUP_CLUSTER_SIZE_DEFAULT);
|
||||
return BACKUP_CLUSTER_SIZE_DEFAULT;
|
||||
} else if (ret < 0 && !target_does_cow) {
|
||||
error_setg_errno(errp, -ret,
|
||||
"Couldn't determine the cluster size of the target image, "
|
||||
"which has no backing file");
|
||||
error_append_hint(errp,
|
||||
"Aborting, since this may create an unusable destination image\n");
|
||||
return ret;
|
||||
} else if (ret < 0 && target_does_cow) {
|
||||
/* Not fatal; just trudge on ahead. */
|
||||
return BACKUP_CLUSTER_SIZE_DEFAULT;
|
||||
}
|
||||
|
||||
return MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
|
||||
}
|
||||
|
||||
BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
BlockDriverState *target, int64_t speed,
|
||||
MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap,
|
||||
@ -367,7 +407,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
int64_t len, target_len;
|
||||
BackupBlockJob *job = NULL;
|
||||
int64_t cluster_size;
|
||||
BlockDriverState *cbw = NULL;
|
||||
BdrvRequestFlags write_flags;
|
||||
BlockDriverState *backup_top = NULL;
|
||||
BlockCopyState *bcs = NULL;
|
||||
|
||||
assert(bs);
|
||||
@ -408,8 +449,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (perf->max_workers < 1 || perf->max_workers > INT_MAX) {
|
||||
error_setg(errp, "max-workers must be between 1 and %d", INT_MAX);
|
||||
cluster_size = backup_calculate_cluster_size(target, errp);
|
||||
if (cluster_size < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (perf->max_workers < 1) {
|
||||
error_setg(errp, "max-workers must be greater than zero");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -419,6 +465,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (perf->max_chunk && perf->max_chunk < cluster_size) {
|
||||
error_setg(errp, "Required max-chunk (%" PRIi64 ") is less than backup "
|
||||
"cluster size (%" PRIi64 ")", perf->max_chunk, cluster_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (sync_bitmap) {
|
||||
/* If we need to write to this bitmap, check that we can: */
|
||||
if (bitmap_mode != BITMAP_SYNC_MODE_NEVER &&
|
||||
@ -451,28 +504,39 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
goto error;
|
||||
}
|
||||
|
||||
cbw = bdrv_cbw_append(bs, target, filter_node_name, &bcs, errp);
|
||||
if (!cbw) {
|
||||
goto error;
|
||||
}
|
||||
/*
|
||||
* If source is in backing chain of target assume that target is going to be
|
||||
* used for "image fleecing", i.e. it should represent a kind of snapshot of
|
||||
* source at backup-start point in time. And target is going to be read by
|
||||
* somebody (for example, used as NBD export) during backup job.
|
||||
*
|
||||
* In this case, we need to add BDRV_REQ_SERIALISING write flag to avoid
|
||||
* intersection of backup writes and third party reads from target,
|
||||
* otherwise reading from target we may occasionally read already updated by
|
||||
* guest data.
|
||||
*
|
||||
* For more information see commit f8d59dfb40bb and test
|
||||
* tests/qemu-iotests/222
|
||||
*/
|
||||
write_flags = (bdrv_chain_contains(target, bs) ? BDRV_REQ_SERIALISING : 0) |
|
||||
(compress ? BDRV_REQ_WRITE_COMPRESSED : 0),
|
||||
|
||||
cluster_size = block_copy_cluster_size(bcs);
|
||||
|
||||
if (perf->max_chunk && perf->max_chunk < cluster_size) {
|
||||
error_setg(errp, "Required max-chunk (%" PRIi64 ") is less than backup "
|
||||
"cluster size (%" PRIi64 ")", perf->max_chunk, cluster_size);
|
||||
backup_top = bdrv_backup_top_append(bs, target, filter_node_name,
|
||||
cluster_size, perf,
|
||||
write_flags, &bcs, errp);
|
||||
if (!backup_top) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* job->len is fixed, so we can't allow resize */
|
||||
job = block_job_create(job_id, &backup_job_driver, txn, cbw,
|
||||
job = block_job_create(job_id, &backup_job_driver, txn, backup_top,
|
||||
0, BLK_PERM_ALL,
|
||||
speed, creation_flags, cb, opaque, errp);
|
||||
if (!job) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
job->cbw = cbw;
|
||||
job->backup_top = backup_top;
|
||||
job->source_bs = bs;
|
||||
job->target_bs = target;
|
||||
job->on_source_error = on_source_error;
|
||||
@ -485,11 +549,10 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
job->len = len;
|
||||
job->perf = *perf;
|
||||
|
||||
block_copy_set_copy_opts(bcs, perf->use_copy_range, compress);
|
||||
block_copy_set_progress_meter(bcs, &job->common.job.progress);
|
||||
block_copy_set_speed(bcs, speed);
|
||||
|
||||
/* Required permissions are taken by copy-before-write filter target */
|
||||
/* Required permissions are already taken by backup-top target */
|
||||
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
|
||||
&error_abort);
|
||||
|
||||
@ -499,8 +562,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
if (sync_bitmap) {
|
||||
bdrv_reclaim_dirty_bitmap(sync_bitmap, NULL);
|
||||
}
|
||||
if (cbw) {
|
||||
bdrv_cbw_drop(cbw);
|
||||
if (backup_top) {
|
||||
bdrv_backup_top_drop(backup_top);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -631,8 +631,8 @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
blkdebug_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
int err;
|
||||
|
||||
@ -652,8 +652,8 @@ blkdebug_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
blkdebug_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
int err;
|
||||
|
||||
@ -684,7 +684,7 @@ static int blkdebug_co_flush(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
int64_t offset, int bytes,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
uint32_t align = MAX(bs->bl.request_alignment,
|
||||
@ -717,7 +717,7 @@ static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes)
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
uint32_t align = bs->bl.pdiscard_alignment;
|
||||
int err;
|
||||
|
@ -301,8 +301,8 @@ static void blk_log_writes_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
blk_log_writes_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
blk_log_writes_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
|
||||
}
|
||||
@ -460,16 +460,16 @@ blk_log_writes_co_do_file_pdiscard(BlkLogWritesFileReq *fr)
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
blk_log_writes_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
blk_log_writes_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
return blk_log_writes_co_log(bs, offset, bytes, qiov, flags,
|
||||
blk_log_writes_co_do_file_pwritev, 0, false);
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
blk_log_writes_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, BdrvRequestFlags flags)
|
||||
blk_log_writes_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
return blk_log_writes_co_log(bs, offset, bytes, NULL, flags,
|
||||
blk_log_writes_co_do_file_pwrite_zeroes, 0,
|
||||
@ -484,9 +484,9 @@ static int coroutine_fn blk_log_writes_co_flush_to_disk(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
|
||||
blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
|
||||
{
|
||||
return blk_log_writes_co_log(bs, offset, bytes, NULL, 0,
|
||||
return blk_log_writes_co_log(bs, offset, count, NULL, 0,
|
||||
blk_log_writes_co_do_file_pdiscard,
|
||||
LOG_DISCARD_FLAG, false);
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ static void block_request_create(uint64_t reqid, BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
uint64_t reqid = blkreplay_next_id();
|
||||
int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
|
||||
@ -83,7 +83,7 @@ static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
uint64_t reqid = blkreplay_next_id();
|
||||
int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
|
||||
@ -94,7 +94,7 @@ static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes, BdrvRequestFlags flags)
|
||||
int64_t offset, int bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
uint64_t reqid = blkreplay_next_id();
|
||||
int ret = bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
|
||||
@ -105,7 +105,7 @@ static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes)
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
uint64_t reqid = blkreplay_next_id();
|
||||
int ret = bdrv_co_pdiscard(bs->file, offset, bytes);
|
||||
|
@ -221,8 +221,8 @@ blkverify_co_prwv(BlockDriverState *bs, BlkverifyRequest *r, uint64_t offset,
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
blkverify_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
blkverify_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BlkverifyRequest r;
|
||||
QEMUIOVector raw_qiov;
|
||||
@ -250,8 +250,8 @@ blkverify_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
blkverify_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
blkverify_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BlkverifyRequest r;
|
||||
return blkverify_co_prwv(bs, &r, offset, bytes, qiov, qiov, flags, true);
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "block/block_int.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "block/coroutines.h"
|
||||
#include "block/throttle-groups.h"
|
||||
#include "hw/qdev-core.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
@ -870,14 +869,6 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change BlockDriverState associated with @blk.
|
||||
*/
|
||||
int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp)
|
||||
{
|
||||
return bdrv_replace_child_bs(blk->root, new_bs, errp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the permission bitmasks that the user of the BlockBackend needs.
|
||||
*/
|
||||
@ -1162,11 +1153,11 @@ void blk_set_disable_request_queuing(BlockBackend *blk, bool disable)
|
||||
}
|
||||
|
||||
static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
|
||||
int64_t bytes)
|
||||
size_t size)
|
||||
{
|
||||
int64_t len;
|
||||
|
||||
if (bytes < 0) {
|
||||
if (size > INT_MAX) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -1184,7 +1175,7 @@ static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
|
||||
return len;
|
||||
}
|
||||
|
||||
if (offset > len || len - offset < bytes) {
|
||||
if (offset > len || len - offset < size) {
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
@ -1205,8 +1196,8 @@ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
int coroutine_fn
|
||||
blk_co_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes,
|
||||
static int coroutine_fn
|
||||
blk_do_preadv(BlockBackend *blk, int64_t offset, unsigned int bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
@ -1237,21 +1228,21 @@ blk_co_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes,
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
ret = blk_co_do_preadv(blk, offset, bytes, qiov, flags);
|
||||
ret = blk_do_preadv(blk, offset, bytes, qiov, flags);
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
int coroutine_fn
|
||||
blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes,
|
||||
static int coroutine_fn
|
||||
blk_do_pwritev_part(BlockBackend *blk, int64_t offset, unsigned int bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
@ -1287,28 +1278,7 @@ blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes,
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset,
|
||||
int64_t bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
ret = blk_co_do_pwritev_part(blk, offset, bytes, qiov, qiov_offset, flags);
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
return blk_co_pwritev_part(blk, offset, bytes, qiov, 0, flags);
|
||||
}
|
||||
|
||||
static int coroutine_fn blk_pwritev_part(BlockBackend *blk, int64_t offset,
|
||||
int64_t bytes,
|
||||
unsigned int bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
@ -1321,6 +1291,13 @@ static int coroutine_fn blk_pwritev_part(BlockBackend *blk, int64_t offset,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
|
||||
unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
return blk_co_pwritev_part(blk, offset, bytes, qiov, 0, flags);
|
||||
}
|
||||
|
||||
typedef struct BlkRwCo {
|
||||
BlockBackend *blk;
|
||||
int64_t offset;
|
||||
@ -1329,10 +1306,57 @@ typedef struct BlkRwCo {
|
||||
BdrvRequestFlags flags;
|
||||
} BlkRwCo;
|
||||
|
||||
int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset,
|
||||
int64_t bytes, BdrvRequestFlags flags)
|
||||
static void blk_read_entry(void *opaque)
|
||||
{
|
||||
return blk_pwritev_part(blk, offset, bytes, NULL, 0,
|
||||
BlkRwCo *rwco = opaque;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
rwco->ret = blk_do_preadv(rwco->blk, rwco->offset, qiov->size,
|
||||
qiov, rwco->flags);
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
static void blk_write_entry(void *opaque)
|
||||
{
|
||||
BlkRwCo *rwco = opaque;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
rwco->ret = blk_do_pwritev_part(rwco->blk, rwco->offset, qiov->size,
|
||||
qiov, 0, rwco->flags);
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
|
||||
int64_t bytes, CoroutineEntry co_entry,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
|
||||
BlkRwCo rwco = {
|
||||
.blk = blk,
|
||||
.offset = offset,
|
||||
.iobuf = &qiov,
|
||||
.flags = flags,
|
||||
.ret = NOT_DONE,
|
||||
};
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
if (qemu_in_coroutine()) {
|
||||
/* Fast-path if already in coroutine context */
|
||||
co_entry(&rwco);
|
||||
} else {
|
||||
Coroutine *co = qemu_coroutine_create(co_entry, &rwco);
|
||||
bdrv_coroutine_enter(blk_bs(blk), co);
|
||||
BDRV_POLL_WHILE(blk_bs(blk), rwco.ret == NOT_DONE);
|
||||
}
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
return rwco.ret;
|
||||
}
|
||||
|
||||
int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset,
|
||||
int bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
return blk_prw(blk, offset, NULL, bytes, blk_write_entry,
|
||||
flags | BDRV_REQ_ZERO_WRITE);
|
||||
}
|
||||
|
||||
@ -1380,7 +1404,7 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk,
|
||||
typedef struct BlkAioEmAIOCB {
|
||||
BlockAIOCB common;
|
||||
BlkRwCo rwco;
|
||||
int64_t bytes;
|
||||
int bytes;
|
||||
bool has_returned;
|
||||
} BlkAioEmAIOCB;
|
||||
|
||||
@ -1412,8 +1436,7 @@ static void blk_aio_complete_bh(void *opaque)
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset,
|
||||
int64_t bytes,
|
||||
static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
|
||||
void *iobuf, CoroutineEntry co_entry,
|
||||
BdrvRequestFlags flags,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
@ -1452,7 +1475,7 @@ static void blk_aio_read_entry(void *opaque)
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
assert(qiov->size == acb->bytes);
|
||||
rwco->ret = blk_co_do_preadv(rwco->blk, rwco->offset, acb->bytes,
|
||||
rwco->ret = blk_do_preadv(rwco->blk, rwco->offset, acb->bytes,
|
||||
qiov, rwco->flags);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
@ -1464,40 +1487,37 @@ static void blk_aio_write_entry(void *opaque)
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
assert(!qiov || qiov->size == acb->bytes);
|
||||
rwco->ret = blk_co_do_pwritev_part(rwco->blk, rwco->offset, acb->bytes,
|
||||
rwco->ret = blk_do_pwritev_part(rwco->blk, rwco->offset, acb->bytes,
|
||||
qiov, 0, rwco->flags);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset,
|
||||
int64_t bytes, BdrvRequestFlags flags,
|
||||
int count, BdrvRequestFlags flags,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_write_entry,
|
||||
return blk_aio_prwv(blk, offset, count, NULL, blk_aio_write_entry,
|
||||
flags | BDRV_REQ_ZERO_WRITE, cb, opaque);
|
||||
}
|
||||
|
||||
int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int bytes)
|
||||
int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count)
|
||||
{
|
||||
int ret;
|
||||
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
ret = blk_do_preadv(blk, offset, bytes, &qiov, 0);
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
return ret < 0 ? ret : bytes;
|
||||
int ret = blk_prw(blk, offset, buf, count, blk_read_entry, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int bytes,
|
||||
int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
|
||||
|
||||
ret = blk_pwritev_part(blk, offset, bytes, &qiov, 0, flags);
|
||||
|
||||
return ret < 0 ? ret : bytes;
|
||||
int ret = blk_prw(blk, offset, (void *) buf, count, blk_write_entry,
|
||||
flags);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int64_t blk_getlength(BlockBackend *blk)
|
||||
@ -1531,7 +1551,6 @@ BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
assert((uint64_t)qiov->size <= INT64_MAX);
|
||||
return blk_aio_prwv(blk, offset, qiov->size, qiov,
|
||||
blk_aio_read_entry, flags, cb, opaque);
|
||||
}
|
||||
@ -1540,7 +1559,6 @@ BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
assert((uint64_t)qiov->size <= INT64_MAX);
|
||||
return blk_aio_prwv(blk, offset, qiov->size, qiov,
|
||||
blk_aio_write_entry, flags, cb, opaque);
|
||||
}
|
||||
@ -1556,8 +1574,8 @@ void blk_aio_cancel_async(BlockAIOCB *acb)
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
int coroutine_fn
|
||||
blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
|
||||
static int coroutine_fn
|
||||
blk_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
|
||||
{
|
||||
blk_wait_while_drained(blk);
|
||||
|
||||
@ -1568,15 +1586,18 @@ blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
|
||||
return bdrv_co_ioctl(blk_bs(blk), req, buf);
|
||||
}
|
||||
|
||||
static void blk_ioctl_entry(void *opaque)
|
||||
{
|
||||
BlkRwCo *rwco = opaque;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
rwco->ret = blk_do_ioctl(rwco->blk, rwco->offset, qiov->iov[0].iov_base);
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
ret = blk_do_ioctl(blk, req, buf);
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
return ret;
|
||||
return blk_prw(blk, req, buf, 0, blk_ioctl_entry, 0);
|
||||
}
|
||||
|
||||
static void blk_aio_ioctl_entry(void *opaque)
|
||||
@ -1584,7 +1605,7 @@ static void blk_aio_ioctl_entry(void *opaque)
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
|
||||
rwco->ret = blk_co_do_ioctl(rwco->blk, rwco->offset, rwco->iobuf);
|
||||
rwco->ret = blk_do_ioctl(rwco->blk, rwco->offset, rwco->iobuf);
|
||||
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
@ -1596,8 +1617,8 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
int coroutine_fn
|
||||
blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes)
|
||||
static int coroutine_fn
|
||||
blk_do_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -1616,31 +1637,19 @@ static void blk_aio_pdiscard_entry(void *opaque)
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
|
||||
rwco->ret = blk_co_do_pdiscard(rwco->blk, rwco->offset, acb->bytes);
|
||||
rwco->ret = blk_do_pdiscard(rwco->blk, rwco->offset, acb->bytes);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk,
|
||||
int64_t offset, int64_t bytes,
|
||||
int64_t offset, int bytes,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_pdiscard_entry, 0,
|
||||
cb, opaque);
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset,
|
||||
int64_t bytes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
ret = blk_co_do_pdiscard(blk, offset, bytes);
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int blk_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes)
|
||||
int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -1651,8 +1660,22 @@ int blk_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void blk_pdiscard_entry(void *opaque)
|
||||
{
|
||||
BlkRwCo *rwco = opaque;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
rwco->ret = blk_do_pdiscard(rwco->blk, rwco->offset, qiov->size);
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
|
||||
{
|
||||
return blk_prw(blk, offset, NULL, bytes, blk_pdiscard_entry, 0);
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
int coroutine_fn blk_co_do_flush(BlockBackend *blk)
|
||||
static int coroutine_fn blk_do_flush(BlockBackend *blk)
|
||||
{
|
||||
blk_wait_while_drained(blk);
|
||||
|
||||
@ -1668,7 +1691,7 @@ static void blk_aio_flush_entry(void *opaque)
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
|
||||
rwco->ret = blk_co_do_flush(rwco->blk);
|
||||
rwco->ret = blk_do_flush(rwco->blk);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
@ -1683,21 +1706,22 @@ int coroutine_fn blk_co_flush(BlockBackend *blk)
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
ret = blk_co_do_flush(blk);
|
||||
ret = blk_do_flush(blk);
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void blk_flush_entry(void *opaque)
|
||||
{
|
||||
BlkRwCo *rwco = opaque;
|
||||
rwco->ret = blk_do_flush(rwco->blk);
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
int blk_flush(BlockBackend *blk)
|
||||
{
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
ret = blk_do_flush(blk);
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
return ret;
|
||||
return blk_prw(blk, 0, NULL, 0, blk_flush_entry, 0);
|
||||
}
|
||||
|
||||
void blk_drain(BlockBackend *blk)
|
||||
@ -2182,17 +2206,16 @@ void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
|
||||
int64_t bytes, BdrvRequestFlags flags)
|
||||
int bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
return blk_co_pwritev(blk, offset, bytes, NULL,
|
||||
flags | BDRV_REQ_ZERO_WRITE);
|
||||
}
|
||||
|
||||
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
|
||||
int64_t bytes)
|
||||
int count)
|
||||
{
|
||||
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
|
||||
return blk_pwritev_part(blk, offset, bytes, &qiov, 0,
|
||||
return blk_prw(blk, offset, (void *) buf, count, blk_write_entry,
|
||||
BDRV_REQ_WRITE_COMPRESSED);
|
||||
}
|
||||
|
||||
@ -2421,7 +2444,7 @@ void blk_unregister_buf(BlockBackend *blk, void *host)
|
||||
|
||||
int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
|
||||
BlockBackend *blk_out, int64_t off_out,
|
||||
int64_t bytes, BdrvRequestFlags read_flags,
|
||||
int bytes, BdrvRequestFlags read_flags,
|
||||
BdrvRequestFlags write_flags)
|
||||
{
|
||||
int r;
|
||||
|
@ -21,14 +21,12 @@
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/coroutine.h"
|
||||
#include "block/aio_task.h"
|
||||
#include "qemu/error-report.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
|
||||
#define BLOCK_COPY_SLICE_TIME 100000000ULL /* ns */
|
||||
#define BLOCK_COPY_CLUSTER_SIZE_DEFAULT (1 << 16)
|
||||
|
||||
typedef enum {
|
||||
COPY_READ_WRITE_CLUSTER,
|
||||
@ -292,11 +290,9 @@ static void coroutine_fn block_copy_task_end(BlockCopyTask *task, int ret)
|
||||
bdrv_set_dirty_bitmap(task->s->copy_bitmap, task->offset, task->bytes);
|
||||
}
|
||||
QLIST_REMOVE(task, list);
|
||||
if (task->s->progress) {
|
||||
progress_set_remaining(task->s->progress,
|
||||
bdrv_get_dirty_count(task->s->copy_bitmap) +
|
||||
task->s->in_flight_bytes);
|
||||
}
|
||||
qemu_co_queue_restart_all(&task->wait_queue);
|
||||
}
|
||||
|
||||
@ -319,14 +315,35 @@ static uint32_t block_copy_max_transfer(BdrvChild *source, BdrvChild *target)
|
||||
target->bs->bl.max_transfer));
|
||||
}
|
||||
|
||||
void block_copy_set_copy_opts(BlockCopyState *s, bool use_copy_range,
|
||||
bool compress)
|
||||
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
|
||||
int64_t cluster_size, bool use_copy_range,
|
||||
BdrvRequestFlags write_flags, Error **errp)
|
||||
{
|
||||
/* Keep BDRV_REQ_SERIALISING set (or not set) in block_copy_state_new() */
|
||||
s->write_flags = (s->write_flags & BDRV_REQ_SERIALISING) |
|
||||
(compress ? BDRV_REQ_WRITE_COMPRESSED : 0);
|
||||
BlockCopyState *s;
|
||||
BdrvDirtyBitmap *copy_bitmap;
|
||||
|
||||
if (s->max_transfer < s->cluster_size) {
|
||||
copy_bitmap = bdrv_create_dirty_bitmap(source->bs, cluster_size, NULL,
|
||||
errp);
|
||||
if (!copy_bitmap) {
|
||||
return NULL;
|
||||
}
|
||||
bdrv_disable_dirty_bitmap(copy_bitmap);
|
||||
|
||||
s = g_new(BlockCopyState, 1);
|
||||
*s = (BlockCopyState) {
|
||||
.source = source,
|
||||
.target = target,
|
||||
.copy_bitmap = copy_bitmap,
|
||||
.cluster_size = cluster_size,
|
||||
.len = bdrv_dirty_bitmap_size(copy_bitmap),
|
||||
.write_flags = write_flags,
|
||||
.mem = shres_create(BLOCK_COPY_MAX_MEM),
|
||||
.max_transfer = QEMU_ALIGN_DOWN(
|
||||
block_copy_max_transfer(source, target),
|
||||
cluster_size),
|
||||
};
|
||||
|
||||
if (s->max_transfer < cluster_size) {
|
||||
/*
|
||||
* copy_range does not respect max_transfer. We don't want to bother
|
||||
* with requests smaller than block-copy cluster size, so fallback to
|
||||
@ -334,7 +351,7 @@ void block_copy_set_copy_opts(BlockCopyState *s, bool use_copy_range,
|
||||
* behalf).
|
||||
*/
|
||||
s->method = COPY_READ_WRITE_CLUSTER;
|
||||
} else if (compress) {
|
||||
} else if (write_flags & BDRV_REQ_WRITE_COMPRESSED) {
|
||||
/* Compression supports only cluster-size writes and no copy-range. */
|
||||
s->method = COPY_READ_WRITE_CLUSTER;
|
||||
} else {
|
||||
@ -344,96 +361,6 @@ void block_copy_set_copy_opts(BlockCopyState *s, bool use_copy_range,
|
||||
*/
|
||||
s->method = use_copy_range ? COPY_RANGE_SMALL : COPY_READ_WRITE;
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
|
||||
Error **errp)
|
||||
{
|
||||
int ret;
|
||||
BlockDriverInfo bdi;
|
||||
bool target_does_cow = bdrv_backing_chain_next(target);
|
||||
|
||||
/*
|
||||
* If there is no backing file on the target, we cannot rely on COW if our
|
||||
* backup cluster size is smaller than the target cluster size. Even for
|
||||
* targets with a backing file, try to avoid COW if possible.
|
||||
*/
|
||||
ret = bdrv_get_info(target, &bdi);
|
||||
if (ret == -ENOTSUP && !target_does_cow) {
|
||||
/* Cluster size is not defined */
|
||||
warn_report("The target block device doesn't provide "
|
||||
"information about the block size and it doesn't have a "
|
||||
"backing file. The default block size of %u bytes is "
|
||||
"used. If the actual block size of the target exceeds "
|
||||
"this default, the backup may be unusable",
|
||||
BLOCK_COPY_CLUSTER_SIZE_DEFAULT);
|
||||
return BLOCK_COPY_CLUSTER_SIZE_DEFAULT;
|
||||
} else if (ret < 0 && !target_does_cow) {
|
||||
error_setg_errno(errp, -ret,
|
||||
"Couldn't determine the cluster size of the target image, "
|
||||
"which has no backing file");
|
||||
error_append_hint(errp,
|
||||
"Aborting, since this may create an unusable destination image\n");
|
||||
return ret;
|
||||
} else if (ret < 0 && target_does_cow) {
|
||||
/* Not fatal; just trudge on ahead. */
|
||||
return BLOCK_COPY_CLUSTER_SIZE_DEFAULT;
|
||||
}
|
||||
|
||||
return MAX(BLOCK_COPY_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
|
||||
}
|
||||
|
||||
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
|
||||
Error **errp)
|
||||
{
|
||||
BlockCopyState *s;
|
||||
int64_t cluster_size;
|
||||
BdrvDirtyBitmap *copy_bitmap;
|
||||
bool is_fleecing;
|
||||
|
||||
cluster_size = block_copy_calculate_cluster_size(target->bs, errp);
|
||||
if (cluster_size < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
copy_bitmap = bdrv_create_dirty_bitmap(source->bs, cluster_size, NULL,
|
||||
errp);
|
||||
if (!copy_bitmap) {
|
||||
return NULL;
|
||||
}
|
||||
bdrv_disable_dirty_bitmap(copy_bitmap);
|
||||
|
||||
/*
|
||||
* If source is in backing chain of target assume that target is going to be
|
||||
* used for "image fleecing", i.e. it should represent a kind of snapshot of
|
||||
* source at backup-start point in time. And target is going to be read by
|
||||
* somebody (for example, used as NBD export) during backup job.
|
||||
*
|
||||
* In this case, we need to add BDRV_REQ_SERIALISING write flag to avoid
|
||||
* intersection of backup writes and third party reads from target,
|
||||
* otherwise reading from target we may occasionally read already updated by
|
||||
* guest data.
|
||||
*
|
||||
* For more information see commit f8d59dfb40bb and test
|
||||
* tests/qemu-iotests/222
|
||||
*/
|
||||
is_fleecing = bdrv_chain_contains(target->bs, source->bs);
|
||||
|
||||
s = g_new(BlockCopyState, 1);
|
||||
*s = (BlockCopyState) {
|
||||
.source = source,
|
||||
.target = target,
|
||||
.copy_bitmap = copy_bitmap,
|
||||
.cluster_size = cluster_size,
|
||||
.len = bdrv_dirty_bitmap_size(copy_bitmap),
|
||||
.write_flags = (is_fleecing ? BDRV_REQ_SERIALISING : 0),
|
||||
.mem = shres_create(BLOCK_COPY_MAX_MEM),
|
||||
.max_transfer = QEMU_ALIGN_DOWN(
|
||||
block_copy_max_transfer(source, target),
|
||||
cluster_size),
|
||||
};
|
||||
|
||||
block_copy_set_copy_opts(s, false, false);
|
||||
|
||||
ratelimit_init(&s->rate_limit);
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
@ -595,7 +522,7 @@ static coroutine_fn int block_copy_task_entry(AioTask *task)
|
||||
t->call_state->ret = ret;
|
||||
t->call_state->error_is_read = error_is_read;
|
||||
}
|
||||
} else if (s->progress) {
|
||||
} else {
|
||||
progress_work_done(s->progress, t->bytes);
|
||||
}
|
||||
}
|
||||
@ -701,11 +628,9 @@ int64_t block_copy_reset_unallocated(BlockCopyState *s,
|
||||
if (!ret) {
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes);
|
||||
if (s->progress) {
|
||||
progress_set_remaining(s->progress,
|
||||
bdrv_get_dirty_count(s->copy_bitmap) +
|
||||
s->in_flight_bytes);
|
||||
}
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
}
|
||||
|
||||
@ -1008,11 +933,6 @@ BdrvDirtyBitmap *block_copy_dirty_bitmap(BlockCopyState *s)
|
||||
return s->copy_bitmap;
|
||||
}
|
||||
|
||||
int64_t block_copy_cluster_size(BlockCopyState *s)
|
||||
{
|
||||
return s->cluster_size;
|
||||
}
|
||||
|
||||
void block_copy_set_skip_unallocated(BlockCopyState *s, bool skip)
|
||||
{
|
||||
qatomic_set(&s->skip_unallocated, skip);
|
||||
|
@ -238,8 +238,8 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
bochs_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
bochs_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
|
||||
|
@ -245,8 +245,8 @@ static inline int cloop_read_block(BlockDriverState *bs, int block_num)
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
cloop_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
cloop_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVCloopState *s = bs->opaque;
|
||||
uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
|
||||
|
@ -207,7 +207,7 @@ static const BlockJobDriver commit_job_driver = {
|
||||
};
|
||||
|
||||
static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
|
||||
}
|
||||
|
@ -1,257 +0,0 @@
|
||||
/*
|
||||
* copy-before-write filter driver
|
||||
*
|
||||
* The driver performs Copy-Before-Write (CBW) operation: it is injected above
|
||||
* some node, and before each write it copies _old_ data to the target node.
|
||||
*
|
||||
* Copyright (c) 2018-2021 Virtuozzo International GmbH.
|
||||
*
|
||||
* Author:
|
||||
* Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qapi/error.h"
|
||||
#include "block/block_int.h"
|
||||
#include "block/qdict.h"
|
||||
#include "block/block-copy.h"
|
||||
|
||||
#include "block/copy-before-write.h"
|
||||
|
||||
typedef struct BDRVCopyBeforeWriteState {
|
||||
BlockCopyState *bcs;
|
||||
BdrvChild *target;
|
||||
} BDRVCopyBeforeWriteState;
|
||||
|
||||
static coroutine_fn int cbw_co_preadv(
|
||||
BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
{
|
||||
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
|
||||
}
|
||||
|
||||
static coroutine_fn int cbw_do_copy_before_write(BlockDriverState *bs,
|
||||
uint64_t offset, uint64_t bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
BDRVCopyBeforeWriteState *s = bs->opaque;
|
||||
uint64_t off, end;
|
||||
int64_t cluster_size = block_copy_cluster_size(s->bcs);
|
||||
|
||||
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
off = QEMU_ALIGN_DOWN(offset, cluster_size);
|
||||
end = QEMU_ALIGN_UP(offset + bytes, cluster_size);
|
||||
|
||||
return block_copy(s->bcs, off, end - off, true);
|
||||
}
|
||||
|
||||
static int coroutine_fn cbw_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes)
|
||||
{
|
||||
int ret = cbw_do_copy_before_write(bs, offset, bytes, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return bdrv_co_pdiscard(bs->file, offset, bytes);
|
||||
}
|
||||
|
||||
static int coroutine_fn cbw_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
int ret = cbw_do_copy_before_write(bs, offset, bytes, flags);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
|
||||
}
|
||||
|
||||
static coroutine_fn int cbw_co_pwritev(BlockDriverState *bs,
|
||||
int64_t offset,
|
||||
int64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret = cbw_do_copy_before_write(bs, offset, bytes, flags);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
|
||||
}
|
||||
|
||||
static int coroutine_fn cbw_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
if (!bs->file) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bdrv_co_flush(bs->file->bs);
|
||||
}
|
||||
|
||||
static void cbw_refresh_filename(BlockDriverState *bs)
|
||||
{
|
||||
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
bs->file->bs->filename);
|
||||
}
|
||||
|
||||
static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c,
|
||||
BdrvChildRole role,
|
||||
BlockReopenQueue *reopen_queue,
|
||||
uint64_t perm, uint64_t shared,
|
||||
uint64_t *nperm, uint64_t *nshared)
|
||||
{
|
||||
if (!(role & BDRV_CHILD_FILTERED)) {
|
||||
/*
|
||||
* Target child
|
||||
*
|
||||
* Share write to target (child_file), to not interfere
|
||||
* with guest writes to its disk which may be in target backing chain.
|
||||
* Can't resize during a backup block job because we check the size
|
||||
* only upfront.
|
||||
*/
|
||||
*nshared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
|
||||
*nperm = BLK_PERM_WRITE;
|
||||
} else {
|
||||
/* Source child */
|
||||
bdrv_default_perms(bs, c, role, reopen_queue,
|
||||
perm, shared, nperm, nshared);
|
||||
|
||||
if (!QLIST_EMPTY(&bs->parents)) {
|
||||
if (perm & BLK_PERM_WRITE) {
|
||||
*nperm = *nperm | BLK_PERM_CONSISTENT_READ;
|
||||
}
|
||||
*nshared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVCopyBeforeWriteState *s = bs->opaque;
|
||||
BdrvDirtyBitmap *copy_bitmap;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s->target = bdrv_open_child(NULL, options, "target", bs, &child_of_bds,
|
||||
BDRV_CHILD_DATA, false, errp);
|
||||
if (!s->target) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bs->total_sectors = bs->file->bs->total_sectors;
|
||||
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
|
||||
(BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
|
||||
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
|
||||
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
|
||||
bs->file->bs->supported_zero_flags);
|
||||
|
||||
s->bcs = block_copy_state_new(bs->file, s->target, errp);
|
||||
if (!s->bcs) {
|
||||
error_prepend(errp, "Cannot create block-copy-state: ");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
copy_bitmap = block_copy_dirty_bitmap(s->bcs);
|
||||
bdrv_set_dirty_bitmap(copy_bitmap, 0, bdrv_dirty_bitmap_size(copy_bitmap));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cbw_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVCopyBeforeWriteState *s = bs->opaque;
|
||||
|
||||
block_copy_state_free(s->bcs);
|
||||
s->bcs = NULL;
|
||||
}
|
||||
|
||||
BlockDriver bdrv_cbw_filter = {
|
||||
.format_name = "copy-before-write",
|
||||
.instance_size = sizeof(BDRVCopyBeforeWriteState),
|
||||
|
||||
.bdrv_open = cbw_open,
|
||||
.bdrv_close = cbw_close,
|
||||
|
||||
.bdrv_co_preadv = cbw_co_preadv,
|
||||
.bdrv_co_pwritev = cbw_co_pwritev,
|
||||
.bdrv_co_pwrite_zeroes = cbw_co_pwrite_zeroes,
|
||||
.bdrv_co_pdiscard = cbw_co_pdiscard,
|
||||
.bdrv_co_flush = cbw_co_flush,
|
||||
|
||||
.bdrv_refresh_filename = cbw_refresh_filename,
|
||||
|
||||
.bdrv_child_perm = cbw_child_perm,
|
||||
|
||||
.is_filter = true,
|
||||
};
|
||||
|
||||
BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
|
||||
BlockDriverState *target,
|
||||
const char *filter_node_name,
|
||||
BlockCopyState **bcs,
|
||||
Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
BDRVCopyBeforeWriteState *state;
|
||||
BlockDriverState *top;
|
||||
QDict *opts;
|
||||
|
||||
assert(source->total_sectors == target->total_sectors);
|
||||
|
||||
opts = qdict_new();
|
||||
qdict_put_str(opts, "driver", "copy-before-write");
|
||||
if (filter_node_name) {
|
||||
qdict_put_str(opts, "node-name", filter_node_name);
|
||||
}
|
||||
qdict_put_str(opts, "file", bdrv_get_node_name(source));
|
||||
qdict_put_str(opts, "target", bdrv_get_node_name(target));
|
||||
|
||||
top = bdrv_insert_node(source, opts, BDRV_O_RDWR, errp);
|
||||
if (!top) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state = top->opaque;
|
||||
*bcs = state->bcs;
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
void bdrv_cbw_drop(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_drop_filter(bs, &error_abort);
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
|
||||
static void cbw_init(void)
|
||||
{
|
||||
bdrv_register(&bdrv_cbw_filter);
|
||||
}
|
||||
|
||||
block_init(cbw_init);
|
@ -128,10 +128,10 @@ static int64_t cor_getlength(BlockDriverState *bs)
|
||||
|
||||
|
||||
static int coroutine_fn cor_co_preadv_part(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
int flags)
|
||||
{
|
||||
int64_t n;
|
||||
int local_flags;
|
||||
@ -181,11 +181,10 @@ static int coroutine_fn cor_co_preadv_part(BlockDriverState *bs,
|
||||
|
||||
|
||||
static int coroutine_fn cor_co_pwritev_part(BlockDriverState *bs,
|
||||
int64_t offset,
|
||||
int64_t bytes,
|
||||
uint64_t offset,
|
||||
uint64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
size_t qiov_offset, int flags)
|
||||
{
|
||||
return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
|
||||
flags);
|
||||
@ -193,7 +192,7 @@ static int coroutine_fn cor_co_pwritev_part(BlockDriverState *bs,
|
||||
|
||||
|
||||
static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
int64_t offset, int bytes,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
|
||||
@ -201,15 +200,15 @@ static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
|
||||
|
||||
static int coroutine_fn cor_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes)
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
return bdrv_co_pdiscard(bs->file, offset, bytes);
|
||||
}
|
||||
|
||||
|
||||
static int coroutine_fn cor_co_pwritev_compressed(BlockDriverState *bs,
|
||||
int64_t offset,
|
||||
int64_t bytes,
|
||||
uint64_t offset,
|
||||
uint64_t bytes,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
return bdrv_co_pwritev(bs->file, offset, bytes, qiov,
|
||||
|
@ -27,9 +27,6 @@
|
||||
|
||||
#include "block/block_int.h"
|
||||
|
||||
/* For blk_bs() in generated block/block-gen.c */
|
||||
#include "sysemu/block-backend.h"
|
||||
|
||||
int coroutine_fn bdrv_co_check(BlockDriverState *bs,
|
||||
BdrvCheckResult *res, BdrvCheckMode fix);
|
||||
int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp);
|
||||
@ -75,34 +72,4 @@ int coroutine_fn
|
||||
nbd_co_do_establish_connection(BlockDriverState *bs, Error **errp);
|
||||
|
||||
|
||||
int generated_co_wrapper
|
||||
blk_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags);
|
||||
int coroutine_fn
|
||||
blk_co_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags);
|
||||
|
||||
|
||||
int generated_co_wrapper
|
||||
blk_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset,
|
||||
BdrvRequestFlags flags);
|
||||
int coroutine_fn
|
||||
blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset,
|
||||
BdrvRequestFlags flags);
|
||||
|
||||
int generated_co_wrapper
|
||||
blk_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf);
|
||||
int coroutine_fn
|
||||
blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf);
|
||||
|
||||
int generated_co_wrapper
|
||||
blk_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes);
|
||||
int coroutine_fn
|
||||
blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes);
|
||||
|
||||
int generated_co_wrapper blk_do_flush(BlockBackend *blk);
|
||||
int coroutine_fn blk_co_do_flush(BlockBackend *blk);
|
||||
|
||||
#endif /* BLOCK_COROUTINES_INT_H */
|
||||
|
@ -397,8 +397,8 @@ static int block_crypto_reopen_prepare(BDRVReopenState *state,
|
||||
#define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024)
|
||||
|
||||
static coroutine_fn int
|
||||
block_crypto_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
block_crypto_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BlockCrypto *crypto = bs->opaque;
|
||||
uint64_t cur_bytes; /* number of bytes in current iteration */
|
||||
@ -460,8 +460,8 @@ block_crypto_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
|
||||
|
||||
static coroutine_fn int
|
||||
block_crypto_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
block_crypto_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BlockCrypto *crypto = bs->opaque;
|
||||
uint64_t cur_bytes; /* number of bytes in current iteration */
|
||||
|
@ -896,8 +896,7 @@ out:
|
||||
}
|
||||
|
||||
static int coroutine_fn curl_co_preadv(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
CURLAIOCB acb = {
|
||||
.co = qemu_coroutine_self(),
|
||||
|
@ -689,8 +689,8 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
dmg_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
dmg_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVDMGState *s = bs->opaque;
|
||||
uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
|
||||
|
@ -31,13 +31,6 @@
|
||||
#include <fuse.h>
|
||||
#include <fuse_lowlevel.h>
|
||||
|
||||
#if defined(CONFIG_FALLOCATE_ZERO_RANGE)
|
||||
#include <linux/falloc.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/fs.h>
|
||||
#endif
|
||||
|
||||
/* Prevent overly long bounce buffer allocations */
|
||||
#define FUSE_MAX_BOUNCE_BYTES (MIN(BDRV_REQUEST_MAX_BYTES, 64 * 1024 * 1024))
|
||||
|
@ -150,8 +150,6 @@ typedef struct BDRVRawState {
|
||||
uint64_t locked_perm;
|
||||
uint64_t locked_shared_perm;
|
||||
|
||||
uint64_t aio_max_batch;
|
||||
|
||||
int perm_change_fd;
|
||||
int perm_change_flags;
|
||||
BDRVReopenState *reopen_state;
|
||||
@ -167,7 +165,6 @@ typedef struct BDRVRawState {
|
||||
int page_cache_inconsistent; /* errno from fdatasync failure */
|
||||
bool has_fallocate;
|
||||
bool needs_alignment;
|
||||
bool force_alignment;
|
||||
bool drop_cache;
|
||||
bool check_cache_dropped;
|
||||
struct {
|
||||
@ -352,17 +349,6 @@ static bool dio_byte_aligned(int fd)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool raw_needs_alignment(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return s->force_alignment;
|
||||
}
|
||||
|
||||
/* Check if read is allowed with given memory buffer and length.
|
||||
*
|
||||
* This function is used to check O_DIRECT memory buffer and request alignment.
|
||||
@ -544,11 +530,6 @@ static QemuOptsList raw_runtime_opts = {
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "host AIO implementation (threads, native, io_uring)",
|
||||
},
|
||||
{
|
||||
.name = "aio-max-batch",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "AIO max batch size (0 = auto handled by AIO backend, default: 0)",
|
||||
},
|
||||
{
|
||||
.name = "locking",
|
||||
.type = QEMU_OPT_STRING,
|
||||
@ -628,8 +609,6 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
s->use_linux_io_uring = (aio == BLOCKDEV_AIO_OPTIONS_IO_URING);
|
||||
#endif
|
||||
|
||||
s->aio_max_batch = qemu_opt_get_number(opts, "aio-max-batch", 0);
|
||||
|
||||
locking = qapi_enum_parse(&OnOffAuto_lookup,
|
||||
qemu_opt_get(opts, "locking"),
|
||||
ON_OFF_AUTO_AUTO, &local_err);
|
||||
@ -740,6 +719,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
|
||||
s->has_discard = true;
|
||||
s->has_write_zeroes = true;
|
||||
if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) {
|
||||
s->needs_alignment = true;
|
||||
}
|
||||
|
||||
if (fstat(s->fd, &st) < 0) {
|
||||
ret = -errno;
|
||||
@ -793,10 +775,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
* so QEMU makes sure all IO operations on the device are aligned
|
||||
* to sector size, or else FreeBSD will reject them with EINVAL.
|
||||
*/
|
||||
s->force_alignment = true;
|
||||
s->needs_alignment = true;
|
||||
}
|
||||
#endif
|
||||
s->needs_alignment = raw_needs_alignment(bs);
|
||||
|
||||
#ifdef CONFIG_XFS
|
||||
if (platform_test_xfs_fd(s->fd)) {
|
||||
@ -1261,9 +1242,7 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
BDRVRawState *s = bs->opaque;
|
||||
struct stat st;
|
||||
|
||||
s->needs_alignment = raw_needs_alignment(bs);
|
||||
raw_probe_alignment(bs, s->fd, errp);
|
||||
|
||||
bs->bl.min_mem_alignment = s->buf_align;
|
||||
bs->bl.opt_mem_alignment = MAX(s->buf_align, qemu_real_host_page_size);
|
||||
|
||||
@ -1726,7 +1705,7 @@ static int handle_aiocb_write_zeroes(void *opaque)
|
||||
*/
|
||||
warn_report_once("Your file system is misbehaving: "
|
||||
"fallocate(FALLOC_FL_PUNCH_HOLE) returned EINVAL. "
|
||||
"Please report this bug to your file system "
|
||||
"Please report this bug to your file sytem "
|
||||
"vendor.");
|
||||
} else if (ret != -ENOTSUP) {
|
||||
return ret;
|
||||
@ -2078,8 +2057,7 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
|
||||
} else if (s->use_linux_aio) {
|
||||
LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
|
||||
assert(qiov->size == bytes);
|
||||
return laio_co_submit(bs, aio, s->fd, offset, qiov, type,
|
||||
s->aio_max_batch);
|
||||
return laio_co_submit(bs, aio, s->fd, offset, qiov, type);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -2099,16 +2077,16 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
|
||||
return raw_thread_pool_submit(bs, handle_aiocb_rw, &acb);
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
static int coroutine_fn raw_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov,
|
||||
int flags)
|
||||
{
|
||||
return raw_co_prw(bs, offset, bytes, qiov, QEMU_AIO_READ);
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov,
|
||||
int flags)
|
||||
{
|
||||
assert(flags == 0);
|
||||
return raw_co_prw(bs, offset, bytes, qiov, QEMU_AIO_WRITE);
|
||||
@ -2137,7 +2115,7 @@ static void raw_aio_unplug(BlockDriverState *bs)
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
if (s->use_linux_aio) {
|
||||
LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
|
||||
laio_io_unplug(bs, aio, s->aio_max_batch);
|
||||
laio_io_unplug(bs, aio);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_LINUX_IO_URING
|
||||
@ -2766,8 +2744,7 @@ static int find_allocation(BlockDriverState *bs, off_t start,
|
||||
* the specified offset) that are known to be in the same
|
||||
* allocated/unallocated state.
|
||||
*
|
||||
* 'bytes' is a soft cap for 'pnum'. If the information is free, 'pnum' may
|
||||
* well exceed it.
|
||||
* 'bytes' is the max value 'pnum' should be set to.
|
||||
*/
|
||||
static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
|
||||
bool want_zero,
|
||||
@ -2805,7 +2782,7 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
|
||||
} else if (data == offset) {
|
||||
/* On a data extent, compute bytes to the end of the extent,
|
||||
* possibly including a partial sector at EOF. */
|
||||
*pnum = hole - offset;
|
||||
*pnum = MIN(bytes, hole - offset);
|
||||
|
||||
/*
|
||||
* We are not allowed to return partial sectors, though, so
|
||||
@ -2824,7 +2801,7 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
|
||||
} else {
|
||||
/* On a hole, compute bytes to the beginning of the next extent. */
|
||||
assert(hole == offset);
|
||||
*pnum = data - offset;
|
||||
*pnum = MIN(bytes, data - offset);
|
||||
ret = BDRV_BLOCK_ZERO;
|
||||
}
|
||||
*map = offset;
|
||||
@ -2964,8 +2941,7 @@ static void raw_account_discard(BDRVRawState *s, uint64_t nbytes, int ret)
|
||||
}
|
||||
|
||||
static coroutine_fn int
|
||||
raw_do_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
bool blkdev)
|
||||
raw_do_pdiscard(BlockDriverState *bs, int64_t offset, int bytes, bool blkdev)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
RawPosixAIOData acb;
|
||||
@ -2989,13 +2965,13 @@ raw_do_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
}
|
||||
|
||||
static coroutine_fn int
|
||||
raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
|
||||
raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
|
||||
{
|
||||
return raw_do_pdiscard(bs, offset, bytes, false);
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
|
||||
BdrvRequestFlags flags, bool blkdev)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
@ -3063,7 +3039,7 @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
|
||||
static int coroutine_fn raw_co_pwrite_zeroes(
|
||||
BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, BdrvRequestFlags flags)
|
||||
int bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
return raw_do_pwrite_zeroes(bs, offset, bytes, flags, false);
|
||||
}
|
||||
@ -3226,8 +3202,8 @@ static void raw_abort_perm_update(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_copy_range_from(
|
||||
BlockDriverState *bs, BdrvChild *src, int64_t src_offset,
|
||||
BdrvChild *dst, int64_t dst_offset, int64_t bytes,
|
||||
BlockDriverState *bs, BdrvChild *src, uint64_t src_offset,
|
||||
BdrvChild *dst, uint64_t dst_offset, uint64_t bytes,
|
||||
BdrvRequestFlags read_flags, BdrvRequestFlags write_flags)
|
||||
{
|
||||
return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes,
|
||||
@ -3236,10 +3212,10 @@ static int coroutine_fn raw_co_copy_range_from(
|
||||
|
||||
static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
|
||||
BdrvChild *src,
|
||||
int64_t src_offset,
|
||||
uint64_t src_offset,
|
||||
BdrvChild *dst,
|
||||
int64_t dst_offset,
|
||||
int64_t bytes,
|
||||
uint64_t dst_offset,
|
||||
uint64_t bytes,
|
||||
BdrvRequestFlags read_flags,
|
||||
BdrvRequestFlags write_flags)
|
||||
{
|
||||
@ -3614,7 +3590,7 @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
|
||||
#endif /* linux */
|
||||
|
||||
static coroutine_fn int
|
||||
hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
|
||||
hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret;
|
||||
@ -3628,7 +3604,7 @@ hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
|
||||
}
|
||||
|
||||
static coroutine_fn int hdev_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes, BdrvRequestFlags flags)
|
||||
int64_t offset, int bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -58,10 +58,6 @@ typedef struct BDRVRawState {
|
||||
QEMUWin32AIOState *aio;
|
||||
} BDRVRawState;
|
||||
|
||||
typedef struct BDRVRawReopenState {
|
||||
HANDLE hfile;
|
||||
} BDRVRawReopenState;
|
||||
|
||||
/*
|
||||
* Read/writes the data to/from a given linear buffer.
|
||||
*
|
||||
@ -396,7 +392,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
s->hfile = CreateFile(filename, access_flags,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
||||
FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, overlapped, NULL);
|
||||
if (s->hfile == INVALID_HANDLE_VALUE) {
|
||||
int err = GetLastError();
|
||||
@ -440,8 +436,8 @@ fail:
|
||||
}
|
||||
|
||||
static BlockAIOCB *raw_aio_preadv(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
@ -455,8 +451,8 @@ static BlockAIOCB *raw_aio_preadv(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static BlockAIOCB *raw_aio_pwritev(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
@ -638,97 +634,6 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
|
||||
return raw_co_create(&options, errp);
|
||||
}
|
||||
|
||||
static int raw_reopen_prepare(BDRVReopenState *state,
|
||||
BlockReopenQueue *queue, Error **errp)
|
||||
{
|
||||
BDRVRawState *s = state->bs->opaque;
|
||||
BDRVRawReopenState *rs;
|
||||
int access_flags;
|
||||
DWORD overlapped;
|
||||
int ret = 0;
|
||||
|
||||
if (s->type != FTYPE_FILE) {
|
||||
error_setg(errp, "Can only reopen files");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rs = g_new0(BDRVRawReopenState, 1);
|
||||
|
||||
/*
|
||||
* We do not support changing any options (only flags). By leaving
|
||||
* all options in state->options, we tell the generic reopen code
|
||||
* that we do not support changing any of them, so it will verify
|
||||
* that their values did not change.
|
||||
*/
|
||||
|
||||
raw_parse_flags(state->flags, s->aio != NULL, &access_flags, &overlapped);
|
||||
rs->hfile = CreateFile(state->bs->filename, access_flags,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, overlapped, NULL);
|
||||
|
||||
if (rs->hfile == INVALID_HANDLE_VALUE) {
|
||||
int err = GetLastError();
|
||||
|
||||
error_setg_win32(errp, err, "Could not reopen '%s'",
|
||||
state->bs->filename);
|
||||
if (err == ERROR_ACCESS_DENIED) {
|
||||
ret = -EACCES;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (s->aio) {
|
||||
ret = win32_aio_attach(s->aio, rs->hfile);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not enable AIO");
|
||||
CloseHandle(rs->hfile);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
state->opaque = rs;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
g_free(rs);
|
||||
state->opaque = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void raw_reopen_commit(BDRVReopenState *state)
|
||||
{
|
||||
BDRVRawState *s = state->bs->opaque;
|
||||
BDRVRawReopenState *rs = state->opaque;
|
||||
|
||||
assert(rs != NULL);
|
||||
|
||||
CloseHandle(s->hfile);
|
||||
s->hfile = rs->hfile;
|
||||
|
||||
g_free(rs);
|
||||
state->opaque = NULL;
|
||||
}
|
||||
|
||||
static void raw_reopen_abort(BDRVReopenState *state)
|
||||
{
|
||||
BDRVRawReopenState *rs = state->opaque;
|
||||
|
||||
if (!rs) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rs->hfile != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(rs->hfile);
|
||||
}
|
||||
|
||||
g_free(rs);
|
||||
state->opaque = NULL;
|
||||
}
|
||||
|
||||
static QemuOptsList raw_create_opts = {
|
||||
.name = "raw-create-opts",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head),
|
||||
@ -754,10 +659,6 @@ BlockDriver bdrv_file = {
|
||||
.bdrv_co_create_opts = raw_co_create_opts,
|
||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||
|
||||
.bdrv_reopen_prepare = raw_reopen_prepare,
|
||||
.bdrv_reopen_commit = raw_reopen_commit,
|
||||
.bdrv_reopen_abort = raw_reopen_abort,
|
||||
|
||||
.bdrv_aio_preadv = raw_aio_preadv,
|
||||
.bdrv_aio_pwritev = raw_aio_pwritev,
|
||||
.bdrv_aio_flush = raw_aio_flush,
|
||||
|
@ -63,10 +63,10 @@ static int64_t compress_getlength(BlockDriverState *bs)
|
||||
|
||||
|
||||
static int coroutine_fn compress_co_preadv_part(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
int flags)
|
||||
{
|
||||
return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset,
|
||||
flags);
|
||||
@ -74,11 +74,10 @@ static int coroutine_fn compress_co_preadv_part(BlockDriverState *bs,
|
||||
|
||||
|
||||
static int coroutine_fn compress_co_pwritev_part(BlockDriverState *bs,
|
||||
int64_t offset,
|
||||
int64_t bytes,
|
||||
uint64_t offset,
|
||||
uint64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
size_t qiov_offset, int flags)
|
||||
{
|
||||
return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
|
||||
flags | BDRV_REQ_WRITE_COMPRESSED);
|
||||
@ -86,7 +85,7 @@ static int coroutine_fn compress_co_pwritev_part(BlockDriverState *bs,
|
||||
|
||||
|
||||
static int coroutine_fn compress_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
int64_t offset, int bytes,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
|
||||
@ -94,7 +93,7 @@ static int coroutine_fn compress_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
|
||||
|
||||
static int coroutine_fn compress_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes)
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
return bdrv_co_pdiscard(bs->file, offset, bytes);
|
||||
}
|
||||
|
@ -891,7 +891,6 @@ out:
|
||||
static void qemu_gluster_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
bs->bl.max_transfer = GLUSTER_MAX_TRANSFER;
|
||||
bs->bl.max_pdiscard = SIZE_MAX;
|
||||
}
|
||||
|
||||
static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
|
||||
@ -1004,19 +1003,19 @@ static void qemu_gluster_reopen_abort(BDRVReopenState *state)
|
||||
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||
static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset,
|
||||
int64_t bytes,
|
||||
int size,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
GlusterAIOCB acb;
|
||||
BDRVGlusterState *s = bs->opaque;
|
||||
|
||||
acb.size = bytes;
|
||||
acb.size = size;
|
||||
acb.ret = 0;
|
||||
acb.coroutine = qemu_coroutine_self();
|
||||
acb.aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
ret = glfs_zerofill_async(s->fd, offset, bytes, gluster_finish_aiocb, &acb);
|
||||
ret = glfs_zerofill_async(s->fd, offset, size, gluster_finish_aiocb, &acb);
|
||||
if (ret < 0) {
|
||||
return -errno;
|
||||
}
|
||||
@ -1298,20 +1297,18 @@ error:
|
||||
|
||||
#ifdef CONFIG_GLUSTERFS_DISCARD
|
||||
static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes)
|
||||
int64_t offset, int size)
|
||||
{
|
||||
int ret;
|
||||
GlusterAIOCB acb;
|
||||
BDRVGlusterState *s = bs->opaque;
|
||||
|
||||
assert(bytes <= SIZE_MAX); /* rely on max_pdiscard */
|
||||
|
||||
acb.size = 0;
|
||||
acb.ret = 0;
|
||||
acb.coroutine = qemu_coroutine_self();
|
||||
acb.aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
ret = glfs_discard_async(s->fd, offset, bytes, gluster_finish_aiocb, &acb);
|
||||
ret = glfs_discard_async(s->fd, offset, size, gluster_finish_aiocb, &acb);
|
||||
if (ret < 0) {
|
||||
return -errno;
|
||||
}
|
||||
@ -1464,8 +1461,7 @@ exit:
|
||||
* the specified offset) that are known to be in the same
|
||||
* allocated/unallocated state.
|
||||
*
|
||||
* 'bytes' is a soft cap for 'pnum'. If the information is free, 'pnum' may
|
||||
* well exceed it.
|
||||
* 'bytes' is the max value 'pnum' should be set to.
|
||||
*
|
||||
* (Based on raw_co_block_status() from file-posix.c.)
|
||||
*/
|
||||
@ -1481,8 +1477,6 @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
|
||||
off_t data = 0, hole = 0;
|
||||
int ret = -EINVAL;
|
||||
|
||||
assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
|
||||
|
||||
if (!s->fd) {
|
||||
return ret;
|
||||
}
|
||||
@ -1506,26 +1500,12 @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
|
||||
} else if (data == offset) {
|
||||
/* On a data extent, compute bytes to the end of the extent,
|
||||
* possibly including a partial sector at EOF. */
|
||||
*pnum = hole - offset;
|
||||
|
||||
/*
|
||||
* We are not allowed to return partial sectors, though, so
|
||||
* round up if necessary.
|
||||
*/
|
||||
if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) {
|
||||
int64_t file_length = qemu_gluster_getlength(bs);
|
||||
if (file_length > 0) {
|
||||
/* Ignore errors, this is just a safeguard */
|
||||
assert(hole == file_length);
|
||||
}
|
||||
*pnum = ROUND_UP(*pnum, bs->bl.request_alignment);
|
||||
}
|
||||
|
||||
*pnum = MIN(bytes, hole - offset);
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
} else {
|
||||
/* On a hole, compute bytes to the beginning of the next extent. */
|
||||
assert(hole == offset);
|
||||
*pnum = data - offset;
|
||||
*pnum = MIN(bytes, data - offset);
|
||||
ret = BDRV_BLOCK_ZERO;
|
||||
}
|
||||
|
||||
|
100
block/io.c
100
block/io.c
@ -957,7 +957,7 @@ bool coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req,
|
||||
return waited;
|
||||
}
|
||||
|
||||
int bdrv_check_qiov_request(int64_t offset, int64_t bytes,
|
||||
static int bdrv_check_qiov_request(int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset,
|
||||
Error **errp)
|
||||
{
|
||||
@ -1231,8 +1231,7 @@ out:
|
||||
static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
size_t qiov_offset, int flags)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
int64_t sector_num;
|
||||
@ -1870,8 +1869,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
||||
int head = 0;
|
||||
int tail = 0;
|
||||
|
||||
int64_t max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes,
|
||||
INT64_MAX);
|
||||
int max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, INT_MAX);
|
||||
int alignment = MAX(bs->bl.pwrite_zeroes_alignment,
|
||||
bs->bl.request_alignment);
|
||||
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFFER);
|
||||
@ -1886,9 +1884,6 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Invalidate the cached block-status data range if this write overlaps */
|
||||
bdrv_bsc_invalidate_range(bs, offset, bytes);
|
||||
|
||||
assert(alignment % bs->bl.request_alignment == 0);
|
||||
head = offset % alignment;
|
||||
tail = (offset + bytes) % alignment;
|
||||
@ -2076,8 +2071,7 @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, int64_t bytes,
|
||||
*/
|
||||
static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
|
||||
BdrvTrackedRequest *req, int64_t offset, int64_t bytes,
|
||||
int64_t align, QEMUIOVector *qiov, size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
int64_t align, QEMUIOVector *qiov, size_t qiov_offset, int flags)
|
||||
{
|
||||
BlockDriverState *bs = child->bs;
|
||||
BlockDriver *drv = bs->drv;
|
||||
@ -2250,11 +2244,7 @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
if (flags & BDRV_REQ_ZERO_WRITE) {
|
||||
ret = bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, NULL);
|
||||
} else {
|
||||
ret = bdrv_check_request32(offset, bytes, qiov, qiov_offset);
|
||||
}
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -2458,65 +2448,9 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
|
||||
aligned_bytes = ROUND_UP(offset + bytes, align) - aligned_offset;
|
||||
|
||||
if (bs->drv->bdrv_co_block_status) {
|
||||
/*
|
||||
* Use the block-status cache only for protocol nodes: Format
|
||||
* drivers are generally quick to inquire the status, but protocol
|
||||
* drivers often need to get information from outside of qemu, so
|
||||
* we do not have control over the actual implementation. There
|
||||
* have been cases where inquiring the status took an unreasonably
|
||||
* long time, and we can do nothing in qemu to fix it.
|
||||
* This is especially problematic for images with large data areas,
|
||||
* because finding the few holes in them and giving them special
|
||||
* treatment does not gain much performance. Therefore, we try to
|
||||
* cache the last-identified data region.
|
||||
*
|
||||
* Second, limiting ourselves to protocol nodes allows us to assume
|
||||
* the block status for data regions to be DATA | OFFSET_VALID, and
|
||||
* that the host offset is the same as the guest offset.
|
||||
*
|
||||
* Note that it is possible that external writers zero parts of
|
||||
* the cached regions without the cache being invalidated, and so
|
||||
* we may report zeroes as data. This is not catastrophic,
|
||||
* however, because reporting zeroes as data is fine.
|
||||
*/
|
||||
if (QLIST_EMPTY(&bs->children) &&
|
||||
bdrv_bsc_is_data(bs, aligned_offset, pnum))
|
||||
{
|
||||
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
|
||||
local_file = bs;
|
||||
local_map = aligned_offset;
|
||||
} else {
|
||||
ret = bs->drv->bdrv_co_block_status(bs, want_zero, aligned_offset,
|
||||
aligned_bytes, pnum, &local_map,
|
||||
&local_file);
|
||||
|
||||
/*
|
||||
* Note that checking QLIST_EMPTY(&bs->children) is also done when
|
||||
* the cache is queried above. Technically, we do not need to check
|
||||
* it here; the worst that can happen is that we fill the cache for
|
||||
* non-protocol nodes, and then it is never used. However, filling
|
||||
* the cache requires an RCU update, so double check here to avoid
|
||||
* such an update if possible.
|
||||
*/
|
||||
if (ret == (BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID) &&
|
||||
QLIST_EMPTY(&bs->children))
|
||||
{
|
||||
/*
|
||||
* When a protocol driver reports BLOCK_OFFSET_VALID, the
|
||||
* returned local_map value must be the same as the offset we
|
||||
* have passed (aligned_offset), and local_bs must be the node
|
||||
* itself.
|
||||
* Assert this, because we follow this rule when reading from
|
||||
* the cache (see the `local_file = bs` and
|
||||
* `local_map = aligned_offset` assignments above), and the
|
||||
* result the cache delivers must be the same as the driver
|
||||
* would deliver.
|
||||
*/
|
||||
assert(local_file == bs);
|
||||
assert(local_map == aligned_offset);
|
||||
bdrv_bsc_fill(bs, aligned_offset, *pnum);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Default code for filters */
|
||||
|
||||
@ -2818,12 +2752,7 @@ bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
BlockDriverState *child_bs = bdrv_primary_bs(bs);
|
||||
int ret;
|
||||
|
||||
ret = bdrv_check_qiov_request(pos, qiov->size, qiov, 0, NULL);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
int ret = -ENOTSUP;
|
||||
|
||||
if (!drv) {
|
||||
return -ENOMEDIUM;
|
||||
@ -2835,8 +2764,6 @@ bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
|
||||
ret = drv->bdrv_load_vmstate(bs, qiov, pos);
|
||||
} else if (child_bs) {
|
||||
ret = bdrv_co_readv_vmstate(child_bs, qiov, pos);
|
||||
} else {
|
||||
ret = -ENOTSUP;
|
||||
}
|
||||
|
||||
bdrv_dec_in_flight(bs);
|
||||
@ -2849,12 +2776,7 @@ bdrv_co_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
BlockDriverState *child_bs = bdrv_primary_bs(bs);
|
||||
int ret;
|
||||
|
||||
ret = bdrv_check_qiov_request(pos, qiov->size, qiov, 0, NULL);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
int ret = -ENOTSUP;
|
||||
|
||||
if (!drv) {
|
||||
return -ENOMEDIUM;
|
||||
@ -2866,8 +2788,6 @@ bdrv_co_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
|
||||
ret = drv->bdrv_save_vmstate(bs, qiov, pos);
|
||||
} else if (child_bs) {
|
||||
ret = bdrv_co_writev_vmstate(child_bs, qiov, pos);
|
||||
} else {
|
||||
ret = -ENOTSUP;
|
||||
}
|
||||
|
||||
bdrv_dec_in_flight(bs);
|
||||
@ -3057,8 +2977,7 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
|
||||
int64_t bytes)
|
||||
{
|
||||
BdrvTrackedRequest req;
|
||||
int ret;
|
||||
int64_t max_pdiscard;
|
||||
int max_pdiscard, ret;
|
||||
int head, tail, align;
|
||||
BlockDriverState *bs = child->bs;
|
||||
|
||||
@ -3084,9 +3003,6 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Invalidate the cached block-status data range if this discard overlaps */
|
||||
bdrv_bsc_invalidate_range(bs, offset, bytes);
|
||||
|
||||
/* Discard is advisory, but some devices track and coalesce
|
||||
* unaligned requests, so we must pass everything down rather than
|
||||
* round here. Still, most devices will just silently ignore
|
||||
@ -3105,7 +3021,7 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
|
||||
goto out;
|
||||
}
|
||||
|
||||
max_pdiscard = QEMU_ALIGN_DOWN(MIN_NON_ZERO(bs->bl.max_pdiscard, INT64_MAX),
|
||||
max_pdiscard = QEMU_ALIGN_DOWN(MIN_NON_ZERO(bs->bl.max_pdiscard, INT_MAX),
|
||||
align);
|
||||
assert(max_pdiscard >= bs->bl.request_alignment);
|
||||
|
||||
|
@ -427,14 +427,14 @@ static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
|
||||
return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
|
||||
}
|
||||
|
||||
static bool is_byte_request_lun_aligned(int64_t offset, int64_t bytes,
|
||||
static bool is_byte_request_lun_aligned(int64_t offset, int count,
|
||||
IscsiLun *iscsilun)
|
||||
{
|
||||
if (offset % iscsilun->block_size || bytes % iscsilun->block_size) {
|
||||
if (offset % iscsilun->block_size || count % iscsilun->block_size) {
|
||||
error_report("iSCSI misaligned request: "
|
||||
"iscsilun->block_size %u, offset %" PRIi64
|
||||
", bytes %" PRIi64,
|
||||
iscsilun->block_size, offset, bytes);
|
||||
", count %d",
|
||||
iscsilun->block_size, offset, count);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -781,6 +781,9 @@ retry:
|
||||
iscsi_allocmap_set_allocated(iscsilun, offset, *pnum);
|
||||
}
|
||||
|
||||
if (*pnum > bytes) {
|
||||
*pnum = bytes;
|
||||
}
|
||||
out_unlock:
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
g_free(iTask.err_str);
|
||||
@ -1138,8 +1141,7 @@ iscsi_getlength(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static int
|
||||
coroutine_fn iscsi_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes)
|
||||
coroutine_fn iscsi_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct IscsiTask iTask;
|
||||
@ -1155,12 +1157,6 @@ coroutine_fn iscsi_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't want to overflow list.num which is uint32_t.
|
||||
* We rely on our max_pdiscard.
|
||||
*/
|
||||
assert(bytes / iscsilun->block_size <= UINT32_MAX);
|
||||
|
||||
list.lba = offset / iscsilun->block_size;
|
||||
list.num = bytes / iscsilun->block_size;
|
||||
|
||||
@ -1209,12 +1205,12 @@ out_unlock:
|
||||
|
||||
static int
|
||||
coroutine_fn iscsi_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, BdrvRequestFlags flags)
|
||||
int bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct IscsiTask iTask;
|
||||
uint64_t lba;
|
||||
uint64_t nb_blocks;
|
||||
uint32_t nb_blocks;
|
||||
bool use_16_for_ws = iscsilun->use_16_for_rw;
|
||||
int r = 0;
|
||||
|
||||
@ -1254,21 +1250,11 @@ coroutine_fn iscsi_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
retry:
|
||||
if (use_16_for_ws) {
|
||||
/*
|
||||
* iscsi_writesame16_task num_blocks argument is uint32_t. We rely here
|
||||
* on our max_pwrite_zeroes limit.
|
||||
*/
|
||||
assert(nb_blocks <= UINT32_MAX);
|
||||
iTask.task = iscsi_writesame16_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
iscsilun->zeroblock, iscsilun->block_size,
|
||||
nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP),
|
||||
0, 0, iscsi_co_generic_cb, &iTask);
|
||||
} else {
|
||||
/*
|
||||
* iscsi_writesame10_task num_blocks argument is uint16_t. We rely here
|
||||
* on our max_pwrite_zeroes limit.
|
||||
*/
|
||||
assert(nb_blocks <= UINT16_MAX);
|
||||
iTask.task = iscsi_writesame10_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
iscsilun->zeroblock, iscsilun->block_size,
|
||||
nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP),
|
||||
@ -2078,19 +2064,20 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
}
|
||||
|
||||
if (iscsilun->lbp.lbpu) {
|
||||
if (iscsilun->bl.max_unmap < 0xffffffff / block_size) {
|
||||
bs->bl.max_pdiscard =
|
||||
MIN_NON_ZERO(iscsilun->bl.max_unmap * iscsilun->block_size,
|
||||
(uint64_t)UINT32_MAX * iscsilun->block_size);
|
||||
iscsilun->bl.max_unmap * iscsilun->block_size;
|
||||
}
|
||||
bs->bl.pdiscard_alignment =
|
||||
iscsilun->bl.opt_unmap_gran * iscsilun->block_size;
|
||||
} else {
|
||||
bs->bl.pdiscard_alignment = iscsilun->block_size;
|
||||
}
|
||||
|
||||
if (iscsilun->bl.max_ws_len < 0xffffffff / block_size) {
|
||||
bs->bl.max_pwrite_zeroes =
|
||||
MIN_NON_ZERO(iscsilun->bl.max_ws_len * iscsilun->block_size,
|
||||
max_xfer_len * iscsilun->block_size);
|
||||
|
||||
iscsilun->bl.max_ws_len * iscsilun->block_size;
|
||||
}
|
||||
if (iscsilun->lbp.lbpws) {
|
||||
bs->bl.pwrite_zeroes_alignment =
|
||||
iscsilun->bl.opt_unmap_gran * iscsilun->block_size;
|
||||
@ -2185,10 +2172,10 @@ static void coroutine_fn iscsi_co_invalidate_cache(BlockDriverState *bs,
|
||||
|
||||
static int coroutine_fn iscsi_co_copy_range_from(BlockDriverState *bs,
|
||||
BdrvChild *src,
|
||||
int64_t src_offset,
|
||||
uint64_t src_offset,
|
||||
BdrvChild *dst,
|
||||
int64_t dst_offset,
|
||||
int64_t bytes,
|
||||
uint64_t dst_offset,
|
||||
uint64_t bytes,
|
||||
BdrvRequestFlags read_flags,
|
||||
BdrvRequestFlags write_flags)
|
||||
{
|
||||
@ -2326,10 +2313,10 @@ static void iscsi_xcopy_data(struct iscsi_data *data,
|
||||
|
||||
static int coroutine_fn iscsi_co_copy_range_to(BlockDriverState *bs,
|
||||
BdrvChild *src,
|
||||
int64_t src_offset,
|
||||
uint64_t src_offset,
|
||||
BdrvChild *dst,
|
||||
int64_t dst_offset,
|
||||
int64_t bytes,
|
||||
uint64_t dst_offset,
|
||||
uint64_t bytes,
|
||||
BdrvRequestFlags read_flags,
|
||||
BdrvRequestFlags write_flags)
|
||||
{
|
||||
|
@ -334,45 +334,30 @@ static void ioq_submit(LinuxAioState *s)
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t laio_max_batch(LinuxAioState *s, uint64_t dev_max_batch)
|
||||
{
|
||||
uint64_t max_batch = s->aio_context->aio_max_batch ?: DEFAULT_MAX_BATCH;
|
||||
|
||||
/*
|
||||
* AIO context can be shared between multiple block devices, so
|
||||
* `dev_max_batch` allows reducing the batch size for latency-sensitive
|
||||
* devices.
|
||||
*/
|
||||
max_batch = MIN_NON_ZERO(dev_max_batch, max_batch);
|
||||
|
||||
/* limit the batch with the number of available events */
|
||||
max_batch = MIN_NON_ZERO(MAX_EVENTS - s->io_q.in_flight, max_batch);
|
||||
|
||||
return max_batch;
|
||||
}
|
||||
|
||||
void laio_io_plug(BlockDriverState *bs, LinuxAioState *s)
|
||||
{
|
||||
s->io_q.plugged++;
|
||||
}
|
||||
|
||||
void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s,
|
||||
uint64_t dev_max_batch)
|
||||
void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s)
|
||||
{
|
||||
assert(s->io_q.plugged);
|
||||
if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch) ||
|
||||
(--s->io_q.plugged == 0 &&
|
||||
!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending))) {
|
||||
if (--s->io_q.plugged == 0 &&
|
||||
!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
|
||||
ioq_submit(s);
|
||||
}
|
||||
}
|
||||
|
||||
static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
|
||||
int type, uint64_t dev_max_batch)
|
||||
int type)
|
||||
{
|
||||
LinuxAioState *s = laiocb->ctx;
|
||||
struct iocb *iocbs = &laiocb->iocb;
|
||||
QEMUIOVector *qiov = laiocb->qiov;
|
||||
int64_t max_batch = s->aio_context->aio_max_batch ?: DEFAULT_MAX_BATCH;
|
||||
|
||||
/* limit the batch with the number of available events */
|
||||
max_batch = MIN_NON_ZERO(MAX_EVENTS - s->io_q.in_flight, max_batch);
|
||||
|
||||
switch (type) {
|
||||
case QEMU_AIO_WRITE:
|
||||
@ -393,7 +378,7 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
|
||||
s->io_q.in_queue++;
|
||||
if (!s->io_q.blocked &&
|
||||
(!s->io_q.plugged ||
|
||||
s->io_q.in_queue >= laio_max_batch(s, dev_max_batch))) {
|
||||
s->io_q.in_queue >= max_batch)) {
|
||||
ioq_submit(s);
|
||||
}
|
||||
|
||||
@ -401,8 +386,7 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
|
||||
}
|
||||
|
||||
int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
|
||||
uint64_t offset, QEMUIOVector *qiov, int type,
|
||||
uint64_t dev_max_batch)
|
||||
uint64_t offset, QEMUIOVector *qiov, int type)
|
||||
{
|
||||
int ret;
|
||||
struct qemu_laiocb laiocb = {
|
||||
@ -414,7 +398,7 @@ int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
|
||||
.qiov = qiov,
|
||||
};
|
||||
|
||||
ret = laio_do_submit(fd, &laiocb, offset, type, dev_max_batch);
|
||||
ret = laio_do_submit(fd, &laiocb, offset, type);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ block_ss.add(files(
|
||||
'aio_task.c',
|
||||
'amend.c',
|
||||
'backup.c',
|
||||
'copy-before-write.c',
|
||||
'backup-top.c',
|
||||
'blkdebug.c',
|
||||
'blklogwrites.c',
|
||||
'blkverify.c',
|
||||
@ -65,7 +65,7 @@ block_ss.add(when: 'CONFIG_POSIX', if_true: [files('file-posix.c'), coref, iokit
|
||||
block_ss.add(when: libiscsi, if_true: files('iscsi-opts.c'))
|
||||
block_ss.add(when: 'CONFIG_LINUX', if_true: files('nvme.c'))
|
||||
block_ss.add(when: 'CONFIG_REPLICATION', if_true: files('replication.c'))
|
||||
block_ss.add(when: libaio, if_true: files('linux-aio.c'))
|
||||
block_ss.add(when: ['CONFIG_LINUX_AIO', libaio], if_true: files('linux-aio.c'))
|
||||
block_ss.add(when: linux_io_uring, if_true: files('io_uring.c'))
|
||||
|
||||
block_modules = {}
|
||||
|
@ -56,6 +56,7 @@ typedef struct MirrorBlockJob {
|
||||
bool zero_target;
|
||||
MirrorCopyMode copy_mode;
|
||||
BlockdevOnError on_source_error, on_target_error;
|
||||
bool synced;
|
||||
/* Set when the target is synced (dirty bitmap is clean, nothing
|
||||
* in flight) and the job is running in active mode */
|
||||
bool actively_synced;
|
||||
@ -120,6 +121,7 @@ typedef enum MirrorMethod {
|
||||
static BlockErrorAction mirror_error_action(MirrorBlockJob *s, bool read,
|
||||
int error)
|
||||
{
|
||||
s->synced = false;
|
||||
s->actively_synced = false;
|
||||
if (read) {
|
||||
return block_job_error_action(&s->common, s->on_source_error,
|
||||
@ -158,25 +160,18 @@ static void coroutine_fn mirror_wait_on_conflicts(MirrorOp *self,
|
||||
if (ranges_overlap(self_start_chunk, self_nb_chunks,
|
||||
op_start_chunk, op_nb_chunks))
|
||||
{
|
||||
if (self) {
|
||||
/*
|
||||
* If the operation is already (indirectly) waiting for us,
|
||||
* or will wait for us as soon as it wakes up, then just go
|
||||
* on (instead of producing a deadlock in the former case).
|
||||
* If the operation is already (indirectly) waiting for us, or
|
||||
* will wait for us as soon as it wakes up, then just go on
|
||||
* (instead of producing a deadlock in the former case).
|
||||
*/
|
||||
if (op->waiting_for_op) {
|
||||
continue;
|
||||
}
|
||||
|
||||
self->waiting_for_op = op;
|
||||
}
|
||||
|
||||
qemu_co_queue_wait(&op->waiting_requests, NULL);
|
||||
|
||||
if (self) {
|
||||
self->waiting_for_op = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -942,10 +937,12 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
|
||||
if (s->bdev_length == 0) {
|
||||
/* Transition to the READY state and wait for complete. */
|
||||
job_transition_to_ready(&s->common.job);
|
||||
s->synced = true;
|
||||
s->actively_synced = true;
|
||||
while (!job_cancel_requested(&s->common.job) && !s->should_complete) {
|
||||
while (!job_is_cancelled(&s->common.job) && !s->should_complete) {
|
||||
job_yield(&s->common.job);
|
||||
}
|
||||
s->common.job.cancelled = false;
|
||||
goto immediate_exit;
|
||||
}
|
||||
|
||||
@ -1006,11 +1003,6 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
|
||||
|
||||
job_pause_point(&s->common.job);
|
||||
|
||||
if (job_is_cancelled(&s->common.job)) {
|
||||
ret = 0;
|
||||
goto immediate_exit;
|
||||
}
|
||||
|
||||
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
|
||||
/* cnt is the number of dirty bytes remaining and s->bytes_in_flight is
|
||||
* the number of bytes currently being processed; together those are
|
||||
@ -1037,7 +1029,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
|
||||
should_complete = false;
|
||||
if (s->in_flight == 0 && cnt == 0) {
|
||||
trace_mirror_before_flush(s);
|
||||
if (!job_is_ready(&s->common.job)) {
|
||||
if (!s->synced) {
|
||||
if (mirror_flush(s) < 0) {
|
||||
/* Go check s->ret. */
|
||||
continue;
|
||||
@ -1048,13 +1040,14 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
|
||||
* the target in a consistent state.
|
||||
*/
|
||||
job_transition_to_ready(&s->common.job);
|
||||
s->synced = true;
|
||||
if (s->copy_mode != MIRROR_COPY_MODE_BACKGROUND) {
|
||||
s->actively_synced = true;
|
||||
}
|
||||
}
|
||||
|
||||
should_complete = s->should_complete ||
|
||||
job_cancel_requested(&s->common.job);
|
||||
job_is_cancelled(&s->common.job);
|
||||
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
|
||||
}
|
||||
|
||||
@ -1084,17 +1077,24 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
|
||||
* completion.
|
||||
*/
|
||||
assert(QLIST_EMPTY(&bs->tracked_requests));
|
||||
s->common.job.cancelled = false;
|
||||
need_drain = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (job_is_ready(&s->common.job) && !should_complete) {
|
||||
ret = 0;
|
||||
|
||||
if (s->synced && !should_complete) {
|
||||
delay_ns = (s->in_flight == 0 &&
|
||||
cnt == 0 ? BLOCK_JOB_SLICE_TIME : 0);
|
||||
}
|
||||
trace_mirror_before_sleep(s, cnt, job_is_ready(&s->common.job),
|
||||
delay_ns);
|
||||
trace_mirror_before_sleep(s, cnt, s->synced, delay_ns);
|
||||
job_sleep_ns(&s->common.job, delay_ns);
|
||||
if (job_is_cancelled(&s->common.job) &&
|
||||
(!s->synced || s->common.job.force_cancel))
|
||||
{
|
||||
break;
|
||||
}
|
||||
s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||
}
|
||||
|
||||
@ -1104,7 +1104,8 @@ immediate_exit:
|
||||
* or it was cancelled prematurely so that we do not guarantee that
|
||||
* the target is a copy of the source.
|
||||
*/
|
||||
assert(ret < 0 || job_is_cancelled(&s->common.job));
|
||||
assert(ret < 0 || ((s->common.job.force_cancel || !s->synced) &&
|
||||
job_is_cancelled(&s->common.job)));
|
||||
assert(need_drain);
|
||||
mirror_wait_for_all_io(s);
|
||||
}
|
||||
@ -1127,7 +1128,7 @@ static void mirror_complete(Job *job, Error **errp)
|
||||
{
|
||||
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
|
||||
|
||||
if (!job_is_ready(job)) {
|
||||
if (!s->synced) {
|
||||
error_setg(errp, "The active block job '%s' cannot be completed",
|
||||
job->id);
|
||||
return;
|
||||
@ -1182,34 +1183,21 @@ static bool mirror_drained_poll(BlockJob *job)
|
||||
* from one of our own drain sections, to avoid a deadlock waiting for
|
||||
* ourselves.
|
||||
*/
|
||||
if (!s->common.job.paused && !job_is_cancelled(&job->job) && !s->in_drain) {
|
||||
if (!s->common.job.paused && !s->common.job.cancelled && !s->in_drain) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !!s->in_flight;
|
||||
}
|
||||
|
||||
static bool mirror_cancel(Job *job, bool force)
|
||||
static void mirror_cancel(Job *job, bool force)
|
||||
{
|
||||
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
|
||||
BlockDriverState *target = blk_bs(s->target);
|
||||
|
||||
/*
|
||||
* Before the job is READY, we treat any cancellation like a
|
||||
* force-cancellation.
|
||||
*/
|
||||
force = force || !job_is_ready(job);
|
||||
|
||||
if (force) {
|
||||
if (force || !job_is_ready(job)) {
|
||||
bdrv_cancel_in_flight(target);
|
||||
}
|
||||
return force;
|
||||
}
|
||||
|
||||
static bool commit_active_cancel(Job *job, bool force)
|
||||
{
|
||||
/* Same as above in mirror_cancel() */
|
||||
return force || !job_is_ready(job);
|
||||
}
|
||||
|
||||
static const BlockJobDriver mirror_job_driver = {
|
||||
@ -1239,7 +1227,6 @@ static const BlockJobDriver commit_active_job_driver = {
|
||||
.abort = mirror_abort,
|
||||
.pause = mirror_pause,
|
||||
.complete = mirror_complete,
|
||||
.cancel = commit_active_cancel,
|
||||
},
|
||||
.drained_poll = mirror_drained_poll,
|
||||
};
|
||||
@ -1408,7 +1395,7 @@ static void coroutine_fn active_write_settle(MirrorOp *op)
|
||||
}
|
||||
|
||||
static int coroutine_fn bdrv_mirror_top_preadv(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
|
||||
}
|
||||
@ -1423,7 +1410,6 @@ static int coroutine_fn bdrv_mirror_top_do_write(BlockDriverState *bs,
|
||||
bool copy_to_target;
|
||||
|
||||
copy_to_target = s->job->ret >= 0 &&
|
||||
!job_is_cancelled(&s->job->common.job) &&
|
||||
s->job->copy_mode == MIRROR_COPY_MODE_WRITE_BLOCKING;
|
||||
|
||||
if (copy_to_target) {
|
||||
@ -1463,7 +1449,7 @@ out:
|
||||
}
|
||||
|
||||
static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
MirrorBDSOpaque *s = bs->opaque;
|
||||
QEMUIOVector bounce_qiov;
|
||||
@ -1472,7 +1458,6 @@ static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,
|
||||
bool copy_to_target;
|
||||
|
||||
copy_to_target = s->job->ret >= 0 &&
|
||||
!job_is_cancelled(&s->job->common.job) &&
|
||||
s->job->copy_mode == MIRROR_COPY_MODE_WRITE_BLOCKING;
|
||||
|
||||
if (copy_to_target) {
|
||||
@ -1509,14 +1494,14 @@ static int coroutine_fn bdrv_mirror_top_flush(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static int coroutine_fn bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes, BdrvRequestFlags flags)
|
||||
int64_t offset, int bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_ZERO, offset, bytes, NULL,
|
||||
flags);
|
||||
}
|
||||
|
||||
static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes)
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_DISCARD, offset, bytes,
|
||||
NULL, 0);
|
||||
|
@ -251,10 +251,10 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
||||
|
||||
if (!filename) {
|
||||
error_setg(&err, QERR_MISSING_PARAMETER, "target");
|
||||
goto end;
|
||||
hmp_handle_error(mon, err);
|
||||
return;
|
||||
}
|
||||
qmp_drive_mirror(&mirror, &err);
|
||||
end:
|
||||
hmp_handle_error(mon, err);
|
||||
}
|
||||
|
||||
@ -281,11 +281,11 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
||||
|
||||
if (!filename) {
|
||||
error_setg(&err, QERR_MISSING_PARAMETER, "target");
|
||||
goto end;
|
||||
hmp_handle_error(mon, err);
|
||||
return;
|
||||
}
|
||||
|
||||
qmp_drive_backup(&backup, &err);
|
||||
end:
|
||||
hmp_handle_error(mon, err);
|
||||
}
|
||||
|
||||
@ -356,7 +356,8 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
|
||||
* will be taken internally. Today it's actually required.
|
||||
*/
|
||||
error_setg(&err, QERR_MISSING_PARAMETER, "snapshot-file");
|
||||
goto end;
|
||||
hmp_handle_error(mon, err);
|
||||
return;
|
||||
}
|
||||
|
||||
mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
||||
@ -364,7 +365,6 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
|
||||
filename, false, NULL,
|
||||
!!format, format,
|
||||
true, mode, &err);
|
||||
end:
|
||||
hmp_handle_error(mon, err);
|
||||
}
|
||||
|
||||
|
433
block/nbd.c
433
block/nbd.c
@ -57,8 +57,7 @@
|
||||
typedef struct {
|
||||
Coroutine *coroutine;
|
||||
uint64_t offset; /* original offset of the request */
|
||||
bool receiving; /* sleeping in the yield in nbd_receive_replies */
|
||||
bool reply_possible; /* reply header not yet received */
|
||||
bool receiving; /* waiting for connection_co? */
|
||||
} NBDClientRequest;
|
||||
|
||||
typedef enum NBDClientState {
|
||||
@ -74,10 +73,14 @@ typedef struct BDRVNBDState {
|
||||
|
||||
CoMutex send_mutex;
|
||||
CoQueue free_sema;
|
||||
|
||||
CoMutex receive_mutex;
|
||||
Coroutine *connection_co;
|
||||
Coroutine *teardown_co;
|
||||
QemuCoSleep reconnect_sleep;
|
||||
bool drained;
|
||||
bool wait_drained_end;
|
||||
int in_flight;
|
||||
NBDClientState state;
|
||||
bool wait_in_flight;
|
||||
|
||||
QEMUTimer *reconnect_delay_timer;
|
||||
|
||||
@ -124,44 +127,33 @@ static bool nbd_client_connected(BDRVNBDState *s)
|
||||
return qatomic_load_acquire(&s->state) == NBD_CLIENT_CONNECTED;
|
||||
}
|
||||
|
||||
static bool nbd_recv_coroutine_wake_one(NBDClientRequest *req)
|
||||
{
|
||||
if (req->receiving) {
|
||||
req->receiving = false;
|
||||
aio_co_wake(req->coroutine);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void nbd_recv_coroutines_wake(BDRVNBDState *s, bool all)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_NBD_REQUESTS; i++) {
|
||||
if (nbd_recv_coroutine_wake_one(&s->requests[i]) && !all) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void nbd_channel_error(BDRVNBDState *s, int ret)
|
||||
{
|
||||
if (nbd_client_connected(s)) {
|
||||
qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
|
||||
}
|
||||
|
||||
if (ret == -EIO) {
|
||||
if (nbd_client_connected(s)) {
|
||||
s->state = s->reconnect_delay ? NBD_CLIENT_CONNECTING_WAIT :
|
||||
NBD_CLIENT_CONNECTING_NOWAIT;
|
||||
}
|
||||
} else {
|
||||
if (nbd_client_connected(s)) {
|
||||
qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
|
||||
}
|
||||
s->state = NBD_CLIENT_QUIT;
|
||||
}
|
||||
}
|
||||
|
||||
nbd_recv_coroutines_wake(s, true);
|
||||
static void nbd_recv_coroutines_wake_all(BDRVNBDState *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_NBD_REQUESTS; i++) {
|
||||
NBDClientRequest *req = &s->requests[i];
|
||||
|
||||
if (req->coroutine && req->receiving) {
|
||||
req->receiving = false;
|
||||
aio_co_wake(req->coroutine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void reconnect_delay_timer_del(BDRVNBDState *s)
|
||||
@ -178,7 +170,6 @@ static void reconnect_delay_timer_cb(void *opaque)
|
||||
|
||||
if (qatomic_load_acquire(&s->state) == NBD_CLIENT_CONNECTING_WAIT) {
|
||||
s->state = NBD_CLIENT_CONNECTING_NOWAIT;
|
||||
nbd_co_establish_connection_cancel(s->conn);
|
||||
while (qemu_co_enter_next(&s->free_sema, NULL)) {
|
||||
/* Resume all queued requests */
|
||||
}
|
||||
@ -201,21 +192,113 @@ static void reconnect_delay_timer_init(BDRVNBDState *s, uint64_t expire_time_ns)
|
||||
timer_mod(s->reconnect_delay_timer, expire_time_ns);
|
||||
}
|
||||
|
||||
static void nbd_client_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
|
||||
|
||||
/* Timer is deleted in nbd_client_co_drain_begin() */
|
||||
assert(!s->reconnect_delay_timer);
|
||||
/*
|
||||
* If reconnect is in progress we may have no ->ioc. It will be
|
||||
* re-instantiated in the proper aio context once the connection is
|
||||
* reestablished.
|
||||
*/
|
||||
if (s->ioc) {
|
||||
qio_channel_detach_aio_context(QIO_CHANNEL(s->ioc));
|
||||
}
|
||||
}
|
||||
|
||||
static void nbd_client_attach_aio_context_bh(void *opaque)
|
||||
{
|
||||
BlockDriverState *bs = opaque;
|
||||
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
|
||||
|
||||
if (s->connection_co) {
|
||||
/*
|
||||
* The node is still drained, so we know the coroutine has yielded in
|
||||
* nbd_read_eof(), the only place where bs->in_flight can reach 0, or
|
||||
* it is entered for the first time. Both places are safe for entering
|
||||
* the coroutine.
|
||||
*/
|
||||
qemu_aio_coroutine_enter(bs->aio_context, s->connection_co);
|
||||
}
|
||||
bdrv_dec_in_flight(bs);
|
||||
}
|
||||
|
||||
static void nbd_client_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
|
||||
|
||||
/*
|
||||
* s->connection_co is either yielded from nbd_receive_reply or from
|
||||
* nbd_co_reconnect_loop()
|
||||
*/
|
||||
if (nbd_client_connected(s)) {
|
||||
qio_channel_attach_aio_context(QIO_CHANNEL(s->ioc), new_context);
|
||||
}
|
||||
|
||||
bdrv_inc_in_flight(bs);
|
||||
|
||||
/*
|
||||
* Need to wait here for the BH to run because the BH must run while the
|
||||
* node is still drained.
|
||||
*/
|
||||
aio_wait_bh_oneshot(new_context, nbd_client_attach_aio_context_bh, bs);
|
||||
}
|
||||
|
||||
static void coroutine_fn nbd_client_co_drain_begin(BlockDriverState *bs)
|
||||
{
|
||||
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
|
||||
|
||||
s->drained = true;
|
||||
qemu_co_sleep_wake(&s->reconnect_sleep);
|
||||
|
||||
nbd_co_establish_connection_cancel(s->conn);
|
||||
|
||||
reconnect_delay_timer_del(s);
|
||||
|
||||
if (qatomic_load_acquire(&s->state) == NBD_CLIENT_CONNECTING_WAIT) {
|
||||
s->state = NBD_CLIENT_CONNECTING_NOWAIT;
|
||||
qemu_co_queue_restart_all(&s->free_sema);
|
||||
}
|
||||
}
|
||||
|
||||
static void coroutine_fn nbd_client_co_drain_end(BlockDriverState *bs)
|
||||
{
|
||||
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
|
||||
|
||||
s->drained = false;
|
||||
if (s->wait_drained_end) {
|
||||
s->wait_drained_end = false;
|
||||
aio_co_wake(s->connection_co);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void nbd_teardown_connection(BlockDriverState *bs)
|
||||
{
|
||||
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
|
||||
|
||||
assert(!s->in_flight);
|
||||
|
||||
if (s->ioc) {
|
||||
/* finish any pending coroutines */
|
||||
qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
|
||||
yank_unregister_function(BLOCKDEV_YANK_INSTANCE(s->bs->node_name),
|
||||
nbd_yank, s->bs);
|
||||
object_unref(OBJECT(s->ioc));
|
||||
s->ioc = NULL;
|
||||
}
|
||||
|
||||
s->state = NBD_CLIENT_QUIT;
|
||||
if (s->connection_co) {
|
||||
qemu_co_sleep_wake(&s->reconnect_sleep);
|
||||
nbd_co_establish_connection_cancel(s->conn);
|
||||
}
|
||||
if (qemu_in_coroutine()) {
|
||||
s->teardown_co = qemu_coroutine_self();
|
||||
/* connection_co resumes us when it terminates */
|
||||
qemu_coroutine_yield();
|
||||
s->teardown_co = NULL;
|
||||
} else {
|
||||
BDRV_POLL_WHILE(bs, s->connection_co);
|
||||
}
|
||||
assert(!s->connection_co);
|
||||
}
|
||||
|
||||
static bool nbd_client_connecting(BDRVNBDState *s)
|
||||
@ -280,11 +363,10 @@ int coroutine_fn nbd_co_do_establish_connection(BlockDriverState *bs,
|
||||
{
|
||||
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
|
||||
int ret;
|
||||
bool blocking = nbd_client_connecting_wait(s);
|
||||
|
||||
assert(!s->ioc);
|
||||
|
||||
s->ioc = nbd_co_establish_connection(s->conn, &s->info, blocking, errp);
|
||||
s->ioc = nbd_co_establish_connection(s->conn, &s->info, true, errp);
|
||||
if (!s->ioc) {
|
||||
return -ECONNREFUSED;
|
||||
}
|
||||
@ -320,22 +402,29 @@ int coroutine_fn nbd_co_do_establish_connection(BlockDriverState *bs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called under s->send_mutex */
|
||||
static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s)
|
||||
{
|
||||
assert(nbd_client_connecting(s));
|
||||
assert(s->in_flight == 0);
|
||||
if (!nbd_client_connecting(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nbd_client_connecting_wait(s) && s->reconnect_delay &&
|
||||
!s->reconnect_delay_timer)
|
||||
{
|
||||
/*
|
||||
* It's first reconnect attempt after switching to
|
||||
* NBD_CLIENT_CONNECTING_WAIT
|
||||
*/
|
||||
reconnect_delay_timer_init(s,
|
||||
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) +
|
||||
s->reconnect_delay * NANOSECONDS_PER_SECOND);
|
||||
/* Wait for completion of all in-flight requests */
|
||||
|
||||
qemu_co_mutex_lock(&s->send_mutex);
|
||||
|
||||
while (s->in_flight > 0) {
|
||||
qemu_co_mutex_unlock(&s->send_mutex);
|
||||
nbd_recv_coroutines_wake_all(s);
|
||||
s->wait_in_flight = true;
|
||||
qemu_coroutine_yield();
|
||||
s->wait_in_flight = false;
|
||||
qemu_co_mutex_lock(&s->send_mutex);
|
||||
}
|
||||
|
||||
qemu_co_mutex_unlock(&s->send_mutex);
|
||||
|
||||
if (!nbd_client_connecting(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -355,73 +444,135 @@ static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s)
|
||||
nbd_co_do_establish_connection(s->bs, NULL);
|
||||
}
|
||||
|
||||
static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t handle)
|
||||
static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s)
|
||||
{
|
||||
int ret;
|
||||
uint64_t ind = HANDLE_TO_INDEX(s, handle), ind2;
|
||||
QEMU_LOCK_GUARD(&s->receive_mutex);
|
||||
uint64_t timeout = 1 * NANOSECONDS_PER_SECOND;
|
||||
uint64_t max_timeout = 16 * NANOSECONDS_PER_SECOND;
|
||||
|
||||
while (true) {
|
||||
if (s->reply.handle == handle) {
|
||||
/* We are done */
|
||||
return 0;
|
||||
if (qatomic_load_acquire(&s->state) == NBD_CLIENT_CONNECTING_WAIT) {
|
||||
reconnect_delay_timer_init(s, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) +
|
||||
s->reconnect_delay * NANOSECONDS_PER_SECOND);
|
||||
}
|
||||
|
||||
nbd_reconnect_attempt(s);
|
||||
|
||||
while (nbd_client_connecting(s)) {
|
||||
if (s->drained) {
|
||||
bdrv_dec_in_flight(s->bs);
|
||||
s->wait_drained_end = true;
|
||||
while (s->drained) {
|
||||
/*
|
||||
* We may be entered once from nbd_client_attach_aio_context_bh
|
||||
* and then from nbd_client_co_drain_end. So here is a loop.
|
||||
*/
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
bdrv_inc_in_flight(s->bs);
|
||||
} else {
|
||||
qemu_co_sleep_ns_wakeable(&s->reconnect_sleep,
|
||||
QEMU_CLOCK_REALTIME, timeout);
|
||||
if (s->drained) {
|
||||
continue;
|
||||
}
|
||||
if (timeout < max_timeout) {
|
||||
timeout *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
nbd_reconnect_attempt(s);
|
||||
}
|
||||
|
||||
reconnect_delay_timer_del(s);
|
||||
}
|
||||
|
||||
static coroutine_fn void nbd_connection_entry(void *opaque)
|
||||
{
|
||||
BDRVNBDState *s = opaque;
|
||||
uint64_t i;
|
||||
int ret = 0;
|
||||
Error *local_err = NULL;
|
||||
|
||||
while (qatomic_load_acquire(&s->state) != NBD_CLIENT_QUIT) {
|
||||
/*
|
||||
* The NBD client can only really be considered idle when it has
|
||||
* yielded from qio_channel_readv_all_eof(), waiting for data. This is
|
||||
* the point where the additional scheduled coroutine entry happens
|
||||
* after nbd_client_attach_aio_context().
|
||||
*
|
||||
* Therefore we keep an additional in_flight reference all the time and
|
||||
* only drop it temporarily here.
|
||||
*/
|
||||
|
||||
if (nbd_client_connecting(s)) {
|
||||
nbd_co_reconnect_loop(s);
|
||||
}
|
||||
|
||||
if (!nbd_client_connected(s)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (s->reply.handle != 0) {
|
||||
/*
|
||||
* Some other request is being handled now. It should already be
|
||||
* woken by whoever set s->reply.handle (or never wait in this
|
||||
* yield). So, we should not wake it here.
|
||||
*/
|
||||
ind2 = HANDLE_TO_INDEX(s, s->reply.handle);
|
||||
assert(!s->requests[ind2].receiving);
|
||||
|
||||
s->requests[ind].receiving = true;
|
||||
qemu_co_mutex_unlock(&s->receive_mutex);
|
||||
|
||||
qemu_coroutine_yield();
|
||||
/*
|
||||
* We may be woken for 3 reasons:
|
||||
* 1. From this function, executing in parallel coroutine, when our
|
||||
* handle is received.
|
||||
* 2. From nbd_channel_error(), when connection is lost.
|
||||
* 3. From nbd_co_receive_one_chunk(), when previous request is
|
||||
* finished and s->reply.handle set to 0.
|
||||
* Anyway, it's OK to lock the mutex and go to the next iteration.
|
||||
*/
|
||||
|
||||
qemu_co_mutex_lock(&s->receive_mutex);
|
||||
assert(!s->requests[ind].receiving);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We are under mutex and handle is 0. We have to do the dirty work. */
|
||||
assert(s->reply.handle == 0);
|
||||
ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, NULL);
|
||||
ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, &local_err);
|
||||
|
||||
if (local_err) {
|
||||
trace_nbd_read_reply_entry_fail(ret, error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
local_err = NULL;
|
||||
}
|
||||
if (ret <= 0) {
|
||||
ret = ret ? ret : -EIO;
|
||||
nbd_channel_error(s, ret);
|
||||
return ret;
|
||||
nbd_channel_error(s, ret ? ret : -EIO);
|
||||
continue;
|
||||
}
|
||||
if (nbd_reply_is_structured(&s->reply) && !s->info.structured_reply) {
|
||||
|
||||
/*
|
||||
* There's no need for a mutex on the receive side, because the
|
||||
* handler acts as a synchronization point and ensures that only
|
||||
* one coroutine is called until the reply finishes.
|
||||
*/
|
||||
i = HANDLE_TO_INDEX(s, s->reply.handle);
|
||||
if (i >= MAX_NBD_REQUESTS ||
|
||||
!s->requests[i].coroutine ||
|
||||
!s->requests[i].receiving ||
|
||||
(nbd_reply_is_structured(&s->reply) && !s->info.structured_reply))
|
||||
{
|
||||
nbd_channel_error(s, -EINVAL);
|
||||
return -EINVAL;
|
||||
continue;
|
||||
}
|
||||
if (s->reply.handle == handle) {
|
||||
/* We are done */
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* We're woken up again by the request itself. Note that there
|
||||
* is no race between yielding and reentering connection_co. This
|
||||
* is because:
|
||||
*
|
||||
* - if the request runs on the same AioContext, it is only
|
||||
* entered after we yield
|
||||
*
|
||||
* - if the request runs on a different AioContext, reentering
|
||||
* connection_co happens through a bottom half, which can only
|
||||
* run after we yield.
|
||||
*/
|
||||
s->requests[i].receiving = false;
|
||||
aio_co_wake(s->requests[i].coroutine);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
ind2 = HANDLE_TO_INDEX(s, s->reply.handle);
|
||||
if (ind2 >= MAX_NBD_REQUESTS || !s->requests[ind2].reply_possible) {
|
||||
nbd_channel_error(s, -EINVAL);
|
||||
return -EINVAL;
|
||||
|
||||
qemu_co_queue_restart_all(&s->free_sema);
|
||||
nbd_recv_coroutines_wake_all(s);
|
||||
bdrv_dec_in_flight(s->bs);
|
||||
|
||||
s->connection_co = NULL;
|
||||
if (s->ioc) {
|
||||
qio_channel_detach_aio_context(QIO_CHANNEL(s->ioc));
|
||||
yank_unregister_function(BLOCKDEV_YANK_INSTANCE(s->bs->node_name),
|
||||
nbd_yank, s->bs);
|
||||
object_unref(OBJECT(s->ioc));
|
||||
s->ioc = NULL;
|
||||
}
|
||||
nbd_recv_coroutine_wake_one(&s->requests[ind2]);
|
||||
|
||||
if (s->teardown_co) {
|
||||
aio_co_wake(s->teardown_co);
|
||||
}
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
static int nbd_co_send_request(BlockDriverState *bs,
|
||||
@ -432,17 +583,10 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
int rc, i = -1;
|
||||
|
||||
qemu_co_mutex_lock(&s->send_mutex);
|
||||
|
||||
while (s->in_flight == MAX_NBD_REQUESTS ||
|
||||
(!nbd_client_connected(s) && s->in_flight > 0))
|
||||
{
|
||||
while (s->in_flight == MAX_NBD_REQUESTS || nbd_client_connecting_wait(s)) {
|
||||
qemu_co_queue_wait(&s->free_sema, &s->send_mutex);
|
||||
}
|
||||
|
||||
if (nbd_client_connecting(s)) {
|
||||
nbd_reconnect_attempt(s);
|
||||
}
|
||||
|
||||
if (!nbd_client_connected(s)) {
|
||||
rc = -EIO;
|
||||
goto err;
|
||||
@ -462,7 +606,6 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
s->requests[i].coroutine = qemu_coroutine_self();
|
||||
s->requests[i].offset = request->from;
|
||||
s->requests[i].receiving = false;
|
||||
s->requests[i].reply_possible = true;
|
||||
|
||||
request->handle = INDEX_TO_HANDLE(s, i);
|
||||
|
||||
@ -490,6 +633,10 @@ err:
|
||||
if (i != -1) {
|
||||
s->requests[i].coroutine = NULL;
|
||||
s->in_flight--;
|
||||
}
|
||||
if (s->in_flight == 0 && s->wait_in_flight) {
|
||||
aio_co_wake(s->connection_co);
|
||||
} else {
|
||||
qemu_co_queue_next(&s->free_sema);
|
||||
}
|
||||
}
|
||||
@ -788,7 +935,10 @@ static coroutine_fn int nbd_co_do_receive_one_chunk(
|
||||
}
|
||||
*request_ret = 0;
|
||||
|
||||
nbd_receive_replies(s, handle);
|
||||
/* Wait until we're woken up by nbd_connection_entry. */
|
||||
s->requests[i].receiving = true;
|
||||
qemu_coroutine_yield();
|
||||
assert(!s->requests[i].receiving);
|
||||
if (!nbd_client_connected(s)) {
|
||||
error_setg(errp, "Connection closed");
|
||||
return -EIO;
|
||||
@ -881,7 +1031,14 @@ static coroutine_fn int nbd_co_receive_one_chunk(
|
||||
}
|
||||
s->reply.handle = 0;
|
||||
|
||||
nbd_recv_coroutines_wake(s, false);
|
||||
if (s->connection_co && !s->wait_in_flight) {
|
||||
/*
|
||||
* We must check s->wait_in_flight, because we may entered by
|
||||
* nbd_recv_coroutines_wake_all(), in this case we should not
|
||||
* wake connection_co here, it will woken by last request.
|
||||
*/
|
||||
aio_co_wake(s->connection_co);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -992,7 +1149,11 @@ break_loop:
|
||||
|
||||
qemu_co_mutex_lock(&s->send_mutex);
|
||||
s->in_flight--;
|
||||
if (s->in_flight == 0 && s->wait_in_flight) {
|
||||
aio_co_wake(s->connection_co);
|
||||
} else {
|
||||
qemu_co_queue_next(&s->free_sema);
|
||||
}
|
||||
qemu_co_mutex_unlock(&s->send_mutex);
|
||||
|
||||
return false;
|
||||
@ -1161,9 +1322,8 @@ static int nbd_co_request(BlockDriverState *bs, NBDRequest *request,
|
||||
return ret ? ret : request_ret;
|
||||
}
|
||||
|
||||
static int nbd_client_co_preadv(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
static int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
int ret, request_ret;
|
||||
Error *local_err = NULL;
|
||||
@ -1220,9 +1380,8 @@ static int nbd_client_co_preadv(BlockDriverState *bs, int64_t offset,
|
||||
return ret ? ret : request_ret;
|
||||
}
|
||||
|
||||
static int nbd_client_co_pwritev(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
static int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
|
||||
NBDRequest request = {
|
||||
@ -1246,17 +1405,15 @@ static int nbd_client_co_pwritev(BlockDriverState *bs, int64_t offset,
|
||||
}
|
||||
|
||||
static int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, BdrvRequestFlags flags)
|
||||
int bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
|
||||
NBDRequest request = {
|
||||
.type = NBD_CMD_WRITE_ZEROES,
|
||||
.from = offset,
|
||||
.len = bytes, /* .len is uint32_t actually */
|
||||
.len = bytes,
|
||||
};
|
||||
|
||||
assert(bytes <= UINT32_MAX); /* rely on max_pwrite_zeroes */
|
||||
|
||||
assert(!(s->info.flags & NBD_FLAG_READ_ONLY));
|
||||
if (!(s->info.flags & NBD_FLAG_SEND_WRITE_ZEROES)) {
|
||||
return -ENOTSUP;
|
||||
@ -1296,17 +1453,15 @@ static int nbd_client_co_flush(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes)
|
||||
int bytes)
|
||||
{
|
||||
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
|
||||
NBDRequest request = {
|
||||
.type = NBD_CMD_TRIM,
|
||||
.from = offset,
|
||||
.len = bytes, /* len is uint32_t */
|
||||
.len = bytes,
|
||||
};
|
||||
|
||||
assert(bytes <= UINT32_MAX); /* rely on max_pdiscard */
|
||||
|
||||
assert(!(s->info.flags & NBD_FLAG_READ_ONLY));
|
||||
if (!(s->info.flags & NBD_FLAG_SEND_TRIM) || !bytes) {
|
||||
return 0;
|
||||
@ -1814,7 +1969,6 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->bs = bs;
|
||||
qemu_co_mutex_init(&s->send_mutex);
|
||||
qemu_co_queue_init(&s->free_sema);
|
||||
qemu_co_mutex_init(&s->receive_mutex);
|
||||
|
||||
if (!yank_register_instance(BLOCKDEV_YANK_INSTANCE(bs->node_name), errp)) {
|
||||
return -EEXIST;
|
||||
@ -1829,13 +1983,14 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->x_dirty_bitmap, s->tlscreds);
|
||||
|
||||
/* TODO: Configurable retry-until-timeout behaviour. */
|
||||
s->state = NBD_CLIENT_CONNECTING_WAIT;
|
||||
ret = nbd_do_establish_connection(bs, errp);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nbd_client_connection_enable_retry(s->conn);
|
||||
s->connection_co = qemu_coroutine_create(nbd_connection_entry, s);
|
||||
bdrv_inc_in_flight(bs);
|
||||
aio_co_schedule(bdrv_get_aio_context(bs), s->connection_co);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1989,8 +2144,6 @@ static void nbd_cancel_in_flight(BlockDriverState *bs)
|
||||
s->state = NBD_CLIENT_CONNECTING_NOWAIT;
|
||||
qemu_co_queue_restart_all(&s->free_sema);
|
||||
}
|
||||
|
||||
nbd_co_establish_connection_cancel(s->conn);
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_nbd = {
|
||||
@ -2011,6 +2164,10 @@ static BlockDriver bdrv_nbd = {
|
||||
.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,
|
||||
.bdrv_co_drain_begin = nbd_client_co_drain_begin,
|
||||
.bdrv_co_drain_end = nbd_client_co_drain_end,
|
||||
.bdrv_refresh_filename = nbd_refresh_filename,
|
||||
.bdrv_co_block_status = nbd_client_co_block_status,
|
||||
.bdrv_dirname = nbd_dirname,
|
||||
@ -2036,6 +2193,10 @@ static BlockDriver bdrv_nbd_tcp = {
|
||||
.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,
|
||||
.bdrv_co_drain_begin = nbd_client_co_drain_begin,
|
||||
.bdrv_co_drain_end = nbd_client_co_drain_end,
|
||||
.bdrv_refresh_filename = nbd_refresh_filename,
|
||||
.bdrv_co_block_status = nbd_client_co_block_status,
|
||||
.bdrv_dirname = nbd_dirname,
|
||||
@ -2061,6 +2222,10 @@ static BlockDriver bdrv_nbd_unix = {
|
||||
.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,
|
||||
.bdrv_co_drain_begin = nbd_client_co_drain_begin,
|
||||
.bdrv_co_drain_end = nbd_client_co_drain_end,
|
||||
.bdrv_refresh_filename = nbd_refresh_filename,
|
||||
.bdrv_co_block_status = nbd_client_co_block_status,
|
||||
.bdrv_dirname = nbd_dirname,
|
||||
|
12
block/nfs.c
12
block/nfs.c
@ -262,9 +262,9 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
|
||||
nfs_co_generic_bh_cb, task);
|
||||
}
|
||||
|
||||
static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *iov,
|
||||
BdrvRequestFlags flags)
|
||||
static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *iov,
|
||||
int flags)
|
||||
{
|
||||
NFSClient *client = bs->opaque;
|
||||
NFSRPC task;
|
||||
@ -296,9 +296,9 @@ static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, int64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coroutine_fn nfs_co_pwritev(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *iov,
|
||||
BdrvRequestFlags flags)
|
||||
static int coroutine_fn nfs_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *iov,
|
||||
int flags)
|
||||
{
|
||||
NFSClient *client = bs->opaque;
|
||||
NFSRPC task;
|
||||
|
18
block/null.c
18
block/null.c
@ -116,9 +116,8 @@ static coroutine_fn int null_co_common(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static coroutine_fn int null_co_preadv(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVNullState *s = bs->opaque;
|
||||
|
||||
@ -130,9 +129,8 @@ static coroutine_fn int null_co_preadv(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static coroutine_fn int null_co_pwritev(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
return null_co_common(bs);
|
||||
}
|
||||
@ -189,8 +187,8 @@ static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static BlockAIOCB *null_aio_preadv(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
@ -204,8 +202,8 @@ static BlockAIOCB *null_aio_preadv(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static BlockAIOCB *null_aio_pwritev(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
|
99
block/nvme.c
99
block/nvme.c
@ -176,27 +176,23 @@ static bool nvme_init_queue(BDRVNVMeState *s, NVMeQueue *q,
|
||||
return false;
|
||||
}
|
||||
memset(q->queue, 0, bytes);
|
||||
r = qemu_vfio_dma_map(s->vfio, q->queue, bytes, false, &q->iova, errp);
|
||||
r = qemu_vfio_dma_map(s->vfio, q->queue, bytes, false, &q->iova);
|
||||
if (r) {
|
||||
error_prepend(errp, "Cannot map queue: ");
|
||||
error_setg(errp, "Cannot map queue");
|
||||
return false;
|
||||
}
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
static void nvme_free_queue(NVMeQueue *q)
|
||||
{
|
||||
qemu_vfree(q->queue);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void nvme_free_queue_pair(NVMeQueuePair *q)
|
||||
{
|
||||
trace_nvme_free_queue_pair(q->index, q, &q->cq, &q->sq);
|
||||
trace_nvme_free_queue_pair(q->index, q);
|
||||
if (q->completion_bh) {
|
||||
qemu_bh_delete(q->completion_bh);
|
||||
}
|
||||
nvme_free_queue(&q->sq);
|
||||
nvme_free_queue(&q->cq);
|
||||
qemu_vfree(q->prp_list_pages);
|
||||
qemu_vfree(q->sq.queue);
|
||||
qemu_vfree(q->cq.queue);
|
||||
qemu_mutex_destroy(&q->lock);
|
||||
g_free(q);
|
||||
}
|
||||
@ -224,7 +220,6 @@ static NVMeQueuePair *nvme_create_queue_pair(BDRVNVMeState *s,
|
||||
|
||||
q = g_try_new0(NVMeQueuePair, 1);
|
||||
if (!q) {
|
||||
error_setg(errp, "Cannot allocate queue pair");
|
||||
return NULL;
|
||||
}
|
||||
trace_nvme_create_queue_pair(idx, q, size, aio_context,
|
||||
@ -233,7 +228,6 @@ static NVMeQueuePair *nvme_create_queue_pair(BDRVNVMeState *s,
|
||||
qemu_real_host_page_size);
|
||||
q->prp_list_pages = qemu_try_memalign(qemu_real_host_page_size, bytes);
|
||||
if (!q->prp_list_pages) {
|
||||
error_setg(errp, "Cannot allocate PRP page list");
|
||||
goto fail;
|
||||
}
|
||||
memset(q->prp_list_pages, 0, bytes);
|
||||
@ -243,9 +237,8 @@ static NVMeQueuePair *nvme_create_queue_pair(BDRVNVMeState *s,
|
||||
qemu_co_queue_init(&q->free_req_queue);
|
||||
q->completion_bh = aio_bh_new(aio_context, nvme_process_completion_bh, q);
|
||||
r = qemu_vfio_dma_map(s->vfio, q->prp_list_pages, bytes,
|
||||
false, &prp_list_iova, errp);
|
||||
false, &prp_list_iova);
|
||||
if (r) {
|
||||
error_prepend(errp, "Cannot map buffer for DMA: ");
|
||||
goto fail;
|
||||
}
|
||||
q->free_req_head = -1;
|
||||
@ -519,10 +512,10 @@ static bool nvme_identify(BlockDriverState *bs, int namespace, Error **errp)
|
||||
{
|
||||
BDRVNVMeState *s = bs->opaque;
|
||||
bool ret = false;
|
||||
QEMU_AUTO_VFREE union {
|
||||
union {
|
||||
NvmeIdCtrl ctrl;
|
||||
NvmeIdNs ns;
|
||||
} *id = NULL;
|
||||
} *id;
|
||||
NvmeLBAF *lbaf;
|
||||
uint16_t oncs;
|
||||
int r;
|
||||
@ -538,9 +531,9 @@ static bool nvme_identify(BlockDriverState *bs, int namespace, Error **errp)
|
||||
error_setg(errp, "Cannot allocate buffer for identify response");
|
||||
goto out;
|
||||
}
|
||||
r = qemu_vfio_dma_map(s->vfio, id, id_size, true, &iova, errp);
|
||||
r = qemu_vfio_dma_map(s->vfio, id, id_size, true, &iova);
|
||||
if (r) {
|
||||
error_prepend(errp, "Cannot map buffer for DMA: ");
|
||||
error_setg(errp, "Cannot map buffer for DMA");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -600,6 +593,7 @@ static bool nvme_identify(BlockDriverState *bs, int namespace, Error **errp)
|
||||
s->blkshift = lbaf->ds;
|
||||
out:
|
||||
qemu_vfio_dma_unmap(s->vfio, id);
|
||||
qemu_vfree(id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1023,7 +1017,6 @@ static coroutine_fn int nvme_cmd_map_qiov(BlockDriverState *bs, NvmeCmd *cmd,
|
||||
uint64_t *pagelist = req->prp_list_page;
|
||||
int i, j, r;
|
||||
int entries = 0;
|
||||
Error *local_err = NULL, **errp = NULL;
|
||||
|
||||
assert(qiov->size);
|
||||
assert(QEMU_IS_ALIGNED(qiov->size, s->page_size));
|
||||
@ -1036,7 +1029,7 @@ static coroutine_fn int nvme_cmd_map_qiov(BlockDriverState *bs, NvmeCmd *cmd,
|
||||
try_map:
|
||||
r = qemu_vfio_dma_map(s->vfio,
|
||||
qiov->iov[i].iov_base,
|
||||
len, true, &iova, errp);
|
||||
len, true, &iova);
|
||||
if (r == -ENOSPC) {
|
||||
/*
|
||||
* In addition to the -ENOMEM error, the VFIO_IOMMU_MAP_DMA
|
||||
@ -1071,8 +1064,6 @@ try_map:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
errp = &local_err;
|
||||
|
||||
goto try_map;
|
||||
}
|
||||
if (r) {
|
||||
@ -1116,9 +1107,6 @@ fail:
|
||||
* because they are already mapped before calling this function; for
|
||||
* temporary mappings, a later nvme_cmd_(un)map_qiov will reclaim by
|
||||
* calling qemu_vfio_dma_reset_temporary when necessary. */
|
||||
if (local_err) {
|
||||
error_reportf_err(local_err, "Cannot map buffer for DMA: ");
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -1223,7 +1211,7 @@ static int nvme_co_prw(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
{
|
||||
BDRVNVMeState *s = bs->opaque;
|
||||
int r;
|
||||
QEMU_AUTO_VFREE uint8_t *buf = NULL;
|
||||
uint8_t *buf = NULL;
|
||||
QEMUIOVector local_qiov;
|
||||
size_t len = QEMU_ALIGN_UP(bytes, qemu_real_host_page_size);
|
||||
assert(QEMU_IS_ALIGNED(offset, s->page_size));
|
||||
@ -1250,21 +1238,20 @@ static int nvme_co_prw(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
if (!r && !is_write) {
|
||||
qemu_iovec_from_buf(qiov, 0, buf, bytes);
|
||||
}
|
||||
qemu_vfree(buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
static coroutine_fn int nvme_co_preadv(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
return nvme_co_prw(bs, offset, bytes, qiov, false, flags);
|
||||
}
|
||||
|
||||
static coroutine_fn int nvme_co_pwritev(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
return nvme_co_prw(bs, offset, bytes, qiov, true, flags);
|
||||
}
|
||||
@ -1299,29 +1286,19 @@ static coroutine_fn int nvme_co_flush(BlockDriverState *bs)
|
||||
|
||||
static coroutine_fn int nvme_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset,
|
||||
int64_t bytes,
|
||||
int bytes,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
BDRVNVMeState *s = bs->opaque;
|
||||
NVMeQueuePair *ioq = s->queues[INDEX_IO(0)];
|
||||
NVMeRequest *req;
|
||||
uint32_t cdw12;
|
||||
|
||||
uint32_t cdw12 = ((bytes >> s->blkshift) - 1) & 0xFFFF;
|
||||
|
||||
if (!s->supports_write_zeroes) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (bytes == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cdw12 = ((bytes >> s->blkshift) - 1) & 0xFFFF;
|
||||
/*
|
||||
* We should not lose information. pwrite_zeroes_alignment and
|
||||
* max_pwrite_zeroes guarantees it.
|
||||
*/
|
||||
assert(((cdw12 + 1) << s->blkshift) == bytes);
|
||||
|
||||
NvmeCmd cmd = {
|
||||
.opcode = NVME_CMD_WRITE_ZEROES,
|
||||
.nsid = cpu_to_le32(s->nsid),
|
||||
@ -1363,12 +1340,12 @@ static coroutine_fn int nvme_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
|
||||
static int coroutine_fn nvme_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset,
|
||||
int64_t bytes)
|
||||
int bytes)
|
||||
{
|
||||
BDRVNVMeState *s = bs->opaque;
|
||||
NVMeQueuePair *ioq = s->queues[INDEX_IO(0)];
|
||||
NVMeRequest *req;
|
||||
QEMU_AUTO_VFREE NvmeDsmRange *buf = NULL;
|
||||
NvmeDsmRange *buf;
|
||||
QEMUIOVector local_qiov;
|
||||
int ret;
|
||||
|
||||
@ -1390,14 +1367,6 @@ static int coroutine_fn nvme_co_pdiscard(BlockDriverState *bs,
|
||||
|
||||
assert(s->queue_count > 1);
|
||||
|
||||
/*
|
||||
* Filling the @buf requires @offset and @bytes to satisfy restrictions
|
||||
* defined in nvme_refresh_limits().
|
||||
*/
|
||||
assert(QEMU_IS_ALIGNED(bytes, 1UL << s->blkshift));
|
||||
assert(QEMU_IS_ALIGNED(offset, 1UL << s->blkshift));
|
||||
assert((bytes >> s->blkshift) <= UINT32_MAX);
|
||||
|
||||
buf = qemu_try_memalign(s->page_size, s->page_size);
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
@ -1443,6 +1412,7 @@ static int coroutine_fn nvme_co_pdiscard(BlockDriverState *bs,
|
||||
trace_nvme_dsm_done(s, offset, bytes, ret);
|
||||
out:
|
||||
qemu_iovec_destroy(&local_qiov);
|
||||
qemu_vfree(buf);
|
||||
return ret;
|
||||
|
||||
}
|
||||
@ -1492,18 +1462,6 @@ static void nvme_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
bs->bl.opt_mem_alignment = s->page_size;
|
||||
bs->bl.request_alignment = s->page_size;
|
||||
bs->bl.max_transfer = s->max_transfer;
|
||||
|
||||
/*
|
||||
* Look at nvme_co_pwrite_zeroes: after shift and decrement we should get
|
||||
* at most 0xFFFF
|
||||
*/
|
||||
bs->bl.max_pwrite_zeroes = 1ULL << (s->blkshift + 16);
|
||||
bs->bl.pwrite_zeroes_alignment = MAX(bs->bl.request_alignment,
|
||||
1UL << s->blkshift);
|
||||
|
||||
bs->bl.max_pdiscard = (uint64_t)UINT32_MAX << s->blkshift;
|
||||
bs->bl.pdiscard_alignment = MAX(bs->bl.request_alignment,
|
||||
1UL << s->blkshift);
|
||||
}
|
||||
|
||||
static void nvme_detach_aio_context(BlockDriverState *bs)
|
||||
@ -1563,15 +1521,14 @@ static void nvme_aio_unplug(BlockDriverState *bs)
|
||||
static void nvme_register_buf(BlockDriverState *bs, void *host, size_t size)
|
||||
{
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
BDRVNVMeState *s = bs->opaque;
|
||||
|
||||
ret = qemu_vfio_dma_map(s->vfio, host, size, false, NULL, &local_err);
|
||||
ret = qemu_vfio_dma_map(s->vfio, host, size, false, NULL);
|
||||
if (ret) {
|
||||
/* FIXME: we may run out of IOVA addresses after repeated
|
||||
* bdrv_register_buf/bdrv_unregister_buf, because nvme_vfio_dma_unmap
|
||||
* doesn't reclaim addresses for fixed mappings. */
|
||||
error_reportf_err(local_err, "nvme_register_buf failed: ");
|
||||
error_report("nvme_register_buf failed: %s", strerror(-ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,15 +227,15 @@ static void preallocate_reopen_abort(BDRVReopenState *state)
|
||||
}
|
||||
|
||||
static coroutine_fn int preallocate_co_preadv_part(
|
||||
BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags)
|
||||
BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset, int flags)
|
||||
{
|
||||
return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset,
|
||||
flags);
|
||||
}
|
||||
|
||||
static int coroutine_fn preallocate_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes)
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
return bdrv_co_pdiscard(bs->file, offset, bytes);
|
||||
}
|
||||
@ -337,7 +337,7 @@ static bool coroutine_fn handle_write(BlockDriverState *bs, int64_t offset,
|
||||
}
|
||||
|
||||
static int coroutine_fn preallocate_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes, BdrvRequestFlags flags)
|
||||
int64_t offset, int bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
bool want_merge_zero =
|
||||
!(flags & ~(BDRV_REQ_ZERO_WRITE | BDRV_REQ_NO_FALLBACK));
|
||||
@ -349,11 +349,11 @@ static int coroutine_fn preallocate_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static coroutine_fn int preallocate_co_pwritev_part(BlockDriverState *bs,
|
||||
int64_t offset,
|
||||
int64_t bytes,
|
||||
uint64_t offset,
|
||||
uint64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
int flags)
|
||||
{
|
||||
handle_write(bs, offset, bytes, false);
|
||||
|
||||
|
16
block/qcow.c
16
block/qcow.c
@ -617,9 +617,9 @@ static void qcow_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
bs->bl.request_alignment = BDRV_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov,
|
||||
int flags)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int offset_in_cluster;
|
||||
@ -714,9 +714,9 @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov,
|
||||
int flags)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int offset_in_cluster;
|
||||
@ -1047,8 +1047,8 @@ static int qcow_make_empty(BlockDriverState *bs)
|
||||
/* XXX: put compressed sectors first, then all the cluster aligned
|
||||
tables to avoid losing bytes in alignment */
|
||||
static coroutine_fn int
|
||||
qcow_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov)
|
||||
qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
z_stream strm;
|
||||
|
@ -505,20 +505,7 @@ static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
/*
|
||||
* We never deal with requests that don't satisfy
|
||||
* bdrv_check_qiov_request(), and aligning requests to clusters never
|
||||
* breaks this condition. So, do some assertions before calling
|
||||
* bs->drv->bdrv_co_preadv_part() which has int64_t arguments.
|
||||
*/
|
||||
assert(src_cluster_offset <= INT64_MAX);
|
||||
assert(src_cluster_offset + offset_in_cluster <= INT64_MAX);
|
||||
/* Cast qiov->size to uint64_t to silence a compiler warning on -m32 */
|
||||
assert((uint64_t)qiov->size <= INT64_MAX);
|
||||
bdrv_check_qiov_request(src_cluster_offset + offset_in_cluster, qiov->size,
|
||||
qiov, 0, &error_abort);
|
||||
/*
|
||||
* Call .bdrv_co_readv() directly instead of using the public block-layer
|
||||
/* Call .bdrv_co_readv() directly instead of using the public block-layer
|
||||
* interface. This avoids double I/O throttling and request tracking,
|
||||
* which can lead to deadlock when block layer copy-on-read is enabled.
|
||||
*/
|
||||
@ -569,7 +556,8 @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
|
||||
* offset needs to be aligned to a cluster boundary.
|
||||
*
|
||||
* If the cluster is unallocated then *host_offset will be 0.
|
||||
* If the cluster is compressed then *host_offset will contain the l2 entry.
|
||||
* If the cluster is compressed then *host_offset will contain the
|
||||
* complete compressed cluster descriptor.
|
||||
*
|
||||
* On entry, *bytes is the maximum number of contiguous bytes starting at
|
||||
* offset that we are interested in.
|
||||
@ -672,7 +660,7 @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
*host_offset = l2_entry;
|
||||
*host_offset = l2_entry & L2E_COMPRESSED_OFFSET_SIZE_MASK;
|
||||
break;
|
||||
case QCOW2_SUBCLUSTER_ZERO_PLAIN:
|
||||
case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
|
||||
@ -1412,22 +1400,7 @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
|
||||
|
||||
if (end <= old_start || start >= old_end) {
|
||||
/* No intersection */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (old_alloc->keep_old_clusters &&
|
||||
(end <= l2meta_cow_start(old_alloc) ||
|
||||
start >= l2meta_cow_end(old_alloc)))
|
||||
{
|
||||
/*
|
||||
* Clusters intersect but COW areas don't. And cluster itself is
|
||||
* already allocated. So, there is no actual conflict.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Conflict */
|
||||
|
||||
} else {
|
||||
if (start < old_start) {
|
||||
/* Stop at the start of a running allocation */
|
||||
bytes = old_start - start;
|
||||
@ -1435,26 +1408,23 @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
|
||||
bytes = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop if an l2meta already exists. After yielding, it wouldn't
|
||||
/* Stop if already an l2meta exists. After yielding, it wouldn't
|
||||
* be valid any more, so we'd have to clean up the old L2Metas
|
||||
* and deal with requests depending on them before starting to
|
||||
* gather new ones. Not worth the trouble.
|
||||
*/
|
||||
* gather new ones. Not worth the trouble. */
|
||||
if (bytes == 0 && *m) {
|
||||
*cur_bytes = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bytes == 0) {
|
||||
/*
|
||||
* Wait for the dependency to complete. We need to recheck
|
||||
* the free/allocated clusters when we continue.
|
||||
*/
|
||||
/* Wait for the dependency to complete. We need to recheck
|
||||
* the free/allocated clusters when we continue. */
|
||||
qemu_co_queue_wait(&old_alloc->dependent_requests, &s->lock);
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure that existing clusters and new allocations are only used up to
|
||||
* the next dependency if we shortened the request above */
|
||||
@ -2493,18 +2463,3 @@ fail:
|
||||
g_free(l1_table);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
|
||||
uint64_t *coffset, int *csize)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int nb_csectors;
|
||||
|
||||
assert(qcow2_get_cluster_type(bs, l2_entry) == QCOW2_CLUSTER_COMPRESSED);
|
||||
|
||||
*coffset = l2_entry & s->cluster_offset_mask;
|
||||
|
||||
nb_csectors = ((l2_entry >> s->csize_shift) & s->csize_mask) + 1;
|
||||
*csize = nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE -
|
||||
(*coffset & (QCOW2_COMPRESSED_SECTOR_SIZE - 1));
|
||||
}
|
||||
|
@ -1177,11 +1177,11 @@ void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry,
|
||||
switch (ctype) {
|
||||
case QCOW2_CLUSTER_COMPRESSED:
|
||||
{
|
||||
uint64_t coffset;
|
||||
int csize;
|
||||
|
||||
qcow2_parse_compressed_l2_entry(bs, l2_entry, &coffset, &csize);
|
||||
qcow2_free_clusters(bs, coffset, csize, type);
|
||||
int64_t offset = (l2_entry & s->cluster_offset_mask)
|
||||
& QCOW2_COMPRESSED_SECTOR_MASK;
|
||||
int size = QCOW2_COMPRESSED_SECTOR_SIZE *
|
||||
(((l2_entry >> s->csize_shift) & s->csize_mask) + 1);
|
||||
qcow2_free_clusters(bs, offset, size, type);
|
||||
}
|
||||
break;
|
||||
case QCOW2_CLUSTER_NORMAL:
|
||||
@ -1247,7 +1247,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
bool l1_allocated = false;
|
||||
int64_t old_entry, old_l2_offset;
|
||||
unsigned slice, slice_size2, n_slices;
|
||||
int i, j, l1_modified = 0;
|
||||
int i, j, l1_modified = 0, nb_csectors;
|
||||
int ret;
|
||||
|
||||
assert(addend >= -1 && addend <= 1);
|
||||
@ -1318,14 +1318,14 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
|
||||
switch (qcow2_get_cluster_type(bs, entry)) {
|
||||
case QCOW2_CLUSTER_COMPRESSED:
|
||||
nb_csectors = ((entry >> s->csize_shift) &
|
||||
s->csize_mask) + 1;
|
||||
if (addend != 0) {
|
||||
uint64_t coffset;
|
||||
int csize;
|
||||
|
||||
qcow2_parse_compressed_l2_entry(bs, entry,
|
||||
&coffset, &csize);
|
||||
uint64_t coffset = (entry & s->cluster_offset_mask)
|
||||
& QCOW2_COMPRESSED_SECTOR_MASK;
|
||||
ret = update_refcount(
|
||||
bs, coffset, csize,
|
||||
bs, coffset,
|
||||
nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE,
|
||||
abs(addend), addend < 0,
|
||||
QCOW2_DISCARD_SNAPSHOT);
|
||||
if (ret < 0) {
|
||||
@ -1587,66 +1587,6 @@ enum {
|
||||
CHECK_FRAG_INFO = 0x2, /* update BlockFragInfo counters */
|
||||
};
|
||||
|
||||
/*
|
||||
* Fix L2 entry by making it QCOW2_CLUSTER_ZERO_PLAIN (or making all its present
|
||||
* subclusters QCOW2_SUBCLUSTER_ZERO_PLAIN).
|
||||
*
|
||||
* This function decrements res->corruptions on success, so the caller is
|
||||
* responsible to increment res->corruptions prior to the call.
|
||||
*
|
||||
* On failure in-memory @l2_table may be modified.
|
||||
*/
|
||||
static int fix_l2_entry_by_zero(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
uint64_t l2_offset,
|
||||
uint64_t *l2_table, int l2_index, bool active,
|
||||
bool *metadata_overlap)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int ret;
|
||||
int idx = l2_index * (l2_entry_size(s) / sizeof(uint64_t));
|
||||
uint64_t l2e_offset = l2_offset + (uint64_t)l2_index * l2_entry_size(s);
|
||||
int ign = active ? QCOW2_OL_ACTIVE_L2 : QCOW2_OL_INACTIVE_L2;
|
||||
|
||||
if (has_subclusters(s)) {
|
||||
uint64_t l2_bitmap = get_l2_bitmap(s, l2_table, l2_index);
|
||||
|
||||
/* Allocated subclusters become zero */
|
||||
l2_bitmap |= l2_bitmap << 32;
|
||||
l2_bitmap &= QCOW_L2_BITMAP_ALL_ZEROES;
|
||||
|
||||
set_l2_bitmap(s, l2_table, l2_index, l2_bitmap);
|
||||
set_l2_entry(s, l2_table, l2_index, 0);
|
||||
} else {
|
||||
set_l2_entry(s, l2_table, l2_index, QCOW_OFLAG_ZERO);
|
||||
}
|
||||
|
||||
ret = qcow2_pre_write_overlap_check(bs, ign, l2e_offset, l2_entry_size(s),
|
||||
false);
|
||||
if (metadata_overlap) {
|
||||
*metadata_overlap = ret < 0;
|
||||
}
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ERROR: Overlap check failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = bdrv_pwrite_sync(bs->file, l2e_offset, &l2_table[idx],
|
||||
l2_entry_size(s));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ERROR: Failed to overwrite L2 "
|
||||
"table entry: %s\n", strerror(-ret));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
res->corruptions--;
|
||||
res->corruptions_fixed++;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
res->check_errors++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increases the refcount in the given refcount table for the all clusters
|
||||
* referenced in the L2 table. While doing so, performs some checks on L2
|
||||
@ -1661,41 +1601,26 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
int flags, BdrvCheckMode fix, bool active)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint64_t l2_entry, l2_bitmap;
|
||||
uint64_t *l2_table, l2_entry;
|
||||
uint64_t next_contiguous_offset = 0;
|
||||
int i, ret;
|
||||
size_t l2_size_bytes = s->l2_size * l2_entry_size(s);
|
||||
g_autofree uint64_t *l2_table = g_malloc(l2_size_bytes);
|
||||
bool metadata_overlap;
|
||||
int i, l2_size, nb_csectors, ret;
|
||||
|
||||
/* Read L2 table from disk */
|
||||
ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size_bytes);
|
||||
l2_size = s->l2_size * l2_entry_size(s);
|
||||
l2_table = g_malloc(l2_size);
|
||||
|
||||
ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n");
|
||||
res->check_errors++;
|
||||
return ret;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Do the actual checks */
|
||||
for (i = 0; i < s->l2_size; i++) {
|
||||
uint64_t coffset;
|
||||
int csize;
|
||||
QCow2ClusterType type;
|
||||
|
||||
for(i = 0; i < s->l2_size; i++) {
|
||||
l2_entry = get_l2_entry(s, l2_table, i);
|
||||
l2_bitmap = get_l2_bitmap(s, l2_table, i);
|
||||
type = qcow2_get_cluster_type(bs, l2_entry);
|
||||
|
||||
if (type != QCOW2_CLUSTER_COMPRESSED) {
|
||||
/* Check reserved bits of Standard Cluster Descriptor */
|
||||
if (l2_entry & L2E_STD_RESERVED_MASK) {
|
||||
fprintf(stderr, "ERROR found l2 entry with reserved bits set: "
|
||||
"%" PRIx64 "\n", l2_entry);
|
||||
res->corruptions++;
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
switch (qcow2_get_cluster_type(bs, l2_entry)) {
|
||||
case QCOW2_CLUSTER_COMPRESSED:
|
||||
/* Compressed clusters don't have QCOW_OFLAG_COPIED */
|
||||
if (l2_entry & QCOW_OFLAG_COPIED) {
|
||||
@ -1713,28 +1638,23 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
break;
|
||||
}
|
||||
|
||||
if (l2_bitmap) {
|
||||
fprintf(stderr, "ERROR compressed cluster %d with non-zero "
|
||||
"subcluster allocation bitmap, entry=0x%" PRIx64 "\n",
|
||||
i, l2_entry);
|
||||
res->corruptions++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Mark cluster as used */
|
||||
qcow2_parse_compressed_l2_entry(bs, l2_entry, &coffset, &csize);
|
||||
nb_csectors = ((l2_entry >> s->csize_shift) &
|
||||
s->csize_mask) + 1;
|
||||
l2_entry &= s->cluster_offset_mask;
|
||||
ret = qcow2_inc_refcounts_imrt(
|
||||
bs, res, refcount_table, refcount_table_size, coffset, csize);
|
||||
bs, res, refcount_table, refcount_table_size,
|
||||
l2_entry & QCOW2_COMPRESSED_SECTOR_MASK,
|
||||
nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (flags & CHECK_FRAG_INFO) {
|
||||
res->bfi.allocated_clusters++;
|
||||
res->bfi.compressed_clusters++;
|
||||
|
||||
/*
|
||||
* Compressed clusters are fragmented by nature. Since they
|
||||
/* Compressed clusters are fragmented by nature. Since they
|
||||
* take up sub-sector space but we only have sector granularity
|
||||
* I/O we need to re-read the same sectors even for adjacent
|
||||
* compressed clusters.
|
||||
@ -1748,19 +1668,13 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
{
|
||||
uint64_t offset = l2_entry & L2E_OFFSET_MASK;
|
||||
|
||||
if ((l2_bitmap >> 32) & l2_bitmap) {
|
||||
res->corruptions++;
|
||||
fprintf(stderr, "ERROR offset=%" PRIx64 ": Allocated "
|
||||
"cluster has corrupted subcluster allocation bitmap\n",
|
||||
offset);
|
||||
}
|
||||
|
||||
/* Correct offsets are cluster aligned */
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
bool contains_data;
|
||||
res->corruptions++;
|
||||
|
||||
if (has_subclusters(s)) {
|
||||
uint64_t l2_bitmap = get_l2_bitmap(s, l2_table, i);
|
||||
contains_data = (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC);
|
||||
} else {
|
||||
contains_data = !(l2_entry & QCOW_OFLAG_ZERO);
|
||||
@ -1773,30 +1687,40 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR",
|
||||
offset);
|
||||
if (fix & BDRV_FIX_ERRORS) {
|
||||
ret = fix_l2_entry_by_zero(bs, res, l2_offset,
|
||||
l2_table, i, active,
|
||||
&metadata_overlap);
|
||||
if (metadata_overlap) {
|
||||
/*
|
||||
* Something is seriously wrong, so abort checking
|
||||
* this L2 table.
|
||||
*/
|
||||
return ret;
|
||||
int idx = i * (l2_entry_size(s) / sizeof(uint64_t));
|
||||
uint64_t l2e_offset =
|
||||
l2_offset + (uint64_t)i * l2_entry_size(s);
|
||||
int ign = active ? QCOW2_OL_ACTIVE_L2 :
|
||||
QCOW2_OL_INACTIVE_L2;
|
||||
|
||||
l2_entry = has_subclusters(s) ? 0 : QCOW_OFLAG_ZERO;
|
||||
set_l2_entry(s, l2_table, i, l2_entry);
|
||||
ret = qcow2_pre_write_overlap_check(bs, ign,
|
||||
l2e_offset, l2_entry_size(s), false);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ERROR: Overlap check failed\n");
|
||||
res->check_errors++;
|
||||
/* Something is seriously wrong, so abort checking
|
||||
* this L2 table */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* Skip marking the cluster as used
|
||||
* (it is unused now).
|
||||
*/
|
||||
ret = bdrv_pwrite_sync(bs->file, l2e_offset,
|
||||
&l2_table[idx],
|
||||
l2_entry_size(s));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ERROR: Failed to overwrite L2 "
|
||||
"table entry: %s\n", strerror(-ret));
|
||||
res->check_errors++;
|
||||
/* Do not abort, continue checking the rest of this
|
||||
* L2 table's entries */
|
||||
} else {
|
||||
res->corruptions--;
|
||||
res->corruptions_fixed++;
|
||||
/* Skip marking the cluster as used
|
||||
* (it is unused now) */
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Failed to fix.
|
||||
* Do not abort, continue checking the rest of this
|
||||
* L2 table's entries.
|
||||
*/
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "ERROR offset=%" PRIx64 ": Data cluster is "
|
||||
@ -1819,23 +1743,14 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
refcount_table_size,
|
||||
offset, s->cluster_size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case QCOW2_CLUSTER_ZERO_PLAIN:
|
||||
/* Impossible when image has subclusters */
|
||||
assert(!l2_bitmap);
|
||||
break;
|
||||
|
||||
case QCOW2_CLUSTER_UNALLOCATED:
|
||||
if (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC) {
|
||||
res->corruptions++;
|
||||
fprintf(stderr, "ERROR: Unallocated "
|
||||
"cluster has non-zero subcluster allocation map\n");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1843,7 +1758,12 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
}
|
||||
}
|
||||
|
||||
g_free(l2_table);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
g_free(l2_table);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1862,60 +1782,47 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
||||
int flags, BdrvCheckMode fix, bool active)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
size_t l1_size_bytes = l1_size * L1E_SIZE;
|
||||
g_autofree uint64_t *l1_table = NULL;
|
||||
uint64_t l2_offset;
|
||||
uint64_t *l1_table = NULL, l2_offset, l1_size2;
|
||||
int i, ret;
|
||||
|
||||
if (!l1_size) {
|
||||
return 0;
|
||||
}
|
||||
l1_size2 = l1_size * L1E_SIZE;
|
||||
|
||||
/* Mark L1 table as used */
|
||||
ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size,
|
||||
l1_table_offset, l1_size_bytes);
|
||||
l1_table_offset, l1_size2);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
l1_table = g_try_malloc(l1_size_bytes);
|
||||
if (l1_table == NULL) {
|
||||
res->check_errors++;
|
||||
return -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Read L1 table entries from disk */
|
||||
ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size_bytes);
|
||||
if (l1_size2 > 0) {
|
||||
l1_table = g_try_malloc(l1_size2);
|
||||
if (l1_table == NULL) {
|
||||
ret = -ENOMEM;
|
||||
res->check_errors++;
|
||||
goto fail;
|
||||
}
|
||||
ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
|
||||
res->check_errors++;
|
||||
return ret;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < l1_size; i++) {
|
||||
for(i = 0;i < l1_size; i++)
|
||||
be64_to_cpus(&l1_table[i]);
|
||||
}
|
||||
|
||||
/* Do the actual checks */
|
||||
for (i = 0; i < l1_size; i++) {
|
||||
if (!l1_table[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (l1_table[i] & L1E_RESERVED_MASK) {
|
||||
fprintf(stderr, "ERROR found L1 entry with reserved bits set: "
|
||||
"%" PRIx64 "\n", l1_table[i]);
|
||||
res->corruptions++;
|
||||
}
|
||||
|
||||
l2_offset = l1_table[i] & L1E_OFFSET_MASK;
|
||||
|
||||
for(i = 0; i < l1_size; i++) {
|
||||
l2_offset = l1_table[i];
|
||||
if (l2_offset) {
|
||||
/* Mark L2 table as used */
|
||||
l2_offset &= L1E_OFFSET_MASK;
|
||||
ret = qcow2_inc_refcounts_imrt(bs, res,
|
||||
refcount_table, refcount_table_size,
|
||||
l2_offset, s->cluster_size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* L2 tables are cluster aligned */
|
||||
@ -1930,11 +1837,16 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
||||
refcount_table_size, l2_offset, flags,
|
||||
fix, active);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
g_free(l1_table);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
g_free(l1_table);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2089,17 +2001,9 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
|
||||
for(i = 0; i < s->refcount_table_size; i++) {
|
||||
uint64_t offset, cluster;
|
||||
offset = s->refcount_table[i] & REFT_OFFSET_MASK;
|
||||
offset = s->refcount_table[i];
|
||||
cluster = offset >> s->cluster_bits;
|
||||
|
||||
if (s->refcount_table[i] & REFT_RESERVED_MASK) {
|
||||
fprintf(stderr, "ERROR refcount table entry %" PRId64 " has "
|
||||
"reserved bits set\n", i);
|
||||
res->corruptions++;
|
||||
*rebuild = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Refcount blocks are cluster aligned */
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
fprintf(stderr, "ERROR refcount block %" PRId64 " is not "
|
||||
|
@ -74,7 +74,7 @@ typedef struct {
|
||||
|
||||
static int coroutine_fn
|
||||
qcow2_co_preadv_compressed(BlockDriverState *bs,
|
||||
uint64_t l2_entry,
|
||||
uint64_t cluster_descriptor,
|
||||
uint64_t offset,
|
||||
uint64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
@ -2205,7 +2205,7 @@ typedef struct Qcow2AioTask {
|
||||
|
||||
BlockDriverState *bs;
|
||||
QCow2SubclusterType subcluster_type; /* only for read */
|
||||
uint64_t host_offset; /* or l2_entry for compressed read */
|
||||
uint64_t host_offset; /* or full descriptor in compressed clusters */
|
||||
uint64_t offset;
|
||||
uint64_t bytes;
|
||||
QEMUIOVector *qiov;
|
||||
@ -2310,10 +2310,9 @@ static coroutine_fn int qcow2_co_preadv_task_entry(AioTask *task)
|
||||
}
|
||||
|
||||
static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
size_t qiov_offset, int flags)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int ret = 0;
|
||||
@ -2597,8 +2596,8 @@ static coroutine_fn int qcow2_co_pwritev_task_entry(AioTask *task)
|
||||
}
|
||||
|
||||
static coroutine_fn int qcow2_co_pwritev_part(
|
||||
BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags)
|
||||
BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset, int flags)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int offset_in_cluster;
|
||||
@ -3941,7 +3940,7 @@ static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
|
||||
}
|
||||
|
||||
static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes, BdrvRequestFlags flags)
|
||||
int64_t offset, int bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
@ -3996,7 +3995,7 @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes)
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
int ret;
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
@ -4026,9 +4025,9 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
|
||||
|
||||
static int coroutine_fn
|
||||
qcow2_co_copy_range_from(BlockDriverState *bs,
|
||||
BdrvChild *src, int64_t src_offset,
|
||||
BdrvChild *dst, int64_t dst_offset,
|
||||
int64_t bytes, BdrvRequestFlags read_flags,
|
||||
BdrvChild *src, uint64_t src_offset,
|
||||
BdrvChild *dst, uint64_t dst_offset,
|
||||
uint64_t bytes, BdrvRequestFlags read_flags,
|
||||
BdrvRequestFlags write_flags)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
@ -4109,9 +4108,9 @@ out:
|
||||
|
||||
static int coroutine_fn
|
||||
qcow2_co_copy_range_to(BlockDriverState *bs,
|
||||
BdrvChild *src, int64_t src_offset,
|
||||
BdrvChild *dst, int64_t dst_offset,
|
||||
int64_t bytes, BdrvRequestFlags read_flags,
|
||||
BdrvChild *src, uint64_t src_offset,
|
||||
BdrvChild *dst, uint64_t dst_offset,
|
||||
uint64_t bytes, BdrvRequestFlags read_flags,
|
||||
BdrvRequestFlags write_flags)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
@ -4631,7 +4630,7 @@ static coroutine_fn int qcow2_co_pwritev_compressed_task_entry(AioTask *task)
|
||||
*/
|
||||
static coroutine_fn int
|
||||
qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
@ -4694,19 +4693,22 @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
|
||||
|
||||
static int coroutine_fn
|
||||
qcow2_co_preadv_compressed(BlockDriverState *bs,
|
||||
uint64_t l2_entry,
|
||||
uint64_t cluster_descriptor,
|
||||
uint64_t offset,
|
||||
uint64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
size_t qiov_offset)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int ret = 0, csize;
|
||||
int ret = 0, csize, nb_csectors;
|
||||
uint64_t coffset;
|
||||
uint8_t *buf, *out_buf;
|
||||
int offset_in_cluster = offset_into_cluster(s, offset);
|
||||
|
||||
qcow2_parse_compressed_l2_entry(bs, l2_entry, &coffset, &csize);
|
||||
coffset = cluster_descriptor & s->cluster_offset_mask;
|
||||
nb_csectors = ((cluster_descriptor >> s->csize_shift) & s->csize_mask) + 1;
|
||||
csize = nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE -
|
||||
(coffset & ~QCOW2_COMPRESSED_SECTOR_MASK);
|
||||
|
||||
buf = g_try_malloc(csize);
|
||||
if (!buf) {
|
||||
@ -5228,55 +5230,24 @@ static int qcow2_has_zero_init(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the request to vmstate. On success return
|
||||
* qcow2_vm_state_offset(bs) + @pos
|
||||
*/
|
||||
static int64_t qcow2_check_vmstate_request(BlockDriverState *bs,
|
||||
QEMUIOVector *qiov, int64_t pos)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int64_t vmstate_offset = qcow2_vm_state_offset(s);
|
||||
int ret;
|
||||
|
||||
/* Incoming requests must be OK */
|
||||
bdrv_check_qiov_request(pos, qiov->size, qiov, 0, &error_abort);
|
||||
|
||||
if (INT64_MAX - pos < vmstate_offset) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
pos += vmstate_offset;
|
||||
ret = bdrv_check_qiov_request(pos, qiov->size, qiov, 0, NULL);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||
int64_t pos)
|
||||
{
|
||||
int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos);
|
||||
if (offset < 0) {
|
||||
return offset;
|
||||
}
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
|
||||
return bs->drv->bdrv_co_pwritev_part(bs, offset, qiov->size, qiov, 0, 0);
|
||||
return bs->drv->bdrv_co_pwritev_part(bs, qcow2_vm_state_offset(s) + pos,
|
||||
qiov->size, qiov, 0, 0);
|
||||
}
|
||||
|
||||
static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||
int64_t pos)
|
||||
{
|
||||
int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos);
|
||||
if (offset < 0) {
|
||||
return offset;
|
||||
}
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD);
|
||||
return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0);
|
||||
return bs->drv->bdrv_co_preadv_part(bs, qcow2_vm_state_offset(s) + pos,
|
||||
qiov->size, qiov, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -110,6 +110,7 @@
|
||||
|
||||
/* Defined in the qcow2 spec (compressed cluster descriptor) */
|
||||
#define QCOW2_COMPRESSED_SECTOR_SIZE 512U
|
||||
#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1ULL))
|
||||
|
||||
/* Must be at least 2 to cover COW */
|
||||
#define MIN_L2_CACHE_SIZE 2 /* cache entries */
|
||||
@ -586,12 +587,10 @@ typedef enum QCow2MetadataOverlap {
|
||||
(QCOW2_OL_CACHED | QCOW2_OL_INACTIVE_L2)
|
||||
|
||||
#define L1E_OFFSET_MASK 0x00fffffffffffe00ULL
|
||||
#define L1E_RESERVED_MASK 0x7f000000000001ffULL
|
||||
#define L2E_OFFSET_MASK 0x00fffffffffffe00ULL
|
||||
#define L2E_STD_RESERVED_MASK 0x3f000000000001feULL
|
||||
#define L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
|
||||
|
||||
#define REFT_OFFSET_MASK 0xfffffffffffffe00ULL
|
||||
#define REFT_RESERVED_MASK 0x1ffULL
|
||||
|
||||
#define INV_OFFSET (-1ULL)
|
||||
|
||||
@ -915,8 +914,6 @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset,
|
||||
int compressed_size,
|
||||
uint64_t *host_offset);
|
||||
void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
|
||||
uint64_t *coffset, int *csize);
|
||||
|
||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
|
||||
void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
|
||||
|
@ -582,7 +582,6 @@ static void bdrv_qed_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
|
||||
bs->bl.pwrite_zeroes_alignment = s->header.cluster_size;
|
||||
bs->bl.max_pwrite_zeroes = QEMU_ALIGN_DOWN(INT_MAX, s->header.cluster_size);
|
||||
}
|
||||
|
||||
/* We have nothing to do for QED reopen, stubs just return
|
||||
@ -1398,7 +1397,7 @@ static int coroutine_fn bdrv_qed_co_writev(BlockDriverState *bs,
|
||||
|
||||
static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset,
|
||||
int64_t bytes,
|
||||
int bytes,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
@ -1409,12 +1408,6 @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
*/
|
||||
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, bytes);
|
||||
|
||||
/*
|
||||
* QED is not prepared for 63bit write-zero requests, so rely on
|
||||
* max_pwrite_zeroes.
|
||||
*/
|
||||
assert(bytes <= INT_MAX);
|
||||
|
||||
/* Fall back if the request is not aligned */
|
||||
if (qed_offset_into_cluster(s, offset) ||
|
||||
qed_offset_into_cluster(s, bytes)) {
|
||||
|
@ -663,8 +663,8 @@ static int read_fifo_child(QuorumAIOCB *acb)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int quorum_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
static int quorum_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags);
|
||||
@ -714,9 +714,8 @@ static void write_quorum_entry(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
static int quorum_co_pwritev(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
static int quorum_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags);
|
||||
@ -746,7 +745,7 @@ static int quorum_co_pwritev(BlockDriverState *bs, int64_t offset,
|
||||
}
|
||||
|
||||
static int quorum_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, BdrvRequestFlags flags)
|
||||
int bytes, BdrvRequestFlags flags)
|
||||
|
||||
{
|
||||
return quorum_co_pwritev(bs, offset, bytes, NULL,
|
||||
|
@ -181,8 +181,8 @@ static void raw_reopen_abort(BDRVReopenState *state)
|
||||
}
|
||||
|
||||
/* Check and adjust the offset, against 'offset' and 'size' options. */
|
||||
static inline int raw_adjust_offset(BlockDriverState *bs, int64_t *offset,
|
||||
int64_t bytes, bool is_write)
|
||||
static inline int raw_adjust_offset(BlockDriverState *bs, uint64_t *offset,
|
||||
uint64_t bytes, bool is_write)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
@ -201,9 +201,9 @@ static inline int raw_adjust_offset(BlockDriverState *bs, int64_t *offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
static int coroutine_fn raw_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov,
|
||||
int flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -216,9 +216,9 @@ static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset,
|
||||
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov,
|
||||
int flags)
|
||||
{
|
||||
void *buf = NULL;
|
||||
BlockDriver *drv;
|
||||
@ -289,12 +289,12 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
int64_t offset, int bytes,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = raw_adjust_offset(bs, &offset, bytes, true);
|
||||
ret = raw_adjust_offset(bs, (uint64_t *)&offset, bytes, true);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@ -302,11 +302,11 @@ static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes)
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = raw_adjust_offset(bs, &offset, bytes, true);
|
||||
ret = raw_adjust_offset(bs, (uint64_t *)&offset, bytes, true);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@ -532,10 +532,10 @@ static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
|
||||
|
||||
static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs,
|
||||
BdrvChild *src,
|
||||
int64_t src_offset,
|
||||
uint64_t src_offset,
|
||||
BdrvChild *dst,
|
||||
int64_t dst_offset,
|
||||
int64_t bytes,
|
||||
uint64_t dst_offset,
|
||||
uint64_t bytes,
|
||||
BdrvRequestFlags read_flags,
|
||||
BdrvRequestFlags write_flags)
|
||||
{
|
||||
@ -551,10 +551,10 @@ static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs,
|
||||
|
||||
static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
|
||||
BdrvChild *src,
|
||||
int64_t src_offset,
|
||||
uint64_t src_offset,
|
||||
BdrvChild *dst,
|
||||
int64_t dst_offset,
|
||||
int64_t bytes,
|
||||
uint64_t dst_offset,
|
||||
uint64_t bytes,
|
||||
BdrvRequestFlags read_flags,
|
||||
BdrvRequestFlags write_flags)
|
||||
{
|
||||
@ -580,25 +580,6 @@ static void raw_cancel_in_flight(BlockDriverState *bs)
|
||||
bdrv_cancel_in_flight(bs->file->bs);
|
||||
}
|
||||
|
||||
static void raw_child_perm(BlockDriverState *bs, BdrvChild *c,
|
||||
BdrvChildRole role,
|
||||
BlockReopenQueue *reopen_queue,
|
||||
uint64_t parent_perm, uint64_t parent_shared,
|
||||
uint64_t *nperm, uint64_t *nshared)
|
||||
{
|
||||
bdrv_default_perms(bs, c, role, reopen_queue, parent_perm,
|
||||
parent_shared, nperm, nshared);
|
||||
|
||||
/*
|
||||
* bdrv_default_perms() may add WRITE and/or RESIZE (see comment in
|
||||
* bdrv_default_perms_for_storage() for an explanation) but we only need
|
||||
* them if they are in parent_perm. Drop WRITE and RESIZE whenever possible
|
||||
* to avoid permission conflicts.
|
||||
*/
|
||||
*nperm &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
|
||||
*nperm |= parent_perm & (BLK_PERM_WRITE | BLK_PERM_RESIZE);
|
||||
}
|
||||
|
||||
BlockDriver bdrv_raw = {
|
||||
.format_name = "raw",
|
||||
.instance_size = sizeof(BDRVRawState),
|
||||
@ -607,7 +588,7 @@ BlockDriver bdrv_raw = {
|
||||
.bdrv_reopen_commit = &raw_reopen_commit,
|
||||
.bdrv_reopen_abort = &raw_reopen_abort,
|
||||
.bdrv_open = &raw_open,
|
||||
.bdrv_child_perm = raw_child_perm,
|
||||
.bdrv_child_perm = bdrv_default_perms,
|
||||
.bdrv_co_create_opts = &raw_co_create_opts,
|
||||
.bdrv_co_preadv = &raw_co_preadv,
|
||||
.bdrv_co_pwritev = &raw_co_pwritev,
|
||||
|
132
block/rbd.c
132
block/rbd.c
@ -97,12 +97,6 @@ typedef struct RBDTask {
|
||||
int64_t ret;
|
||||
} RBDTask;
|
||||
|
||||
typedef struct RBDDiffIterateReq {
|
||||
uint64_t offs;
|
||||
uint64_t bytes;
|
||||
bool exists;
|
||||
} RBDDiffIterateReq;
|
||||
|
||||
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
|
||||
BlockdevOptionsRbd *opts, bool cache,
|
||||
const char *keypairs, const char *secretid,
|
||||
@ -1170,17 +1164,17 @@ static int coroutine_fn qemu_rbd_start_co(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int
|
||||
coroutine_fn qemu_rbd_co_preadv(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
coroutine_fn qemu_rbd_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov,
|
||||
int flags)
|
||||
{
|
||||
return qemu_rbd_start_co(bs, offset, bytes, qiov, flags, RBD_AIO_READ);
|
||||
}
|
||||
|
||||
static int
|
||||
coroutine_fn qemu_rbd_co_pwritev(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
coroutine_fn qemu_rbd_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov,
|
||||
int flags)
|
||||
{
|
||||
BDRVRBDState *s = bs->opaque;
|
||||
/*
|
||||
@ -1203,17 +1197,17 @@ static int coroutine_fn qemu_rbd_co_flush(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static int coroutine_fn qemu_rbd_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes)
|
||||
int64_t offset, int count)
|
||||
{
|
||||
return qemu_rbd_start_co(bs, offset, bytes, NULL, 0, RBD_AIO_DISCARD);
|
||||
return qemu_rbd_start_co(bs, offset, count, NULL, 0, RBD_AIO_DISCARD);
|
||||
}
|
||||
|
||||
#ifdef LIBRBD_SUPPORTS_WRITE_ZEROES
|
||||
static int
|
||||
coroutine_fn qemu_rbd_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, BdrvRequestFlags flags)
|
||||
int count, BdrvRequestFlags flags)
|
||||
{
|
||||
return qemu_rbd_start_co(bs, offset, bytes, NULL, flags,
|
||||
return qemu_rbd_start_co(bs, offset, count, NULL, flags,
|
||||
RBD_AIO_WRITE_ZEROES);
|
||||
}
|
||||
#endif
|
||||
@ -1265,111 +1259,6 @@ static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs,
|
||||
return spec_info;
|
||||
}
|
||||
|
||||
/*
|
||||
* rbd_diff_iterate2 allows to interrupt the exection by returning a negative
|
||||
* value in the callback routine. Choose a value that does not conflict with
|
||||
* an existing exitcode and return it if we want to prematurely stop the
|
||||
* execution because we detected a change in the allocation status.
|
||||
*/
|
||||
#define QEMU_RBD_EXIT_DIFF_ITERATE2 -9000
|
||||
|
||||
static int qemu_rbd_diff_iterate_cb(uint64_t offs, size_t len,
|
||||
int exists, void *opaque)
|
||||
{
|
||||
RBDDiffIterateReq *req = opaque;
|
||||
|
||||
assert(req->offs + req->bytes <= offs);
|
||||
/*
|
||||
* we do not diff against a snapshot so we should never receive a callback
|
||||
* for a hole.
|
||||
*/
|
||||
assert(exists);
|
||||
|
||||
if (!req->exists && offs > req->offs) {
|
||||
/*
|
||||
* we started in an unallocated area and hit the first allocated
|
||||
* block. req->bytes must be set to the length of the unallocated area
|
||||
* before the allocated area. stop further processing.
|
||||
*/
|
||||
req->bytes = offs - req->offs;
|
||||
return QEMU_RBD_EXIT_DIFF_ITERATE2;
|
||||
}
|
||||
|
||||
if (req->exists && offs > req->offs + req->bytes) {
|
||||
/*
|
||||
* we started in an allocated area and jumped over an unallocated area,
|
||||
* req->bytes contains the length of the allocated area before the
|
||||
* unallocated area. stop further processing.
|
||||
*/
|
||||
return QEMU_RBD_EXIT_DIFF_ITERATE2;
|
||||
}
|
||||
|
||||
req->bytes += len;
|
||||
req->exists = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
|
||||
bool want_zero, int64_t offset,
|
||||
int64_t bytes, int64_t *pnum,
|
||||
int64_t *map,
|
||||
BlockDriverState **file)
|
||||
{
|
||||
BDRVRBDState *s = bs->opaque;
|
||||
int status, r;
|
||||
RBDDiffIterateReq req = { .offs = offset };
|
||||
uint64_t features, flags;
|
||||
|
||||
assert(offset + bytes <= s->image_size);
|
||||
|
||||
/* default to all sectors allocated */
|
||||
status = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
|
||||
*map = offset;
|
||||
*file = bs;
|
||||
*pnum = bytes;
|
||||
|
||||
/* check if RBD image supports fast-diff */
|
||||
r = rbd_get_features(s->image, &features);
|
||||
if (r < 0) {
|
||||
return status;
|
||||
}
|
||||
if (!(features & RBD_FEATURE_FAST_DIFF)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* check if RBD fast-diff result is valid */
|
||||
r = rbd_get_flags(s->image, &flags);
|
||||
if (r < 0) {
|
||||
return status;
|
||||
}
|
||||
if (flags & RBD_FLAG_FAST_DIFF_INVALID) {
|
||||
return status;
|
||||
}
|
||||
|
||||
r = rbd_diff_iterate2(s->image, NULL, offset, bytes, true, true,
|
||||
qemu_rbd_diff_iterate_cb, &req);
|
||||
if (r < 0 && r != QEMU_RBD_EXIT_DIFF_ITERATE2) {
|
||||
return status;
|
||||
}
|
||||
assert(req.bytes <= bytes);
|
||||
if (!req.exists) {
|
||||
if (r == 0) {
|
||||
/*
|
||||
* rbd_diff_iterate2 does not invoke callbacks for unallocated
|
||||
* areas. This here catches the case where no callback was
|
||||
* invoked at all (req.bytes == 0).
|
||||
*/
|
||||
assert(req.bytes == 0);
|
||||
req.bytes = bytes;
|
||||
}
|
||||
status = BDRV_BLOCK_ZERO | BDRV_BLOCK_OFFSET_VALID;
|
||||
}
|
||||
|
||||
*pnum = req.bytes;
|
||||
return status;
|
||||
}
|
||||
|
||||
static int64_t qemu_rbd_getlength(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRBDState *s = bs->opaque;
|
||||
@ -1605,7 +1494,6 @@ static BlockDriver bdrv_rbd = {
|
||||
#ifdef LIBRBD_SUPPORTS_WRITE_ZEROES
|
||||
.bdrv_co_pwrite_zeroes = qemu_rbd_co_pwrite_zeroes,
|
||||
#endif
|
||||
.bdrv_co_block_status = qemu_rbd_co_block_status,
|
||||
|
||||
.bdrv_snapshot_create = qemu_rbd_snap_create,
|
||||
.bdrv_snapshot_delete = qemu_rbd_snap_remove,
|
||||
|
@ -149,7 +149,7 @@ static void replication_close(BlockDriverState *bs)
|
||||
if (s->stage == BLOCK_REPLICATION_FAILOVER) {
|
||||
commit_job = &s->commit_job->job;
|
||||
assert(commit_job->aio_context == qemu_get_current_aio_context());
|
||||
job_cancel_sync(commit_job, false);
|
||||
job_cancel_sync(commit_job);
|
||||
}
|
||||
|
||||
if (s->mode == REPLICATION_MODE_SECONDARY) {
|
||||
@ -726,7 +726,7 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
|
||||
* disk, secondary disk in backup_job_completed().
|
||||
*/
|
||||
if (s->backup_job) {
|
||||
job_cancel_sync(&s->backup_job->job, true);
|
||||
job_cancel_sync(&s->backup_job->job);
|
||||
}
|
||||
|
||||
if (!failover) {
|
||||
|
@ -54,8 +54,8 @@ static int stream_prepare(Job *job)
|
||||
{
|
||||
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
|
||||
BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs);
|
||||
BlockDriverState *base;
|
||||
BlockDriverState *unfiltered_base;
|
||||
BlockDriverState *base = bdrv_filter_or_cow_bs(s->above_base);
|
||||
BlockDriverState *unfiltered_base = bdrv_skip_filters(base);
|
||||
Error *local_err = NULL;
|
||||
int ret = 0;
|
||||
|
||||
@ -63,9 +63,6 @@ static int stream_prepare(Job *job)
|
||||
bdrv_cor_filter_drop(s->cor_filter_bs);
|
||||
s->cor_filter_bs = NULL;
|
||||
|
||||
base = bdrv_filter_or_cow_bs(s->above_base);
|
||||
unfiltered_base = bdrv_skip_filters(base);
|
||||
|
||||
if (bdrv_cow_child(unfiltered_bs)) {
|
||||
const char *base_id = NULL, *base_fmt = NULL;
|
||||
if (unfiltered_base) {
|
||||
|
@ -112,9 +112,8 @@ static int64_t throttle_getlength(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static int coroutine_fn throttle_co_preadv(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
|
||||
ThrottleGroupMember *tgm = bs->opaque;
|
||||
@ -124,9 +123,8 @@ static int coroutine_fn throttle_co_preadv(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
ThrottleGroupMember *tgm = bs->opaque;
|
||||
throttle_group_co_io_limits_intercept(tgm, bytes, true);
|
||||
@ -135,7 +133,7 @@ static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int coroutine_fn throttle_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes,
|
||||
int64_t offset, int bytes,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
ThrottleGroupMember *tgm = bs->opaque;
|
||||
@ -145,7 +143,7 @@ static int coroutine_fn throttle_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int coroutine_fn throttle_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int64_t bytes)
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
ThrottleGroupMember *tgm = bs->opaque;
|
||||
throttle_group_co_io_limits_intercept(tgm, bytes, true);
|
||||
@ -154,8 +152,8 @@ static int coroutine_fn throttle_co_pdiscard(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int coroutine_fn throttle_co_pwritev_compressed(BlockDriverState *bs,
|
||||
int64_t offset,
|
||||
int64_t bytes,
|
||||
uint64_t offset,
|
||||
uint64_t bytes,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
return throttle_co_pwritev(bs, offset, bytes, qiov,
|
||||
|
@ -5,8 +5,8 @@ bdrv_open_common(void *bs, const char *filename, int flags, const char *format_n
|
||||
bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
|
||||
|
||||
# block-backend.c
|
||||
blk_co_preadv(void *blk, void *bs, int64_t offset, int64_t bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %" PRId64 " flags 0x%x"
|
||||
blk_co_pwritev(void *blk, void *bs, int64_t offset, int64_t bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %" PRId64 " flags 0x%x"
|
||||
blk_co_preadv(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x"
|
||||
blk_co_pwritev(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x"
|
||||
blk_root_attach(void *child, void *blk, void *bs) "child %p blk %p bs %p"
|
||||
blk_root_detach(void *child, void *blk, void *bs) "child %p blk %p bs %p"
|
||||
|
||||
@ -75,13 +75,13 @@ luring_resubmit_short_read(void *s, void *luringcb, int nread) "LuringState %p l
|
||||
|
||||
# qcow2.c
|
||||
qcow2_add_task(void *co, void *bs, void *pool, const char *action, int cluster_type, uint64_t host_offset, uint64_t offset, uint64_t bytes, void *qiov, size_t qiov_offset) "co %p bs %p pool %p: %s: cluster_type %d file_cluster_offset %" PRIu64 " offset %" PRIu64 " bytes %" PRIu64 " qiov %p qiov_offset %zu"
|
||||
qcow2_writev_start_req(void *co, int64_t offset, int64_t bytes) "co %p offset 0x%" PRIx64 " bytes %" PRId64
|
||||
qcow2_writev_start_req(void *co, int64_t offset, int bytes) "co %p offset 0x%" PRIx64 " bytes %d"
|
||||
qcow2_writev_done_req(void *co, int ret) "co %p ret %d"
|
||||
qcow2_writev_start_part(void *co) "co %p"
|
||||
qcow2_writev_done_part(void *co, int cur_bytes) "co %p cur_bytes %d"
|
||||
qcow2_writev_data(void *co, uint64_t offset) "co %p offset 0x%" PRIx64
|
||||
qcow2_pwrite_zeroes_start_req(void *co, int64_t offset, int64_t bytes) "co %p offset 0x%" PRIx64 " bytes %" PRId64
|
||||
qcow2_pwrite_zeroes(void *co, int64_t offset, int64_t bytes) "co %p offset 0x%" PRIx64 " bytes %" PRId64
|
||||
qcow2_pwrite_zeroes_start_req(void *co, int64_t offset, int count) "co %p offset 0x%" PRIx64 " count %d"
|
||||
qcow2_pwrite_zeroes(void *co, int64_t offset, int count) "co %p offset 0x%" PRIx64 " count %d"
|
||||
qcow2_skip_cow(void *co, uint64_t offset, int nb_clusters) "co %p offset 0x%" PRIx64 " nb_clusters %d"
|
||||
|
||||
# qcow2-cluster.c
|
||||
@ -152,12 +152,12 @@ nvme_write_zeroes(void *s, uint64_t offset, uint64_t bytes, int flags) "s %p off
|
||||
nvme_qiov_unaligned(const void *qiov, int n, void *base, size_t size, int align) "qiov %p n %d base %p size 0x%zx align 0x%x"
|
||||
nvme_prw_buffered(void *s, uint64_t offset, uint64_t bytes, int niov, int is_write) "s %p offset 0x%"PRIx64" bytes %"PRId64" niov %d is_write %d"
|
||||
nvme_rw_done(void *s, int is_write, uint64_t offset, uint64_t bytes, int ret) "s %p is_write %d offset 0x%"PRIx64" bytes %"PRId64" ret %d"
|
||||
nvme_dsm(void *s, int64_t offset, int64_t bytes) "s %p offset 0x%"PRIx64" bytes %"PRId64""
|
||||
nvme_dsm_done(void *s, int64_t offset, int64_t bytes, int ret) "s %p offset 0x%"PRIx64" bytes %"PRId64" ret %d"
|
||||
nvme_dsm(void *s, uint64_t offset, uint64_t bytes) "s %p offset 0x%"PRIx64" bytes %"PRId64""
|
||||
nvme_dsm_done(void *s, uint64_t offset, uint64_t bytes, int ret) "s %p offset 0x%"PRIx64" bytes %"PRId64" ret %d"
|
||||
nvme_dma_map_flush(void *s) "s %p"
|
||||
nvme_free_req_queue_wait(void *s, unsigned q_index) "s %p q #%u"
|
||||
nvme_create_queue_pair(unsigned q_index, void *q, size_t size, void *aio_context, int fd) "index %u q %p size %zu aioctx %p fd %d"
|
||||
nvme_free_queue_pair(unsigned q_index, void *q, void *cq, void *sq) "index %u q %p cq %p sq %p"
|
||||
nvme_create_queue_pair(unsigned q_index, void *q, unsigned size, void *aio_context, int fd) "index %u q %p size %u aioctx %p fd %d"
|
||||
nvme_free_queue_pair(unsigned q_index, void *q) "index %u q %p"
|
||||
nvme_cmd_map_qiov(void *s, void *cmd, void *req, void *qiov, int entries) "s %p cmd %p req %p qiov %p entries %d"
|
||||
nvme_cmd_map_qiov_pages(void *s, int i, uint64_t page) "s %p page[%d] 0x%"PRIx64
|
||||
nvme_cmd_map_qiov_iov(void *s, int i, void *page, int pages) "s %p iov[%d] %p pages %d"
|
||||
|
@ -544,8 +544,8 @@ static int coroutine_fn vdi_co_block_status(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
vdi_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
vdi_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVVdiState *s = bs->opaque;
|
||||
QEMUIOVector local_qiov;
|
||||
@ -600,8 +600,8 @@ vdi_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
vdi_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
vdi_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVVdiState *s = bs->opaque;
|
||||
QEMUIOVector local_qiov;
|
||||
|
38
block/vmdk.c
38
block/vmdk.c
@ -60,7 +60,6 @@
|
||||
#define VMDK_ZEROED (-3)
|
||||
|
||||
#define BLOCK_OPT_ZEROED_GRAIN "zeroed_grain"
|
||||
#define BLOCK_OPT_TOOLSVERSION "toolsversion"
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
@ -1889,8 +1888,8 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
vmdk_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
vmdk_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int ret;
|
||||
@ -2069,8 +2068,8 @@ static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
vmdk_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
vmdk_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
int ret;
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
@ -2081,8 +2080,8 @@ vmdk_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov)
|
||||
vmdk_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov)
|
||||
{
|
||||
if (bytes == 0) {
|
||||
/* The caller will write bytes 0 to signal EOF.
|
||||
@ -2110,7 +2109,7 @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
|
||||
static int coroutine_fn vmdk_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset,
|
||||
int64_t bytes,
|
||||
int bytes,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
@ -2345,7 +2344,6 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
|
||||
BlockdevVmdkAdapterType adapter_type,
|
||||
const char *backing_file,
|
||||
const char *hw_version,
|
||||
const char *toolsversion,
|
||||
bool compat6,
|
||||
bool zeroed_grain,
|
||||
vmdk_create_extent_fn extent_fn,
|
||||
@ -2386,8 +2384,7 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
|
||||
"ddb.geometry.cylinders = \"%" PRId64 "\"\n"
|
||||
"ddb.geometry.heads = \"%" PRIu32 "\"\n"
|
||||
"ddb.geometry.sectors = \"63\"\n"
|
||||
"ddb.adapterType = \"%s\"\n"
|
||||
"ddb.toolsVersion = \"%s\"\n";
|
||||
"ddb.adapterType = \"%s\"\n";
|
||||
|
||||
ext_desc_lines = g_string_new(NULL);
|
||||
|
||||
@ -2404,9 +2401,6 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
|
||||
if (!hw_version) {
|
||||
hw_version = "4";
|
||||
}
|
||||
if (!toolsversion) {
|
||||
toolsversion = "2147483647";
|
||||
}
|
||||
|
||||
if (adapter_type != BLOCKDEV_VMDK_ADAPTER_TYPE_IDE) {
|
||||
/* that's the number of heads with which vmware operates when
|
||||
@ -2531,8 +2525,7 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
|
||||
size /
|
||||
(int64_t)(63 * number_heads * BDRV_SECTOR_SIZE),
|
||||
number_heads,
|
||||
BlockdevVmdkAdapterType_str(adapter_type),
|
||||
toolsversion);
|
||||
BlockdevVmdkAdapterType_str(adapter_type));
|
||||
desc_len = strlen(desc);
|
||||
/* the descriptor offset = 0x200 */
|
||||
if (!split && !flat) {
|
||||
@ -2624,7 +2617,6 @@ static int coroutine_fn vmdk_co_create_opts(BlockDriver *drv,
|
||||
BlockdevVmdkAdapterType adapter_type_enum;
|
||||
char *backing_file = NULL;
|
||||
char *hw_version = NULL;
|
||||
char *toolsversion = NULL;
|
||||
char *fmt = NULL;
|
||||
BlockdevVmdkSubformat subformat;
|
||||
int ret = 0;
|
||||
@ -2657,7 +2649,6 @@ static int coroutine_fn vmdk_co_create_opts(BlockDriver *drv,
|
||||
adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE);
|
||||
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
|
||||
hw_version = qemu_opt_get_del(opts, BLOCK_OPT_HWVERSION);
|
||||
toolsversion = qemu_opt_get_del(opts, BLOCK_OPT_TOOLSVERSION);
|
||||
compat6 = qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false);
|
||||
if (strcmp(hw_version, "undefined") == 0) {
|
||||
g_free(hw_version);
|
||||
@ -2701,15 +2692,14 @@ static int coroutine_fn vmdk_co_create_opts(BlockDriver *drv,
|
||||
.opts = opts,
|
||||
};
|
||||
ret = vmdk_co_do_create(total_size, subformat, adapter_type_enum,
|
||||
backing_file, hw_version, toolsversion, compat6,
|
||||
zeroed_grain, vmdk_co_create_opts_cb, &data, errp);
|
||||
backing_file, hw_version, compat6, zeroed_grain,
|
||||
vmdk_co_create_opts_cb, &data, errp);
|
||||
|
||||
exit:
|
||||
g_free(backing_fmt);
|
||||
g_free(adapter_type);
|
||||
g_free(backing_file);
|
||||
g_free(hw_version);
|
||||
g_free(toolsversion);
|
||||
g_free(fmt);
|
||||
g_free(desc);
|
||||
g_free(path);
|
||||
@ -2792,7 +2782,6 @@ static int coroutine_fn vmdk_co_create(BlockdevCreateOptions *create_options,
|
||||
opts->adapter_type,
|
||||
opts->backing_file,
|
||||
opts->hwversion,
|
||||
opts->toolsversion,
|
||||
false,
|
||||
opts->zeroed_grain,
|
||||
vmdk_co_create_cb,
|
||||
@ -3042,11 +3031,6 @@ static QemuOptsList vmdk_create_opts = {
|
||||
.help = "VMDK hardware version",
|
||||
.def_value_str = "undefined"
|
||||
},
|
||||
{
|
||||
.name = BLOCK_OPT_TOOLSVERSION,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "VMware guest tools version",
|
||||
},
|
||||
{
|
||||
.name = BLOCK_OPT_SUBFMT,
|
||||
.type = QEMU_OPT_STRING,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user