Compare commits
156
Commits
v5.0.1
..
stable-4.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cdf8c4efa | ||
|
|
4a0db6ba7d | ||
|
|
0664ffac4b | ||
|
|
27f56b9aa2 | ||
|
|
97701bc03e | ||
|
|
ecdb0d5651 | ||
|
|
9c2e242077 | ||
|
|
fb6a24fb1d | ||
|
|
60c21aa017 | ||
|
|
5eca12bbad | ||
|
|
1c8d9fb334 | ||
|
|
09397e9657 | ||
|
|
674d382225 | ||
|
|
5ff78dc9bc | ||
|
|
47e0fa7479 | ||
|
|
745859d5bf | ||
|
|
c6decabc4a | ||
|
|
580c08b326 | ||
|
|
9dd68ac26b | ||
|
|
4e258da94a | ||
|
|
e08de99abe | ||
|
|
5e063a5846 | ||
|
|
1509a13240 | ||
|
|
0b487ea664 | ||
|
|
3dd28c8ecc | ||
|
|
ee9f37f3e5 | ||
|
|
8952da32c3 | ||
|
|
e92b21ffc4 | ||
|
|
a967e75f3a | ||
|
|
aacf6bfb7e | ||
|
|
4b34c6d724 | ||
|
|
9adb6569bf | ||
|
|
b1b362aa8e | ||
|
|
dc6bdba433 | ||
|
|
bc509b2a5b | ||
|
|
cd8ecfb19c | ||
|
|
abf9ffa7b3 | ||
|
|
c44015c50c | ||
|
|
b5ba361d8f | ||
|
|
52771abbfa | ||
|
|
d306348fd6 | ||
|
|
f3ef98874e | ||
|
|
e8a286010c | ||
|
|
9a30621d3d | ||
|
|
0972fbf353 | ||
|
|
9b59fdf478 | ||
|
|
ec3bd881e2 | ||
|
|
65fad28d85 | ||
|
|
256ecc06eb | ||
|
|
606a6bf788 | ||
|
|
e8ae3a4e2b | ||
|
|
7e1bc51f3f | ||
|
|
8d151ab5c2 | ||
|
|
6772bba8a4 | ||
|
|
45b65bf8df | ||
|
|
aea7a50fb5 | ||
|
|
2f7597fbc2 | ||
|
|
f127d16397 | ||
|
|
862240852b | ||
|
|
1343d33371 | ||
|
|
c436692c6a | ||
|
|
69a6048e1e | ||
|
|
01392ae31a | ||
|
|
4e98c388d6 | ||
|
|
54bcaf08d6 | ||
|
|
e727aa1a7b | ||
|
|
690e3004ae | ||
|
|
a918ea2ec3 | ||
|
|
c1cad76dcd | ||
|
|
a6e44eee6c | ||
|
|
3729ff3032 | ||
|
|
2367c7235b | ||
|
|
0c6499ff2b | ||
|
|
17216bc044 | ||
|
|
410252fc5b | ||
|
|
603cda272d | ||
|
|
03afe9c035 | ||
|
|
18f6b13e08 | ||
|
|
6c75ddf4a9 | ||
|
|
d6d45d9ed1 | ||
|
|
2a7c80d82e | ||
|
|
e27f334fdc | ||
|
|
0c1d805360 | ||
|
|
252d614ea2 | ||
|
|
dad6d5e7e6 | ||
|
|
ad56aecb21 | ||
|
|
d5691a6373 | ||
|
|
34c78a4100 | ||
|
|
8d127b4be7 | ||
|
|
ea1518bb5e | ||
|
|
c5feb39219 | ||
|
|
25fcaed9a3 | ||
|
|
aabd9ddd2d | ||
|
|
33be7aa9b6 | ||
|
|
8f5728cb97 | ||
|
|
e3531619f1 | ||
|
|
4996bd7161 | ||
|
|
3c3e1653c5 | ||
|
|
7cc217b30d | ||
|
|
219362f965 | ||
|
|
8fc4aa4822 | ||
|
|
4a9486a02d | ||
|
|
c44c4f7229 | ||
|
|
a0dc4d2495 | ||
|
|
e0ccde3887 | ||
|
|
4a1c5955e7 | ||
|
|
2dc540e40d | ||
|
|
4540aa4a8d | ||
|
|
30aa0ea6c5 | ||
|
|
382b9f09bd | ||
|
|
373fd948ab | ||
|
|
ab7f6eaa5b | ||
|
|
f9854de0d8 | ||
|
|
e49ae74a24 | ||
|
|
0319118bcf | ||
|
|
2a7569e751 | ||
|
|
3e1d95301e | ||
|
|
735cd8ddab | ||
|
|
1190026fe4 | ||
|
|
8d61b1e2c4 | ||
|
|
cbc8277051 | ||
|
|
e7cad754fd | ||
|
|
d50aa8acbc | ||
|
|
3a8068f4eb | ||
|
|
5f08c382ca | ||
|
|
edd67a61f4 | ||
|
|
153c3320e7 | ||
|
|
bf3f12ac8c | ||
|
|
956e1b2d97 | ||
|
|
eb54a2f9ce | ||
|
|
fa446ae444 | ||
|
|
3fb2521040 | ||
|
|
742195db17 | ||
|
|
98c74fe49a | ||
|
|
7042922dd7 | ||
|
|
a474197f11 | ||
|
|
a843731d7f | ||
|
|
d5a5d43e27 | ||
|
|
0253531824 | ||
|
|
2f4affb721 | ||
|
|
77d9c84d9f | ||
|
|
4412cb3bca | ||
|
|
3a94a8b7fd | ||
|
|
0cfa46da8f | ||
|
|
ba6a94e64e | ||
|
|
a5f815514a | ||
|
|
2215837fe2 | ||
|
|
cbdfd3865b | ||
|
|
89eebb016d | ||
|
|
def30090ad | ||
|
|
52a02834e0 | ||
|
|
da0948d13c | ||
|
|
d636d64b35 | ||
|
|
bed590f2b8 | ||
|
|
a115daadf6 | ||
|
|
85df33073a |
No files matched your search
+2
-6
@@ -22,9 +22,7 @@ macos_task:
|
||||
install_script:
|
||||
- brew install pkg-config python gnu-sed glib pixman make sdl2
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --python=/usr/local/bin/python3 || { cat config.log; exit 1; }
|
||||
- ./configure --python=/usr/local/bin/python3 || { cat config.log; exit 1; }
|
||||
- gmake -j$(sysctl -n hw.ncpu)
|
||||
- gmake check -j$(sysctl -n hw.ncpu)
|
||||
|
||||
@@ -35,8 +33,6 @@ macos_xcode_task:
|
||||
install_script:
|
||||
- brew install pkg-config gnu-sed glib pixman make sdl2
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --cc=clang || { cat config.log; exit 1; }
|
||||
- ./configure --cc=clang || { cat config.log; exit 1; }
|
||||
- gmake -j$(sysctl -n hw.ncpu)
|
||||
- gmake check -j$(sysctl -n hw.ncpu)
|
||||
@@ -1,34 +0,0 @@
|
||||
# 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 master
|
||||
repostories hosted on https://git.qemu.org/git/qemu.git.
|
||||
The project does not process issues filed on GitHub.
|
||||
|
||||
The project issues are tracked on Launchpad:
|
||||
https://bugs.launchpad.net/qemu
|
||||
|
||||
QEMU welcomes bug report contributions. You can file new ones on:
|
||||
https://bugs.launchpad.net/qemu/+filebug
|
||||
|
||||
pulls:
|
||||
comment: |
|
||||
Thank you for your interest in the QEMU project.
|
||||
|
||||
This repository is a read-only mirror of the project's master
|
||||
repostories hosted on https://git.qemu.org/git/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/
|
||||
+3
-2
@@ -6,7 +6,6 @@
|
||||
/config-target.*
|
||||
/config.status
|
||||
/config-temp
|
||||
/tools/virtiofsd/50-qemu-virtiofsd.json
|
||||
/elf2dmp
|
||||
/trace-events-all
|
||||
/trace/generated-events.h
|
||||
@@ -38,7 +37,6 @@
|
||||
/qapi/qapi-emit-events.[ch]
|
||||
/qapi/qapi-events-*.[ch]
|
||||
/qapi/qapi-events.[ch]
|
||||
/qapi/qapi-init-commands.[ch]
|
||||
/qapi/qapi-introspect.[ch]
|
||||
/qapi/qapi-types-*.[ch]
|
||||
/qapi/qapi-types.[ch]
|
||||
@@ -46,6 +44,9 @@
|
||||
!/qapi/qapi-visit-core.c
|
||||
/qapi/qapi-visit.[ch]
|
||||
/qapi/qapi-doc.texi
|
||||
/qemu-doc.html
|
||||
/qemu-doc.info
|
||||
/qemu-doc.txt
|
||||
/qemu-edid
|
||||
/qemu-img
|
||||
/qemu-nbd
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
docker-edk2:
|
||||
stage: build
|
||||
rules: # Only run this job when the Dockerfile is modified
|
||||
- changes:
|
||||
- .gitlab-ci-edk2.yml
|
||||
- .gitlab-ci.d/edk2/Dockerfile
|
||||
when: always
|
||||
image: docker:19.03.1
|
||||
services:
|
||||
- docker:19.03.1-dind
|
||||
variables:
|
||||
GIT_DEPTH: 3
|
||||
IMAGE_TAG: $CI_REGISTRY_IMAGE:edk2-cross-build
|
||||
# We don't use TLS
|
||||
DOCKER_HOST: tcp://docker:2375
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
before_script:
|
||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||
script:
|
||||
- docker pull $IMAGE_TAG || true
|
||||
- docker build --cache-from $IMAGE_TAG --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
--tag $IMAGE_TAG .gitlab-ci.d/edk2
|
||||
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
- docker push $IMAGE_TAG
|
||||
|
||||
build-edk2:
|
||||
rules: # Only run this job when ...
|
||||
- changes: # ... roms/edk2/ is modified (submodule updated)
|
||||
- roms/edk2/*
|
||||
when: always
|
||||
- if: '$CI_COMMIT_REF_NAME =~ /^edk2/' # or the branch/tag starts with 'edk2'
|
||||
when: always
|
||||
- if: '$CI_COMMIT_MESSAGE =~ /edk2/i' # or last commit description contains 'EDK2'
|
||||
when: always
|
||||
artifacts:
|
||||
paths: # 'artifacts.zip' will contains the following files:
|
||||
- pc-bios/edk2*bz2
|
||||
- pc-bios/edk2-licenses.txt
|
||||
- edk2-stdout.log
|
||||
- edk2-stderr.log
|
||||
image: $CI_REGISTRY_IMAGE:edk2-cross-build
|
||||
variables:
|
||||
GIT_DEPTH: 3
|
||||
script: # Clone the required submodules and build EDK2
|
||||
- git submodule update --init roms/edk2
|
||||
- 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
|
||||
@@ -1,63 +0,0 @@
|
||||
docker-opensbi:
|
||||
stage: build
|
||||
rules: # Only run this job when the Dockerfile is modified
|
||||
- changes:
|
||||
- .gitlab-ci-opensbi.yml
|
||||
- .gitlab-ci.d/opensbi/Dockerfile
|
||||
when: always
|
||||
image: docker:19.03.1
|
||||
services:
|
||||
- docker:19.03.1-dind
|
||||
variables:
|
||||
GIT_DEPTH: 3
|
||||
IMAGE_TAG: $CI_REGISTRY_IMAGE:opensbi-cross-build
|
||||
# We don't use TLS
|
||||
DOCKER_HOST: tcp://docker:2375
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
before_script:
|
||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||
script:
|
||||
- docker pull $IMAGE_TAG || true
|
||||
- docker build --cache-from $IMAGE_TAG --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
--tag $IMAGE_TAG .gitlab-ci.d/opensbi
|
||||
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
- docker push $IMAGE_TAG
|
||||
|
||||
build-opensbi:
|
||||
rules: # Only run this job when ...
|
||||
- changes: # ... roms/opensbi/ is modified (submodule updated)
|
||||
- roms/opensbi/*
|
||||
when: always
|
||||
- if: '$CI_COMMIT_REF_NAME =~ /^opensbi/' # or the branch/tag starts with 'opensbi'
|
||||
when: always
|
||||
- if: '$CI_COMMIT_MESSAGE =~ /opensbi/i' # or last commit description contains 'OpenSBI'
|
||||
when: always
|
||||
artifacts:
|
||||
paths: # 'artifacts.zip' will contains the following files:
|
||||
- pc-bios/opensbi-riscv32-sifive_u-fw_jump.bin
|
||||
- pc-bios/opensbi-riscv32-virt-fw_jump.bin
|
||||
- pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin
|
||||
- pc-bios/opensbi-riscv64-virt-fw_jump.bin
|
||||
- opensbi32-virt-stdout.log
|
||||
- opensbi32-virt-stderr.log
|
||||
- opensbi64-virt-stdout.log
|
||||
- opensbi64-virt-stderr.log
|
||||
- opensbi32-sifive_u-stdout.log
|
||||
- opensbi32-sifive_u-stderr.log
|
||||
- opensbi64-sifive_u-stdout.log
|
||||
- opensbi64-sifive_u-stderr.log
|
||||
image: $CI_REGISTRY_IMAGE:opensbi-cross-build
|
||||
variables:
|
||||
GIT_DEPTH: 3
|
||||
script: # Clone the required submodules and build OpenSBI
|
||||
- git submodule update --init roms/opensbi
|
||||
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||
- echo "=== Using ${JOBS} simultaneous jobs ==="
|
||||
- make -j${JOBS} -C roms/opensbi clean
|
||||
- make -j${JOBS} -C roms opensbi32-virt 2>&1 1>opensbi32-virt-stdout.log | tee -a opensbi32-virt-stderr.log >&2
|
||||
- make -j${JOBS} -C roms/opensbi clean
|
||||
- make -j${JOBS} -C roms opensbi64-virt 2>&1 1>opensbi64-virt-stdout.log | tee -a opensbi64-virt-stderr.log >&2
|
||||
- make -j${JOBS} -C roms/opensbi clean
|
||||
- make -j${JOBS} -C roms opensbi32-sifive_u 2>&1 1>opensbi32-sifive_u-stdout.log | tee -a opensbi32-sifive_u-stderr.log >&2
|
||||
- make -j${JOBS} -C roms/opensbi clean
|
||||
- make -j${JOBS} -C roms opensbi64-sifive_u 2>&1 1>opensbi64-sifive_u-stdout.log | tee -a opensbi64-sifive_u-stderr.log >&2
|
||||
@@ -1,27 +0,0 @@
|
||||
#
|
||||
# Docker image to cross-compile EDK2 firmware binaries
|
||||
#
|
||||
FROM ubuntu:16.04
|
||||
|
||||
MAINTAINER Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
|
||||
# Install packages required to build EDK2
|
||||
RUN apt update \
|
||||
&& \
|
||||
\
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
apt install --assume-yes --no-install-recommends \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
dos2unix \
|
||||
gcc-aarch64-linux-gnu \
|
||||
gcc-arm-linux-gnueabi \
|
||||
git \
|
||||
iasl \
|
||||
make \
|
||||
nasm \
|
||||
python \
|
||||
uuid-dev \
|
||||
&& \
|
||||
\
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
@@ -1,33 +0,0 @@
|
||||
#
|
||||
# Docker image to cross-compile OpenSBI firmware binaries
|
||||
#
|
||||
FROM ubuntu:18.04
|
||||
|
||||
MAINTAINER Bin Meng <bmeng.cn@gmail.com>
|
||||
|
||||
# Install packages required to build OpenSBI
|
||||
RUN apt update \
|
||||
&& \
|
||||
\
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
apt install --assume-yes --no-install-recommends \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
git \
|
||||
make \
|
||||
wget \
|
||||
&& \
|
||||
\
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Manually install the kernel.org "Crosstool" based toolchains for gcc-8.3
|
||||
RUN wget -O - \
|
||||
https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin/x86_64/8.3.0/x86_64-gcc-8.3.0-nolibc-riscv32-linux.tar.xz \
|
||||
| tar -C /opt -xJ
|
||||
RUN wget -O - \
|
||||
https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin/x86_64/8.3.0/x86_64-gcc-8.3.0-nolibc-riscv64-linux.tar.xz \
|
||||
| tar -C /opt -xJ
|
||||
|
||||
# Export the toolchains to the system path
|
||||
ENV PATH="/opt/gcc-8.3.0-nolibc/riscv32-linux/bin:${PATH}"
|
||||
ENV PATH="/opt/gcc-8.3.0-nolibc/riscv64-linux/bin:${PATH}"
|
||||
+20
-41
@@ -1,7 +1,3 @@
|
||||
include:
|
||||
- local: '/.gitlab-ci-edk2.yml'
|
||||
- local: '/.gitlab-ci-opensbi.yml'
|
||||
|
||||
before_script:
|
||||
- apt-get update -qq
|
||||
- apt-get install -y -qq flex bison libglib2.0-dev libpixman-1-dev genisoimage
|
||||
@@ -10,9 +6,7 @@ build-system1:
|
||||
script:
|
||||
- apt-get install -y -qq libgtk-3-dev libvte-dev nettle-dev libcacard-dev
|
||||
libusb-dev libvde-dev libspice-protocol-dev libgl1-mesa-dev libvdeplug-dev
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-werror --target-list="aarch64-softmmu alpha-softmmu
|
||||
- ./configure --enable-werror --target-list="aarch64-softmmu alpha-softmmu
|
||||
cris-softmmu hppa-softmmu lm32-softmmu moxie-softmmu microblazeel-softmmu
|
||||
mips64el-softmmu m68k-softmmu ppc-softmmu riscv64-softmmu sparc-softmmu"
|
||||
- make -j2
|
||||
@@ -22,10 +16,7 @@ build-system2:
|
||||
script:
|
||||
- apt-get install -y -qq libsdl2-dev libgcrypt-dev libbrlapi-dev libaio-dev
|
||||
libfdt-dev liblzo2-dev librdmacm-dev libibverbs-dev libibumad-dev
|
||||
libzstd-dev
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-werror --target-list="tricore-softmmu unicore32-softmmu
|
||||
- ./configure --enable-werror --target-list="tricore-softmmu unicore32-softmmu
|
||||
microblaze-softmmu mips-softmmu riscv32-softmmu s390x-softmmu sh4-softmmu
|
||||
sparc64-softmmu x86_64-softmmu xtensa-softmmu nios2-softmmu or1k-softmmu"
|
||||
- make -j2
|
||||
@@ -33,9 +24,7 @@ build-system2:
|
||||
|
||||
build-disabled:
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-werror --disable-rdma --disable-slirp --disable-curl
|
||||
- ./configure --enable-werror --disable-rdma --disable-slirp --disable-curl
|
||||
--disable-capstone --disable-live-block-migration --disable-glusterfs
|
||||
--disable-replication --disable-coroutine-pool --disable-smartcard
|
||||
--disable-guest-agent --disable-curses --disable-libxml2 --disable-tpm
|
||||
@@ -47,38 +36,32 @@ build-disabled:
|
||||
|
||||
build-tcg-disabled:
|
||||
script:
|
||||
- apt-get install -y -qq clang libgtk-3-dev libusb-dev
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --cc=clang --enable-werror --disable-tcg --audio-drv-list=""
|
||||
- apt-get install -y -qq clang libgtk-3-dev libbluetooth-dev libusb-dev
|
||||
- ./configure --cc=clang --enable-werror --disable-tcg --audio-drv-list=""
|
||||
- make -j2
|
||||
- make check-unit
|
||||
- make check-qapi-schema
|
||||
- cd tests/qemu-iotests/
|
||||
- ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048
|
||||
052 063 077 086 101 104 106 113 148 150 151 152 157 159 160 163
|
||||
170 171 183 184 192 194 197 208 215 221 222 226 227 236 253 277
|
||||
- ./check -qcow2 028 051 056 057 058 065 067 068 082 085 091 095 096 102 122
|
||||
124 132 139 142 144 145 151 152 155 157 165 194 196 197 200 202
|
||||
208 209 215 216 218 222 227 234 246 247 248 250 254 255 257 258
|
||||
260 261 262 263 264 270 272 273 277 279
|
||||
052 063 077 086 101 104 106 113 147 148 150 151 152 157 159 160
|
||||
163 170 171 183 184 192 194 197 205 208 215 221 222 226 227 236
|
||||
- ./check -qcow2 028 040 051 056 057 058 065 067 068 082 085 091 095 096 102
|
||||
122 124 127 129 132 139 142 144 145 147 151 152 155 157 165 194
|
||||
196 197 200 202 203 205 208 209 215 216 218 222 227 234 246 247
|
||||
248 250 254 255 256
|
||||
|
||||
build-user:
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-werror --disable-system --disable-guest-agent
|
||||
- ./configure --enable-werror --disable-system --disable-guest-agent
|
||||
--disable-capstone --disable-slirp --disable-fdt
|
||||
- make -j2
|
||||
- make run-tcg-tests-i386-linux-user run-tcg-tests-x86_64-linux-user
|
||||
|
||||
build-clang:
|
||||
script:
|
||||
- apt-get install -y -qq clang libsdl2-dev libattr1-dev libcap-ng-dev
|
||||
- apt-get install -y -qq clang libsdl2-dev libattr1-dev libcap-dev
|
||||
xfslibs-dev libiscsi-dev libnfs-dev libseccomp-dev gnutls-dev librbd-dev
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --cc=clang --cxx=clang++ --enable-werror
|
||||
- ./configure --cc=clang --cxx=clang++ --enable-werror
|
||||
--target-list="alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu
|
||||
ppc-softmmu s390x-softmmu x86_64-softmmu arm-linux-user"
|
||||
- make -j2
|
||||
@@ -87,18 +70,14 @@ build-clang:
|
||||
build-tci:
|
||||
script:
|
||||
- TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64"
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-tcg-interpreter
|
||||
- ./configure --enable-tcg-interpreter
|
||||
--target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)"
|
||||
- make -j2
|
||||
- make run-tcg-tests-x86_64-softmmu
|
||||
- make tests/qtest/boot-serial-test tests/qtest/cdrom-test tests/qtest/pxe-test
|
||||
- make tests/boot-serial-test tests/cdrom-test tests/pxe-test
|
||||
- for tg in $TARGETS ; do
|
||||
export QTEST_QEMU_BINARY="${tg}-softmmu/qemu-system-${tg}" ;
|
||||
./tests/qtest/boot-serial-test || exit 1 ;
|
||||
./tests/qtest/cdrom-test || exit 1 ;
|
||||
./tests/boot-serial-test || exit 1 ;
|
||||
./tests/cdrom-test || exit 1 ;
|
||||
done
|
||||
- QTEST_QEMU_BINARY="x86_64-softmmu/qemu-system-x86_64" ./tests/qtest/pxe-test
|
||||
- QTEST_QEMU_BINARY="s390x-softmmu/qemu-system-s390x"
|
||||
./tests/qtest/pxe-test -m slow
|
||||
- QTEST_QEMU_BINARY="x86_64-softmmu/qemu-system-x86_64" ./tests/pxe-test
|
||||
- QTEST_QEMU_BINARY="s390x-softmmu/qemu-system-s390x" ./tests/pxe-test -m slow
|
||||
@@ -10,6 +10,9 @@
|
||||
[submodule "roms/openbios"]
|
||||
path = roms/openbios
|
||||
url = https://git.qemu.org/git/openbios.git
|
||||
[submodule "roms/openhackware"]
|
||||
path = roms/openhackware
|
||||
url = https://git.qemu.org/git/openhackware.git
|
||||
[submodule "roms/qemu-palcode"]
|
||||
path = roms/qemu-palcode
|
||||
url = https://git.qemu.org/git/qemu-palcode.git
|
||||
|
||||
@@ -39,13 +39,11 @@ Julia Suvorova <jusual@mail.ru> Julia Suvorova via Qemu-devel <qemu-devel@nongnu
|
||||
Justin Terry (VM) <juterry@microsoft.com> Justin Terry (VM) via Qemu-devel <qemu-devel@nongnu.org>
|
||||
|
||||
# Next, replace old addresses by a more recent one.
|
||||
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <aleksandar.markovic@mips.com>
|
||||
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <aleksandar.markovic@imgtec.com>
|
||||
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <amarkovic@wavecomp.com>
|
||||
Aleksandar Markovic <amarkovic@wavecomp.com> <aleksandar.markovic@mips.com>
|
||||
Aleksandar Markovic <amarkovic@wavecomp.com> <aleksandar.markovic@imgtec.com>
|
||||
Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com> <arikalo@wavecomp.com>
|
||||
Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com>
|
||||
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
|
||||
Leif Lindholm <leif@nuviainc.com> <leif.lindholm@linaro.org>
|
||||
Paul Burton <pburton@wavecomp.com> <paul.burton@mips.com>
|
||||
Paul Burton <pburton@wavecomp.com> <paul.burton@imgtec.com>
|
||||
Paul Burton <pburton@wavecomp.com> <paul@archlinuxmips.org>
|
||||
@@ -153,8 +151,7 @@ Xiaoqiang Zhao <zxq_yx_007@163.com>
|
||||
Xinhua Cao <caoxinhua@huawei.com>
|
||||
Xiong Zhang <xiong.y.zhang@intel.com>
|
||||
Yin Yin <yin.yin@cs2c.com.cn>
|
||||
Yu-Chen Lin <npes87184@gmail.com>
|
||||
Yu-Chen Lin <npes87184@gmail.com> <yuchenlin@synology.com>
|
||||
yuchenlin <npes87184@gmail.com>
|
||||
YunQiang Su <syq@debian.org>
|
||||
YunQiang Su <ysu@wavecomp.com>
|
||||
Yuri Pudgorodskiy <yur@virtuozzo.com>
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# .readthedocs.yml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
||||
# We want all the document formats
|
||||
formats: all
|
||||
|
||||
# For consistency, we require that QEMU's Sphinx extensions
|
||||
# run with at least the same minimum version of Python that
|
||||
# we require for other Python in our codebase (our conf.py
|
||||
# enforces this, and some code needs it.)
|
||||
python:
|
||||
version: 3.5
|
||||
+1
-3
@@ -35,7 +35,5 @@ build:
|
||||
options: "-e HOME=/root"
|
||||
ci:
|
||||
- unset CC
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-docs ${QEMU_CONFIGURE_OPTS} --target-list=${TARGET_LIST}
|
||||
- ./configure ${QEMU_CONFIGURE_OPTS} --target-list=${TARGET_LIST}
|
||||
- make -j$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||
+78
-291
@@ -1,7 +1,6 @@
|
||||
# The current Travis default is a VM based 16.04 Xenial on GCE
|
||||
# Additional builds with specific requirements for a full VM need to
|
||||
# be added as additional matrix: entries later on
|
||||
os: linux
|
||||
dist: xenial
|
||||
language: c
|
||||
compiler:
|
||||
@@ -27,6 +26,7 @@ addons:
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-dev
|
||||
- libcap-ng-dev
|
||||
- libgcc-4.8-dev
|
||||
- libgnutls28-dev
|
||||
@@ -49,12 +49,16 @@ addons:
|
||||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
- libzstd-dev
|
||||
- sparse
|
||||
- uuid-dev
|
||||
- gcovr
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
homebrew:
|
||||
packages:
|
||||
- ccache
|
||||
- glib
|
||||
- pixman
|
||||
- gnu-sed
|
||||
update: true
|
||||
|
||||
|
||||
# The channel name "irc.oftc.net#qemu" is encrypted against qemu/qemu
|
||||
@@ -70,126 +74,94 @@ notifications:
|
||||
|
||||
env:
|
||||
global:
|
||||
- SRC_DIR=".."
|
||||
- BUILD_DIR="build"
|
||||
- SRC_DIR="."
|
||||
- BUILD_DIR="."
|
||||
- BASE_CONFIG="--disable-docs --disable-tools"
|
||||
- TEST_BUILD_CMD=""
|
||||
- TEST_CMD="make check V=1"
|
||||
# This is broadly a list of "mainline" softmmu targets which have support across the major distros
|
||||
- MAIN_SOFTMMU_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
|
||||
- CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime"
|
||||
- CCACHE_MAXSIZE=1G
|
||||
- G_MESSAGES_DEBUG=error
|
||||
|
||||
|
||||
git:
|
||||
# we want to do this ourselves
|
||||
submodules: false
|
||||
|
||||
# Common first phase for all steps
|
||||
before_install:
|
||||
- if command -v ccache ; then ccache --zero-stats ; fi
|
||||
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||
- echo "=== Using ${JOBS} simultaneous jobs ==="
|
||||
|
||||
# Configure step - may be overridden
|
||||
before_script:
|
||||
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then export PATH="/usr/local/opt/ccache/libexec:$PATH" ; fi
|
||||
- if command -v ccache ; then ccache --zero-stats ; fi
|
||||
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
|
||||
- ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
|
||||
|
||||
# Main build & test - rarely overridden - controlled by TEST_CMD
|
||||
script:
|
||||
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
|
||||
- |
|
||||
if [ "$BUILD_RC" -eq 0 ] && [ -n "$TEST_BUILD_CMD" ]; then
|
||||
${TEST_BUILD_CMD} || BUILD_RC=$?
|
||||
else
|
||||
$(exit $BUILD_RC);
|
||||
fi
|
||||
- |
|
||||
if [ "$BUILD_RC" -eq 0 ] ; then
|
||||
${TEST_CMD} ;
|
||||
else
|
||||
$(exit $BUILD_RC);
|
||||
fi
|
||||
- make -j3 && travis_retry ${TEST_CMD}
|
||||
after_script:
|
||||
- if command -v ccache ; then ccache --show-stats ; fi
|
||||
|
||||
|
||||
jobs:
|
||||
matrix:
|
||||
include:
|
||||
- name: "GCC static (user)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--disable-system --static"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
# we split the system builds as it takes a while to build them all
|
||||
- name: "GCC (main-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--disable-user --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
- name: "GCC (other-softmmu)"
|
||||
env:
|
||||
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
|
||||
- env:
|
||||
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
# Just build tools and run minimal unit and softfloat checks
|
||||
- name: "GCC check-softfloat (user)"
|
||||
env:
|
||||
- env:
|
||||
- BASE_CONFIG="--enable-tools"
|
||||
- CONFIG="--disable-user --disable-system"
|
||||
- TEST_CMD="make check-unit check-softfloat -j${JOBS}"
|
||||
- TEST_CMD="make check-unit check-softfloat -j3"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
# --enable-debug implies --enable-debug-tcg, also runs quite a bit slower
|
||||
- name: "GCC debug (main-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-debug --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug"
|
||||
|
||||
|
||||
# TCG debug can be run just on its own and is mostly agnostic to user/softmmu distinctions
|
||||
- name: "GCC debug (user)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-debug-tcg --disable-system"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
- name: "GCC some libs disabled (main-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-libusb --disable-replication --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
|
||||
|
||||
# Module builds are mostly of interest to major distros
|
||||
- name: "GCC modules (main-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-modules --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
# Alternate coroutines implementations are only really of interest to KVM users
|
||||
# However we can't test against KVM on Travis so we can only run unit tests
|
||||
- name: "check-unit coroutine=ucontext"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--with-coroutine=ucontext --disable-tcg"
|
||||
- TEST_CMD="make check-unit -j${JOBS} V=1"
|
||||
- TEST_CMD="make check-unit -j3 V=1"
|
||||
|
||||
|
||||
- name: "check-unit coroutine=sigaltstack"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--with-coroutine=sigaltstack --disable-tcg"
|
||||
- TEST_CMD="make check-unit -j${JOBS} V=1"
|
||||
- TEST_CMD="make check-unit -j3 V=1"
|
||||
|
||||
|
||||
# Check we can build docs and tools (out of tree)
|
||||
- name: "tools and docs (bionic)"
|
||||
dist: bionic
|
||||
env:
|
||||
- env:
|
||||
- BUILD_DIR="out-of-tree/build/dir" SRC_DIR="../../.."
|
||||
- BASE_CONFIG="--enable-tools --enable-docs"
|
||||
- CONFIG="--target-list=x86_64-softmmu,aarch64-linux-user"
|
||||
@@ -197,147 +169,118 @@ jobs:
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- python3-sphinx
|
||||
- python-sphinx
|
||||
- texinfo
|
||||
- perl
|
||||
|
||||
|
||||
# Test with Clang for compile portability (Travis uses clang-5.0)
|
||||
- name: "Clang (user)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--disable-system"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
|
||||
compiler: clang
|
||||
|
||||
|
||||
- name: "Clang (main-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--disable-user --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
|
||||
compiler: clang
|
||||
|
||||
|
||||
- env:
|
||||
- CONFIG="--target-list=${MAIN_SOFTMMU_TARGETS} "
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-sanitize"
|
||||
compiler: clang
|
||||
before_script:
|
||||
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
|
||||
- ${SRC_DIR}/configure ${CONFIG} --extra-cflags="-fsanitize=undefined -Werror" || { cat config.log && exit 1; }
|
||||
- ./configure ${CONFIG} --extra-cflags="-fsanitize=undefined -Werror" || { cat config.log && exit 1; }
|
||||
|
||||
|
||||
- name: "Clang (other-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
|
||||
compiler: clang
|
||||
|
||||
|
||||
# gprof/gcov are GCC features
|
||||
- name: "GCC gprof/gcov"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-gprof --enable-gcov --disable-pie --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
after_success:
|
||||
- ${SRC_DIR}/scripts/travis/coverage-summary.sh
|
||||
|
||||
|
||||
# We manually include builds which we disable "make check" for
|
||||
- name: "GCC without-default-devices (softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--without-default-devices --disable-user"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
# Check the TCG interpreter (TCI)
|
||||
- name: "GCC TCI"
|
||||
env:
|
||||
- CONFIG="--enable-debug-tcg --enable-tcg-interpreter --disable-kvm --disable-containers
|
||||
--target-list=alpha-softmmu,arm-softmmu,hppa-softmmu,m68k-softmmu,microblaze-softmmu,moxie-softmmu,ppc-softmmu,s390x-softmmu,x86_64-softmmu"
|
||||
- TEST_CMD="make check-qtest check-tcg V=1"
|
||||
# We manually include builds which we disable "make check" for
|
||||
- env:
|
||||
- CONFIG="--enable-debug --enable-tcg-interpreter"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
# We don't need to exercise every backend with every front-end
|
||||
- name: "GCC trace log,simple,syslog (user)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-trace-backends=log,simple,syslog --disable-system"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
- name: "GCC trace ftrace (x86_64-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-trace-backends=ftrace --target-list=x86_64-softmmu"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
- name: "GCC trace ust (x86_64-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-trace-backends=ust --target-list=x86_64-softmmu"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
# MacOSX builds - cirrus.yml also tests some MacOS builds including latest Xcode
|
||||
|
||||
- name: "OSX Xcode 10.3"
|
||||
env:
|
||||
- BASE_CONFIG="--disable-docs --enable-tools"
|
||||
- env:
|
||||
- CONFIG="--target-list=i386-softmmu,ppc-softmmu,ppc64-softmmu,m68k-softmmu,x86_64-softmmu"
|
||||
os: osx
|
||||
osx_image: xcode10.3
|
||||
compiler: clang
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- ccache
|
||||
- glib
|
||||
- pixman
|
||||
- gnu-sed
|
||||
- python
|
||||
update: true
|
||||
before_script:
|
||||
- brew link --overwrite python
|
||||
- export PATH="/usr/local/opt/ccache/libexec:$PATH"
|
||||
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
|
||||
- ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
|
||||
|
||||
|
||||
# Python builds
|
||||
- name: "GCC Python 3.5 (x86_64-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--target-list=x86_64-softmmu"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
language: python
|
||||
python: 3.5
|
||||
python:
|
||||
- "3.4"
|
||||
|
||||
|
||||
- name: "GCC Python 3.6 (x86_64-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--target-list=x86_64-softmmu"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
language: python
|
||||
python: 3.6
|
||||
python:
|
||||
- "3.6"
|
||||
|
||||
|
||||
# Acceptance (Functional) tests
|
||||
- name: "GCC check-acceptance"
|
||||
dist: bionic
|
||||
env:
|
||||
- CONFIG="--enable-tools --target-list=aarch64-softmmu,alpha-softmmu,arm-softmmu,m68k-softmmu,microblaze-softmmu,mips-softmmu,mips64el-softmmu,nios2-softmmu,or1k-softmmu,ppc-softmmu,ppc64-softmmu,s390x-softmmu,sparc-softmmu,x86_64-softmmu,xtensa-softmmu"
|
||||
- env:
|
||||
- CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu,mips-softmmu,mips64el-softmmu,aarch64-softmmu,arm-softmmu,s390x-softmmu,alpha-softmmu,ppc-softmmu,ppc64-softmmu,m68k-softmmu,sparc-softmmu"
|
||||
- TEST_CMD="make check-acceptance"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-acceptance"
|
||||
after_script:
|
||||
- python3 -c 'import json; r = json.load(open("tests/results/latest/results.json")); [print(t["logfile"]) for t in r["tests"] if t["status"] not in ("PASS", "SKIP")]' | xargs cat
|
||||
- du -chs $HOME/avocado/data/cache
|
||||
after_failure:
|
||||
- cat tests/results/latest/job.log
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- python3-pil
|
||||
- python3-pip
|
||||
- python3-numpy
|
||||
- python3-opencv
|
||||
- python3-venv
|
||||
- rpm2cpio
|
||||
- python3.5-venv
|
||||
- tesseract-ocr
|
||||
- tesseract-ocr-eng
|
||||
|
||||
|
||||
# Using newer GCC with sanitizers
|
||||
- name: "GCC9 with sanitizers (softmmu)"
|
||||
addons:
|
||||
- addons:
|
||||
apt:
|
||||
update: true
|
||||
sources:
|
||||
@@ -380,212 +323,56 @@ jobs:
|
||||
- CONFIG="--cc=gcc-9 --cxx=g++-9 --disable-pie --disable-linux-user"
|
||||
- TEST_CMD=""
|
||||
before_script:
|
||||
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
|
||||
- ${SRC_DIR}/configure ${CONFIG} --extra-cflags="-g3 -O0 -Wno-error=stringop-truncation -fsanitize=thread" --extra-ldflags="-fuse-ld=gold" || { cat config.log && exit 1; }
|
||||
- ./configure ${CONFIG} --extra-cflags="-g3 -O0 -Wno-error=stringop-truncation -fsanitize=thread -fuse-ld=gold" || { cat config.log && exit 1; }
|
||||
|
||||
|
||||
# Run check-tcg against linux-user
|
||||
- name: "GCC check-tcg (user)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--disable-system --enable-debug-tcg"
|
||||
- TEST_BUILD_CMD="make build-tcg"
|
||||
- TEST_CMD="make check-tcg"
|
||||
- TEST_CMD="make -j3 check-tcg V=1"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
# Run check-tcg against linux-user (with plugins)
|
||||
# we skip sparc64-linux-user until it has been fixed somewhat
|
||||
# we skip cris-linux-user as it doesn't use the common run loop
|
||||
- name: "GCC plugins check-tcg (user)"
|
||||
env:
|
||||
- CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user"
|
||||
- TEST_BUILD_CMD="make build-tcg"
|
||||
- TEST_CMD="make check-tcg"
|
||||
- env:
|
||||
- CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user"
|
||||
- TEST_CMD="make -j3 check-tcg V=1"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
# Run check-tcg against softmmu targets
|
||||
- name: "GCC check-tcg (some-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-debug-tcg --target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
|
||||
- TEST_BUILD_CMD="make build-tcg"
|
||||
- TEST_CMD="make check-tcg"
|
||||
- TEST_CMD="make -j3 check-tcg V=1"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
# Run check-tcg against softmmu targets (with plugins)
|
||||
- name: "GCC plugins check-tcg (some-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-plugins --enable-debug-tcg --target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
|
||||
- TEST_BUILD_CMD="make build-tcg"
|
||||
- TEST_CMD="make check-tcg"
|
||||
- TEST_CMD="make -j3 check-tcg V=1"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
- name: "[aarch64] GCC check-tcg"
|
||||
arch: arm64
|
||||
dist: xenial
|
||||
addons:
|
||||
apt_packages:
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-ng-dev
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
- libgtk-3-dev
|
||||
- libiscsi-dev
|
||||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- librados-dev
|
||||
- libsdl2-dev
|
||||
- libseccomp-dev
|
||||
- liburcu-dev
|
||||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
env:
|
||||
- TEST_CMD="make check check-tcg V=1"
|
||||
- CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
|
||||
- name: "[ppc64] GCC check-tcg"
|
||||
arch: ppc64le
|
||||
dist: xenial
|
||||
addons:
|
||||
apt_packages:
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-ng-dev
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
- libgtk-3-dev
|
||||
- libiscsi-dev
|
||||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- librados-dev
|
||||
- libsdl2-dev
|
||||
- libseccomp-dev
|
||||
- liburcu-dev
|
||||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
env:
|
||||
- TEST_CMD="make check check-tcg V=1"
|
||||
- CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},ppc64le-linux-user"
|
||||
|
||||
- name: "[s390x] GCC check-tcg"
|
||||
arch: s390x
|
||||
dist: bionic
|
||||
addons:
|
||||
apt_packages:
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-ng-dev
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
- libgtk-3-dev
|
||||
- libiscsi-dev
|
||||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- librados-dev
|
||||
- libsdl2-dev
|
||||
- libseccomp-dev
|
||||
- liburcu-dev
|
||||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
env:
|
||||
- TEST_CMD="make check check-tcg V=1"
|
||||
- CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user"
|
||||
script:
|
||||
- ( cd ${SRC_DIR} ; git submodule update --init roms/SLOF )
|
||||
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
|
||||
- |
|
||||
if [ "$BUILD_RC" -eq 0 ] ; then
|
||||
mv pc-bios/s390-ccw/*.img pc-bios/ ;
|
||||
${TEST_CMD} ;
|
||||
else
|
||||
$(exit $BUILD_RC);
|
||||
fi
|
||||
|
||||
- name: "[s390x] GCC check (KVM)"
|
||||
arch: s390x
|
||||
dist: bionic
|
||||
addons:
|
||||
apt_packages:
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-ng-dev
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
- libgtk-3-dev
|
||||
- libiscsi-dev
|
||||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- librados-dev
|
||||
- libsdl2-dev
|
||||
- libseccomp-dev
|
||||
- liburcu-dev
|
||||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
env:
|
||||
- TEST_CMD="make check-unit"
|
||||
- CONFIG="--disable-containers --disable-tcg --enable-kvm --disable-tools"
|
||||
script:
|
||||
- ( cd ${SRC_DIR} ; git submodule update --init roms/SLOF )
|
||||
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
|
||||
- |
|
||||
if [ "$BUILD_RC" -eq 0 ] ; then
|
||||
mv pc-bios/s390-ccw/*.img pc-bios/ ;
|
||||
${TEST_CMD} ;
|
||||
else
|
||||
$(exit $BUILD_RC);
|
||||
fi
|
||||
|
||||
# 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*)?$/
|
||||
- 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}"
|
||||
- TEST_CMD="make install -j3"
|
||||
- QEMU_VERSION="${TRAVIS_TAG:1}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
before_script:
|
||||
- command -v ccache && ccache --zero-stats
|
||||
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
|
||||
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 && exit 1; }
|
||||
- ./configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
|
||||
- make install
|
||||
@@ -25,11 +25,6 @@ config TPM
|
||||
|
||||
config VHOST_USER
|
||||
bool
|
||||
select VHOST
|
||||
|
||||
config VHOST_KERNEL
|
||||
bool
|
||||
select VHOST
|
||||
|
||||
config XEN
|
||||
bool
|
||||
|
||||
+75
-269
@@ -101,8 +101,7 @@ F: include/hw/watchdog/wdt_diag288.h
|
||||
F: pc-bios/s390-ccw/
|
||||
F: pc-bios/s390-ccw.img
|
||||
F: target/s390x/
|
||||
F: docs/system/target-s390x.rst
|
||||
F: docs/system/s390x/
|
||||
F: docs/vfio-ap.txt
|
||||
F: tests/migration/s390x/
|
||||
K: ^Subject:.*(?i)s390x?
|
||||
T: git https://github.com/cohuck/qemu.git s390-next
|
||||
@@ -156,7 +155,6 @@ F: include/hw/cpu/a*mpcore.h
|
||||
F: disas/arm.c
|
||||
F: disas/arm-a64.cc
|
||||
F: disas/libvixl/
|
||||
F: docs/system/target-arm.rst
|
||||
|
||||
ARM SMMU
|
||||
M: Eric Auger <eric.auger@redhat.com>
|
||||
@@ -180,8 +178,6 @@ S: Maintained
|
||||
F: target/hppa/
|
||||
F: hw/hppa/
|
||||
F: disas/hppa.c
|
||||
F: hw/net/*i82596*
|
||||
F: include/hw/net/lasi_82596.h
|
||||
|
||||
LM32 TCG CPUs
|
||||
M: Michael Walle <michael@walle.cc>
|
||||
@@ -210,14 +206,13 @@ F: hw/microblaze/
|
||||
F: disas/microblaze.c
|
||||
|
||||
MIPS TCG CPUs
|
||||
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
|
||||
R: Aurelien Jarno <aurelien@aurel32.net>
|
||||
M: Aurelien Jarno <aurelien@aurel32.net>
|
||||
M: Aleksandar Markovic <amarkovic@wavecomp.com>
|
||||
R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
|
||||
S: Maintained
|
||||
F: target/mips/
|
||||
F: default-configs/*mips*
|
||||
F: disas/*mips*
|
||||
F: docs/system/cpu-models-mips.rst.inc
|
||||
F: hw/intc/mips_gic.c
|
||||
F: hw/mips/
|
||||
F: hw/misc/mips_*
|
||||
@@ -226,8 +221,6 @@ 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/acceptance/linux_ssh_mips_malta.py
|
||||
F: tests/acceptance/machine_mips_malta.py
|
||||
F: tests/tcg/mips/
|
||||
K: ^Subject:.*(?i)mips
|
||||
|
||||
@@ -278,11 +271,6 @@ F: include/hw/riscv/
|
||||
F: linux-user/host/riscv32/
|
||||
F: linux-user/host/riscv64/
|
||||
|
||||
RENESAS RX CPUs
|
||||
M: Yoshinori Sato <ysato@users.sourceforge.jp>
|
||||
S: Maintained
|
||||
F: target/rx/
|
||||
|
||||
S390 TCG CPUs
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
@@ -328,7 +316,7 @@ F: tests/tcg/i386/
|
||||
F: tests/tcg/x86_64/
|
||||
F: hw/i386/
|
||||
F: disas/i386.c
|
||||
F: docs/system/cpu-models-x86.rst.inc
|
||||
F: docs/qemu-cpu-models.texi
|
||||
T: git https://github.com/ehabkost/qemu.git x86-next
|
||||
|
||||
Xtensa TCG CPUs
|
||||
@@ -374,8 +362,9 @@ S: Maintained
|
||||
F: target/arm/kvm.c
|
||||
|
||||
MIPS KVM CPUs
|
||||
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
|
||||
S: Odd Fixes
|
||||
M: James Hogan <jhogan@kernel.org>
|
||||
R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
|
||||
S: Maintained
|
||||
F: target/mips/kvm.c
|
||||
|
||||
PPC KVM CPUs
|
||||
@@ -412,21 +401,6 @@ S: Supported
|
||||
F: target/i386/kvm.c
|
||||
F: scripts/kvm/vmxcap
|
||||
|
||||
X86 HVF CPUs
|
||||
M: Roman Bolshakov <r.bolshakov@yadro.com>
|
||||
S: Maintained
|
||||
F: accel/stubs/hvf-stub.c
|
||||
F: target/i386/hvf/
|
||||
F: include/sysemu/hvf.h
|
||||
|
||||
WHPX CPUs
|
||||
M: Sunil Muthuswamy <sunilmut@microsoft.com>
|
||||
S: Supported
|
||||
F: target/i386/whpx-all.c
|
||||
F: target/i386/whp-dispatch.h
|
||||
F: accel/stubs/whpx-stub.c
|
||||
F: include/sysemu/whpx.h
|
||||
|
||||
Guest CPU Cores (Xen)
|
||||
---------------------
|
||||
X86 Xen CPUs
|
||||
@@ -440,28 +414,15 @@ F: hw/9pfs/xen-9p*
|
||||
F: hw/char/xen_console.c
|
||||
F: hw/display/xenfb.c
|
||||
F: hw/net/xen_nic.c
|
||||
F: hw/usb/xen-usb.c
|
||||
F: hw/block/xen*
|
||||
F: hw/block/dataplane/xen*
|
||||
F: hw/xen/
|
||||
F: hw/xenpv/
|
||||
F: hw/i386/xen/
|
||||
F: hw/pci-host/xen_igd_pt.c
|
||||
F: include/hw/block/dataplane/xen*
|
||||
F: include/hw/xen/
|
||||
F: include/sysemu/xen-mapcache.h
|
||||
|
||||
Guest CPU Cores (HAXM)
|
||||
---------------------
|
||||
X86 HAXM CPUs
|
||||
M: Wenchao Wang <wenchao.wang@intel.com>
|
||||
M: Colin Xu <colin.xu@intel.com>
|
||||
L: haxm-team@intel.com
|
||||
W: https://github.com/intel/haxm/issues
|
||||
S: Maintained
|
||||
F: include/sysemu/hax.h
|
||||
F: target/i386/hax-*
|
||||
|
||||
Hosts
|
||||
-----
|
||||
LINUX
|
||||
@@ -518,15 +479,6 @@ F: hw/*/allwinner*
|
||||
F: include/hw/*/allwinner*
|
||||
F: hw/arm/cubieboard.c
|
||||
|
||||
Allwinner-h3
|
||||
M: Niek Linnenbank <nieklinnenbank@gmail.com>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/*/allwinner-h3*
|
||||
F: include/hw/*/allwinner-h3*
|
||||
F: hw/arm/orangepi.c
|
||||
F: docs/system/orangepi.rst
|
||||
|
||||
ARM PrimeCell and CMSDK devices
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
@@ -579,7 +531,7 @@ 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: tests/qtest/test-arm-mptimer.c
|
||||
F: tests/test-arm-mptimer.c
|
||||
|
||||
Exynos
|
||||
M: Igor Mitsyanko <i.mitsyanko@gmail.com>
|
||||
@@ -606,14 +558,6 @@ F: include/hw/arm/digic.h
|
||||
F: hw/*/digic*
|
||||
F: include/hw/*/digic*
|
||||
|
||||
Goldfish RTC
|
||||
M: Anup Patel <anup.patel@wdc.com>
|
||||
M: Alistair Francis <Alistair.Francis@wdc.com>
|
||||
L: qemu-riscv@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/rtc/goldfish_rtc.c
|
||||
F: include/hw/rtc/goldfish_rtc.h
|
||||
|
||||
Gumstix
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
@@ -650,8 +594,6 @@ S: Maintained
|
||||
F: hw/arm/integratorcp.c
|
||||
F: hw/misc/arm_integrator_debug.c
|
||||
F: include/hw/misc/arm_integrator_debug.h
|
||||
F: tests/acceptance/machine_arm_integratorcp.py
|
||||
F: docs/system/arm/integratorcp.rst
|
||||
|
||||
MCIMX6UL EVK / i.MX6ul
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
@@ -710,7 +652,6 @@ M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/arm/musicpal.c
|
||||
F: docs/system/arm/musicpal.rst
|
||||
|
||||
nSeries
|
||||
M: Andrzej Zaborowski <balrogg@gmail.com>
|
||||
@@ -726,8 +667,6 @@ F: hw/rtc/twl92230.c
|
||||
F: include/hw/display/blizzard.h
|
||||
F: include/hw/input/tsc2xxx.h
|
||||
F: include/hw/misc/cbus.h
|
||||
F: tests/acceptance/machine_arm_n8x0.py
|
||||
F: docs/system/arm/nseries.rst
|
||||
|
||||
Palm
|
||||
M: Andrzej Zaborowski <balrogg@gmail.com>
|
||||
@@ -737,7 +676,6 @@ S: Odd Fixes
|
||||
F: hw/arm/palm.c
|
||||
F: hw/input/tsc210x.c
|
||||
F: include/hw/input/tsc2xxx.h
|
||||
F: docs/system/arm/palm.rst
|
||||
|
||||
Raspberry Pi
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
@@ -759,7 +697,6 @@ F: hw/arm/realview*
|
||||
F: hw/cpu/realview_mpcore.c
|
||||
F: hw/intc/realview_gic.c
|
||||
F: include/hw/intc/realview_gic.h
|
||||
F: docs/system/arm/realview.rst
|
||||
|
||||
PXA2XX
|
||||
M: Andrzej Zaborowski <balrogg@gmail.com>
|
||||
@@ -779,7 +716,6 @@ F: hw/misc/max111x.c
|
||||
F: include/hw/arm/pxa.h
|
||||
F: include/hw/arm/sharpsl.h
|
||||
F: include/hw/display/tc6393xb.h
|
||||
F: docs/system/arm/xscale.rst
|
||||
|
||||
SABRELITE / i.MX6
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
@@ -790,8 +726,6 @@ F: hw/arm/sabrelite.c
|
||||
F: hw/arm/fsl-imx6.c
|
||||
F: hw/misc/imx6_*.c
|
||||
F: hw/ssi/imx_spi.c
|
||||
F: hw/usb/imx-usb-phy.c
|
||||
F: include/hw/usb/imx-usb-phy.h
|
||||
F: include/hw/arm/fsl-imx6.h
|
||||
F: include/hw/misc/imx6_*.h
|
||||
F: include/hw/ssi/imx_spi.h
|
||||
@@ -799,7 +733,7 @@ F: include/hw/ssi/imx_spi.h
|
||||
SBSA-REF
|
||||
M: Radoslaw Biernacki <radoslaw.biernacki@linaro.org>
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
R: Leif Lindholm <leif@nuviainc.com>
|
||||
R: Leif Lindholm <leif.lindholm@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/sbsa-ref.c
|
||||
@@ -817,7 +751,6 @@ L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/*/stellaris*
|
||||
F: include/hw/input/gamepad.h
|
||||
F: docs/system/arm/stellaris.rst
|
||||
|
||||
Versatile Express
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
@@ -831,7 +764,6 @@ L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/*/versatile*
|
||||
F: hw/misc/arm_sysctl.c
|
||||
F: docs/system/arm/versatile.rst
|
||||
|
||||
Virt
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
@@ -873,7 +805,6 @@ F: hw/arm/virt-acpi-build.c
|
||||
STM32F205
|
||||
M: Alistair Francis <alistair@alistair23.me>
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/stm32f205_soc.c
|
||||
F: hw/misc/stm32f2xx_syscfg.c
|
||||
@@ -883,33 +814,15 @@ F: hw/adc/*
|
||||
F: hw/ssi/stm32f2xx_spi.c
|
||||
F: include/hw/*/stm32*.h
|
||||
|
||||
STM32F405
|
||||
M: Alistair Francis <alistair@alistair23.me>
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/stm32f405_soc.c
|
||||
F: hw/misc/stm32f4xx_syscfg.c
|
||||
F: hw/misc/stm32f4xx_exti.c
|
||||
|
||||
Netduino 2
|
||||
M: Alistair Francis <alistair@alistair23.me>
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/netduino2.c
|
||||
|
||||
Netduino Plus 2
|
||||
M: Alistair Francis <alistair@alistair23.me>
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/netduinoplus2.c
|
||||
|
||||
SmartFusion2
|
||||
M: Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/msf2-soc.c
|
||||
F: hw/misc/msf2-sysreg.c
|
||||
@@ -923,7 +836,6 @@ F: include/hw/ssi/mss-spi.h
|
||||
Emcraft M2S-FG484
|
||||
M: Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/msf2-som.c
|
||||
|
||||
@@ -950,7 +862,7 @@ F: hw/*/nrf51*.c
|
||||
F: hw/*/microbit*.c
|
||||
F: include/hw/*/nrf51*.h
|
||||
F: include/hw/*/microbit*.h
|
||||
F: tests/qtest/microbit-test.c
|
||||
F: tests/microbit-test.c
|
||||
|
||||
CRIS Machines
|
||||
-------------
|
||||
@@ -962,11 +874,10 @@ F: hw/*/etraxfs_*.c
|
||||
|
||||
HP-PARISC Machines
|
||||
------------------
|
||||
HP B160L
|
||||
Dino
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
R: Helge Deller <deller@gmx.de>
|
||||
S: Odd Fixes
|
||||
F: default-configs/hppa-softmmu.mak
|
||||
F: hw/hppa/
|
||||
F: pc-bios/hppa-firmware.img
|
||||
|
||||
@@ -1044,35 +955,29 @@ F: hw/display/jazz_led.c
|
||||
F: hw/dma/rc4030.c
|
||||
|
||||
Malta
|
||||
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
R: Aurelien Jarno <aurelien@aurel32.net>
|
||||
M: Aurelien Jarno <aurelien@aurel32.net>
|
||||
R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
|
||||
S: Maintained
|
||||
F: hw/isa/piix4.c
|
||||
F: hw/acpi/piix4.c
|
||||
F: hw/mips/mips_malta.c
|
||||
F: hw/mips/gt64xxx_pci.c
|
||||
F: include/hw/southbridge/piix.h
|
||||
F: tests/acceptance/linux_ssh_mips_malta.py
|
||||
F: tests/acceptance/machine_mips_malta.py
|
||||
|
||||
Mipssim
|
||||
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
|
||||
M: Aleksandar Markovic <amarkovic@wavecomp.com>
|
||||
R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
|
||||
S: Odd Fixes
|
||||
F: hw/mips/mips_mipssim.c
|
||||
F: hw/net/mipsnet.c
|
||||
|
||||
R4000
|
||||
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
|
||||
R: Aurelien Jarno <aurelien@aurel32.net>
|
||||
M: Aurelien Jarno <aurelien@aurel32.net>
|
||||
R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
|
||||
S: Obsolete
|
||||
S: Maintained
|
||||
F: hw/mips/mips_r4k.c
|
||||
|
||||
Fulong 2E
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
|
||||
M: Aleksandar Markovic <amarkovic@wavecomp.com>
|
||||
R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
|
||||
S: Odd Fixes
|
||||
F: hw/mips/mips_fulong2e.c
|
||||
F: hw/isa/vt82c686.c
|
||||
@@ -1176,6 +1081,7 @@ F: hw/dma/i82374.c
|
||||
F: hw/rtc/m48t59-isa.c
|
||||
F: include/hw/isa/pc87312.h
|
||||
F: include/hw/rtc/m48t59.h
|
||||
F: pc-bios/ppc_rom.bin
|
||||
F: tests/acceptance/ppc_prep_40p.py
|
||||
|
||||
sPAPR
|
||||
@@ -1189,10 +1095,10 @@ F: include/hw/*/xics*
|
||||
F: pc-bios/slof.bin
|
||||
F: docs/specs/ppc-spapr-hcalls.txt
|
||||
F: docs/specs/ppc-spapr-hotplug.txt
|
||||
F: tests/qtest/spapr*
|
||||
F: tests/qtest/libqos/*spapr*
|
||||
F: tests/qtest/rtas*
|
||||
F: tests/qtest/libqos/rtas*
|
||||
F: tests/spapr*
|
||||
F: tests/libqos/*spapr*
|
||||
F: tests/rtas*
|
||||
F: tests/libqos/rtas*
|
||||
|
||||
PowerNV (Non-Virtualized)
|
||||
M: Cédric Le Goater <clg@kaod.org>
|
||||
@@ -1204,7 +1110,7 @@ F: hw/intc/pnv*
|
||||
F: hw/intc/xics_pnv.c
|
||||
F: include/hw/ppc/pnv*
|
||||
F: pc-bios/skiboot.lid
|
||||
F: tests/qtest/pnv*
|
||||
F: tests/pnv*
|
||||
|
||||
virtex_ml507
|
||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
@@ -1309,7 +1215,7 @@ S: Supported
|
||||
F: hw/s390x/ipl.*
|
||||
F: pc-bios/s390-ccw/
|
||||
F: pc-bios/s390-ccw.img
|
||||
F: docs/devel/s390-dasd-ipl.rst
|
||||
F: docs/devel/s390-dasd-ipl.txt
|
||||
T: git https://github.com/borntraeger/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
@@ -1352,7 +1258,7 @@ F: hw/misc/sga.c
|
||||
F: hw/isa/apm.c
|
||||
F: include/hw/isa/apm.h
|
||||
F: tests/test-x86-cpuid.c
|
||||
F: tests/qtest/test-x86-cpuid-compat.c
|
||||
F: tests/test-x86-cpuid-compat.c
|
||||
|
||||
PC Chipset
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
@@ -1448,10 +1354,10 @@ F: hw/ide/
|
||||
F: hw/block/block.c
|
||||
F: hw/block/cdrom.c
|
||||
F: hw/block/hd-geometry.c
|
||||
F: tests/qtest/ide-test.c
|
||||
F: tests/qtest/ahci-test.c
|
||||
F: tests/qtest/cdrom-test.c
|
||||
F: tests/qtest/libqos/ahci*
|
||||
F: tests/ide-test.c
|
||||
F: tests/ahci-test.c
|
||||
F: tests/cdrom-test.c
|
||||
F: tests/libqos/ahci*
|
||||
T: git https://github.com/jnsnow/qemu.git ide
|
||||
|
||||
IPMI
|
||||
@@ -1460,7 +1366,7 @@ S: Maintained
|
||||
F: include/hw/ipmi/*
|
||||
F: hw/ipmi/*
|
||||
F: hw/smbios/smbios_type_38.c
|
||||
F: tests/qtest/ipmi*
|
||||
F: tests/ipmi*
|
||||
T: git https://github.com/cminyard/qemu.git master-ipmi-rebase
|
||||
|
||||
Floppy
|
||||
@@ -1469,12 +1375,11 @@ L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: hw/block/fdc.c
|
||||
F: include/hw/block/fdc.h
|
||||
F: tests/qtest/fdc-test.c
|
||||
F: tests/fdc-test.c
|
||||
T: git https://github.com/jnsnow/qemu.git ide
|
||||
|
||||
OMAP
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/*/omap*
|
||||
F: include/hw/arm/omap.h
|
||||
@@ -1508,8 +1413,8 @@ F: hw/acpi/*
|
||||
F: hw/smbios/*
|
||||
F: hw/i386/acpi-build.[hc]
|
||||
F: hw/arm/virt-acpi-build.c
|
||||
F: tests/qtest/bios-tables-test.c
|
||||
F: tests/qtest/acpi-utils.[hc]
|
||||
F: tests/bios-tables-test.c
|
||||
F: tests/acpi-utils.[hc]
|
||||
F: tests/data/acpi/
|
||||
|
||||
ppc4xx
|
||||
@@ -1532,7 +1437,7 @@ M: Jason Wang <jasowang@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: hw/net/
|
||||
F: include/hw/net/
|
||||
F: tests/qtest/virtio-net-test.c
|
||||
F: tests/virtio-net-test.c
|
||||
F: docs/virtio-net-failover.rst
|
||||
T: git https://github.com/jasowang/qemu.git net
|
||||
|
||||
@@ -1549,7 +1454,7 @@ R: Fam Zheng <fam@euphon.net>
|
||||
S: Supported
|
||||
F: include/hw/scsi/*
|
||||
F: hw/scsi/*
|
||||
F: tests/qtest/virtio-scsi-test.c
|
||||
F: tests/virtio-scsi-test.c
|
||||
T: git https://github.com/bonzini/qemu.git scsi-next
|
||||
|
||||
SSI
|
||||
@@ -1559,7 +1464,7 @@ F: hw/ssi/*
|
||||
F: hw/block/m25p80.c
|
||||
F: include/hw/ssi/ssi.h
|
||||
X: hw/ssi/xilinx_*
|
||||
F: tests/qtest/m25p80-test.c
|
||||
F: tests/m25p80-test.c
|
||||
|
||||
Xilinx SPI
|
||||
M: Alistair Francis <alistair@alistair23.me>
|
||||
@@ -1572,14 +1477,13 @@ S: Odd Fixes
|
||||
F: include/hw/sd/sd*
|
||||
F: hw/sd/core.c
|
||||
F: hw/sd/sd*
|
||||
F: hw/sd/ssi-sd.c
|
||||
F: tests/qtest/sd*
|
||||
F: tests/sd*
|
||||
|
||||
USB
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Maintained
|
||||
F: hw/usb/*
|
||||
F: tests/qtest/usb-*-test.c
|
||||
F: tests/usb-*-test.c
|
||||
F: docs/usb2.txt
|
||||
F: docs/usb-storage.txt
|
||||
F: include/hw/usb.h
|
||||
@@ -1620,7 +1524,7 @@ F: hw/s390x/ap-bridge.c
|
||||
F: include/hw/s390x/ap-device.h
|
||||
F: include/hw/s390x/ap-bridge.h
|
||||
F: hw/vfio/ap.c
|
||||
F: docs/system/s390x/vfio-ap.rst
|
||||
F: docs/vfio-ap.txt
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
vhost
|
||||
@@ -1641,25 +1545,15 @@ F: hw/virtio/Makefile.objs
|
||||
F: hw/virtio/trace-events
|
||||
F: net/vhost-user.c
|
||||
F: include/hw/virtio/
|
||||
|
||||
virtio-balloon
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
S: Maintained
|
||||
F: hw/virtio/virtio-balloon*.c
|
||||
F: include/hw/virtio/virtio-balloon.h
|
||||
F: balloon.c
|
||||
F: include/sysemu/balloon.h
|
||||
F: tests/virtio-balloon-test.c
|
||||
|
||||
virtio-9p
|
||||
M: Greg Kurz <groug@kaod.org>
|
||||
R: Christian Schoenebeck <qemu_oss@crudebyte.com>
|
||||
S: Odd Fixes
|
||||
F: hw/9pfs/
|
||||
X: hw/9pfs/xen-9p*
|
||||
F: fsdev/
|
||||
F: docs/interop/virtfs-proxy-helper.rst
|
||||
F: tests/qtest/virtio-9p-test.c
|
||||
F: tests/virtio-9p-test.c
|
||||
T: git https://github.com/gkurz/qemu.git 9p-next
|
||||
|
||||
virtio-blk
|
||||
@@ -1668,7 +1562,7 @@ L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: hw/block/virtio-blk.c
|
||||
F: hw/block/dataplane/*
|
||||
F: tests/qtest/virtio-blk-test.c
|
||||
F: tests/virtio-blk-test.c
|
||||
T: git https://github.com/stefanha/qemu.git block
|
||||
|
||||
virtio-ccw
|
||||
@@ -1681,15 +1575,6 @@ T: git https://github.com/cohuck/qemu.git s390-next
|
||||
T: git https://github.com/borntraeger/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
virtiofs
|
||||
M: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
S: Supported
|
||||
F: tools/virtiofsd/*
|
||||
F: hw/virtio/vhost-user-fs*
|
||||
F: include/hw/virtio/vhost-user-fs.h
|
||||
F: docs/interop/virtiofsd.rst
|
||||
|
||||
virtio-input
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Maintained
|
||||
@@ -1698,12 +1583,6 @@ F: hw/input/virtio-input*.c
|
||||
F: include/hw/virtio/virtio-input.h
|
||||
F: contrib/vhost-user-input/*
|
||||
|
||||
virtio-iommu
|
||||
M: Eric Auger <eric.auger@redhat.com>
|
||||
S: Maintained
|
||||
F: hw/virtio/virtio-iommu*.c
|
||||
F: include/hw/virtio/virtio-iommu.h
|
||||
|
||||
virtio-serial
|
||||
M: Laurent Vivier <lvivier@redhat.com>
|
||||
R: Amit Shah <amit@kernel.org>
|
||||
@@ -1711,7 +1590,8 @@ S: Supported
|
||||
F: hw/char/virtio-serial-bus.c
|
||||
F: hw/char/virtio-console.c
|
||||
F: include/hw/virtio/virtio-serial.h
|
||||
F: tests/qtest/virtio-serial-test.c
|
||||
F: tests/virtio-console-test.c
|
||||
F: tests/virtio-serial-test.c
|
||||
|
||||
virtio-rng
|
||||
M: Laurent Vivier <lvivier@redhat.com>
|
||||
@@ -1721,7 +1601,7 @@ F: hw/virtio/virtio-rng.c
|
||||
F: include/hw/virtio/virtio-rng.h
|
||||
F: include/sysemu/rng*.h
|
||||
F: backends/rng*.c
|
||||
F: tests/qtest/virtio-rng-test.c
|
||||
F: tests/virtio-rng-test.c
|
||||
|
||||
virtio-crypto
|
||||
M: Gonglei <arei.gonglei@huawei.com>
|
||||
@@ -1735,7 +1615,7 @@ M: Keith Busch <keith.busch@intel.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: hw/block/nvme*
|
||||
F: tests/qtest/nvme-test.c
|
||||
F: tests/nvme-test.c
|
||||
|
||||
megasas
|
||||
M: Hannes Reinecke <hare@suse.com>
|
||||
@@ -1743,7 +1623,7 @@ L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: hw/scsi/megasas.c
|
||||
F: hw/scsi/mfi.h
|
||||
F: tests/qtest/megasas-test.c
|
||||
F: tests/megasas-test.c
|
||||
|
||||
Network packet abstractions
|
||||
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
|
||||
@@ -1758,7 +1638,7 @@ M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
|
||||
S: Maintained
|
||||
F: hw/net/vmxnet*
|
||||
F: hw/scsi/vmw_pvscsi*
|
||||
F: tests/qtest/vmxnet3-test.c
|
||||
F: tests/vmxnet3-test.c
|
||||
|
||||
Rocker
|
||||
M: Jiri Pirko <jiri@resnulli.us>
|
||||
@@ -1806,7 +1686,7 @@ F: docs/generic-loader.txt
|
||||
Intel Hexadecimal Object File Loader
|
||||
M: Su Hang <suhang16@mails.ucas.ac.cn>
|
||||
S: Maintained
|
||||
F: tests/qtest/hexloader-test.c
|
||||
F: tests/hexloader-test.c
|
||||
F: tests/data/hex-loader/test.hex
|
||||
|
||||
CHRP NVRAM
|
||||
@@ -1814,7 +1694,7 @@ M: Thomas Huth <thuth@redhat.com>
|
||||
S: Maintained
|
||||
F: hw/nvram/chrp_nvram.c
|
||||
F: include/hw/nvram/chrp_nvram.h
|
||||
F: tests/qtest/prom-env-test.c
|
||||
F: tests/prom-env-test.c
|
||||
|
||||
VM Generation ID
|
||||
M: Ben Warren <ben@skyportsystems.com>
|
||||
@@ -1822,7 +1702,7 @@ S: Maintained
|
||||
F: hw/acpi/vmgenid.c
|
||||
F: include/hw/acpi/vmgenid.h
|
||||
F: docs/specs/vmgenid.txt
|
||||
F: tests/qtest/vmgenid-test.c
|
||||
F: tests/vmgenid-test.c
|
||||
F: stubs/vmgenid.c
|
||||
|
||||
Unimplemented device
|
||||
@@ -1853,18 +1733,6 @@ F: hw/display/virtio-gpu*
|
||||
F: hw/display/virtio-vga.*
|
||||
F: include/hw/virtio/virtio-gpu.h
|
||||
|
||||
vhost-user-blk
|
||||
M: Raphael Norwitz <raphael.norwitz@nutanix.com>
|
||||
S: Maintained
|
||||
F: contrib/vhost-user-blk/
|
||||
F: contrib/vhost-user-scsi/
|
||||
F: hw/block/vhost-user-blk.c
|
||||
F: hw/scsi/vhost-user-scsi.c
|
||||
F: hw/virtio/vhost-user-blk-pci.c
|
||||
F: hw/virtio/vhost-user-scsi-pci.c
|
||||
F: include/hw/virtio/vhost-user-blk.h
|
||||
F: include/hw/virtio/vhost-user-scsi.h
|
||||
|
||||
vhost-user-gpu
|
||||
M: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
@@ -1903,8 +1771,8 @@ F: hw/nvram/fw_cfg.c
|
||||
F: stubs/fw_cfg.c
|
||||
F: include/hw/nvram/fw_cfg.h
|
||||
F: include/standard-headers/linux/qemu_fw_cfg.h
|
||||
F: tests/qtest/libqos/fw_cfg.c
|
||||
F: tests/qtest/fw_cfg-test.c
|
||||
F: tests/libqos/fw_cfg.c
|
||||
F: tests/fw_cfg-test.c
|
||||
T: git https://github.com/philmd/qemu.git fw_cfg-next
|
||||
|
||||
XIVE
|
||||
@@ -1924,9 +1792,9 @@ S: Maintained
|
||||
F: audio/
|
||||
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/ac97-test.c
|
||||
F: tests/es1370-test.c
|
||||
F: tests/intel-hda-test.c
|
||||
|
||||
Block layer core
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
@@ -1938,7 +1806,6 @@ F: block/
|
||||
F: hw/block/
|
||||
F: include/block/
|
||||
F: qemu-img*
|
||||
F: docs/interop/qemu-img.rst
|
||||
F: qemu-io*
|
||||
F: tests/qemu-iotests/
|
||||
F: util/qemu-progress.c
|
||||
@@ -1953,8 +1820,6 @@ L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: util/async.c
|
||||
F: util/aio-*.c
|
||||
F: util/aio-*.h
|
||||
F: util/fdmon-*.c
|
||||
F: block/io.c
|
||||
F: migration/block*
|
||||
F: include/block/aio.h
|
||||
@@ -1990,7 +1855,6 @@ Block QAPI, monitor, command line
|
||||
M: Markus Armbruster <armbru@redhat.com>
|
||||
S: Supported
|
||||
F: blockdev.c
|
||||
F: blockdev-hmp-cmds.c
|
||||
F: block/qapi.c
|
||||
F: qapi/block*.json
|
||||
F: qapi/transaction.json
|
||||
@@ -2001,12 +1865,12 @@ M: John Snow <jsnow@redhat.com>
|
||||
R: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: util/hbitmap.c
|
||||
F: block/dirty-bitmap.c
|
||||
F: include/qemu/hbitmap.h
|
||||
F: include/block/dirty-bitmap.h
|
||||
F: block/dirty-bitmap.c
|
||||
F: block/qcow2-bitmap.c
|
||||
F: qcow2-bitmap.c
|
||||
F: migration/block-dirty-bitmap.c
|
||||
F: util/hbitmap.c
|
||||
F: tests/test-hbitmap.c
|
||||
F: docs/interop/bitmaps.rst
|
||||
T: git https://github.com/jnsnow/qemu.git bitmaps
|
||||
@@ -2038,11 +1902,6 @@ M: Markus Armbruster <armbru@redhat.com>
|
||||
S: Supported
|
||||
F: scripts/coverity-model.c
|
||||
|
||||
Coverity Scan integration
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
S: Maintained
|
||||
F: scripts/coverity-scan/
|
||||
|
||||
Device Tree
|
||||
M: Alistair Francis <alistair.francis@wdc.com>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
@@ -2071,11 +1930,6 @@ F: include/qemu/error-report.h
|
||||
F: qapi/error.json
|
||||
F: util/error.c
|
||||
F: util/qemu-error.c
|
||||
F: scripts/coccinelle/err-bad-newline.cocci
|
||||
F: scripts/coccinelle/error-use-after-free.cocci
|
||||
F: scripts/coccinelle/error_propagate_null.cocci
|
||||
F: scripts/coccinelle/remove_local_err.cocci
|
||||
F: scripts/coccinelle/use-error_fatal.cocci
|
||||
|
||||
GDB stub
|
||||
M: Alex Bennée <alex.bennee@linaro.org>
|
||||
@@ -2092,11 +1946,9 @@ F: ioport.c
|
||||
F: include/exec/memop.h
|
||||
F: include/exec/memory.h
|
||||
F: include/exec/ram_addr.h
|
||||
F: include/exec/ramblock.h
|
||||
F: memory.c
|
||||
F: include/exec/memory-internal.h
|
||||
F: exec.c
|
||||
F: scripts/coccinelle/memory-region-housekeeping.cocci
|
||||
|
||||
SPICE
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
@@ -2130,8 +1982,7 @@ F: include/qemu/main-loop.h
|
||||
F: include/sysemu/runstate.h
|
||||
F: util/main-loop.c
|
||||
F: util/qemu-timer.c
|
||||
F: softmmu/vl.c
|
||||
F: softmmu/main.c
|
||||
F: vl.c
|
||||
F: qapi/run-state.json
|
||||
|
||||
Human Monitor (HMP)
|
||||
@@ -2144,7 +1995,7 @@ F: monitor/hmp*
|
||||
F: hmp.h
|
||||
F: hmp-commands*.hx
|
||||
F: include/monitor/hmp-target.h
|
||||
F: tests/qtest/test-hmp.c
|
||||
F: tests/test-hmp.c
|
||||
F: include/qemu/qemu-print.h
|
||||
F: util/qemu-print.c
|
||||
|
||||
@@ -2187,11 +2038,6 @@ F: python/qemu/*py
|
||||
F: scripts/*.py
|
||||
F: tests/*.py
|
||||
|
||||
Benchmark util
|
||||
M: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||||
S: Maintained
|
||||
F: scripts/simplebench/
|
||||
|
||||
QAPI
|
||||
M: Markus Armbruster <armbru@redhat.com>
|
||||
M: Michael Roth <mdroth@linux.vnet.ibm.com>
|
||||
@@ -2275,8 +2121,8 @@ F: qapi/error.json
|
||||
F: docs/devel/*qmp-*
|
||||
F: docs/interop/*qmp-*
|
||||
F: scripts/qmp/
|
||||
F: tests/qtest/qmp-test.c
|
||||
F: tests/qtest/qmp-cmd-test.c
|
||||
F: tests/qmp-test.c
|
||||
F: tests/qmp-cmd-test.c
|
||||
T: git https://repo.or.cz/qemu/armbru.git qapi-next
|
||||
|
||||
qtest
|
||||
@@ -2286,15 +2132,9 @@ R: Paolo Bonzini <pbonzini@redhat.com>
|
||||
S: Maintained
|
||||
F: qtest.c
|
||||
F: accel/qtest.c
|
||||
F: tests/qtest/
|
||||
|
||||
Device Fuzzing
|
||||
M: Alexander Bulekov <alxndr@bu.edu>
|
||||
R: Paolo Bonzini <pbonzini@redhat.com>
|
||||
R: Bandan Das <bsd@redhat.com>
|
||||
R: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
S: Maintained
|
||||
F: tests/qtest/fuzz/
|
||||
F: tests/libqtest*
|
||||
F: tests/libqos/
|
||||
F: tests/*-test.c
|
||||
|
||||
Register API
|
||||
M: Alistair Francis <alistair@alistair23.me>
|
||||
@@ -2321,11 +2161,10 @@ M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
S: Maintained
|
||||
F: trace/
|
||||
F: trace-events
|
||||
F: docs/qemu-option-trace.rst.inc
|
||||
F: qemu-option-trace.texi
|
||||
F: scripts/tracetool.py
|
||||
F: scripts/tracetool/
|
||||
F: scripts/qemu-trace-stap*
|
||||
F: docs/interop/qemu-trace-stap.rst
|
||||
F: docs/devel/tracing.txt
|
||||
T: git https://github.com/stefanha/qemu.git tracing
|
||||
|
||||
@@ -2339,7 +2178,7 @@ F: include/hw/acpi/tpm.h
|
||||
F: include/sysemu/tpm*
|
||||
F: qapi/tpm.json
|
||||
F: backends/tpm.c
|
||||
F: tests/qtest/*tpm*
|
||||
F: tests/*tpm*
|
||||
T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
|
||||
|
||||
Checkpatch
|
||||
@@ -2350,26 +2189,14 @@ Migration
|
||||
M: Juan Quintela <quintela@redhat.com>
|
||||
M: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
S: Maintained
|
||||
F: hw/core/vmstate-if.c
|
||||
F: include/hw/vmstate-if.h
|
||||
F: include/migration/
|
||||
F: migration/
|
||||
F: scripts/vmstate-static-checker.py
|
||||
F: tests/vmstate-static-checker-data/
|
||||
F: tests/qtest/migration-test.c
|
||||
F: tests/migration-test.c
|
||||
F: docs/devel/migration.rst
|
||||
F: qapi/migration.json
|
||||
|
||||
D-Bus
|
||||
M: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
S: Maintained
|
||||
F: backends/dbus-vmstate.c
|
||||
F: tests/dbus-vmstate*
|
||||
F: util/dbus.c
|
||||
F: include/qemu/dbus.h
|
||||
F: docs/interop/dbus.rst
|
||||
F: docs/interop/dbus-vmstate.rst
|
||||
|
||||
Seccomp
|
||||
M: Eduardo Otubo <otubo@redhat.com>
|
||||
S: Supported
|
||||
@@ -2512,8 +2339,6 @@ F: roms/edk2
|
||||
F: roms/edk2-*
|
||||
F: tests/data/uefi-boot-images/
|
||||
F: tests/uefi-test-tools/
|
||||
F: .gitlab-ci-edk2.yml
|
||||
F: .gitlab-ci.d/edk2/
|
||||
|
||||
Usermode Emulation
|
||||
------------------
|
||||
@@ -2535,9 +2360,6 @@ S: Maintained
|
||||
F: linux-user/
|
||||
F: default-configs/*-linux-user.mak
|
||||
F: scripts/qemu-binfmt-conf.sh
|
||||
F: scripts/update-syscalltbl.sh
|
||||
F: scripts/update-mips-syscall-args.sh
|
||||
F: scripts/gensyscalls.sh
|
||||
|
||||
Tiny Code Generator (TCG)
|
||||
-------------------------
|
||||
@@ -2545,7 +2367,6 @@ Common TCG code
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
S: Maintained
|
||||
F: tcg/
|
||||
F: include/tcg/
|
||||
|
||||
TCG Plugins
|
||||
M: Alex Bennée <alex.bennee@linaro.org>
|
||||
@@ -2555,7 +2376,8 @@ F: plugins/
|
||||
F: tests/plugin
|
||||
|
||||
AArch64 TCG target
|
||||
M: Richard Henderson <richard.henderson@linaro.org>
|
||||
M: Claudio Fontana <claudio.fontana@huawei.com>
|
||||
M: Claudio Fontana <claudio.fontana@gmail.com>
|
||||
S: Maintained
|
||||
L: qemu-arm@nongnu.org
|
||||
F: tcg/aarch64/
|
||||
@@ -2576,8 +2398,7 @@ F: tcg/i386/
|
||||
F: disas/i386.c
|
||||
|
||||
MIPS TCG target
|
||||
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
|
||||
R: Aurelien Jarno <aurelien@aurel32.net>
|
||||
M: Aurelien Jarno <aurelien@aurel32.net>
|
||||
R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
|
||||
S: Maintained
|
||||
F: tcg/mips/
|
||||
@@ -2667,7 +2488,6 @@ F: include/block/nbd*
|
||||
F: qemu-nbd.*
|
||||
F: blockdev-nbd.c
|
||||
F: docs/interop/nbd.txt
|
||||
F: docs/interop/qemu-nbd.rst
|
||||
T: git https://repo.or.cz/qemu/ericb.git nbd
|
||||
|
||||
NFS
|
||||
@@ -2771,15 +2591,6 @@ F: block/file-posix.c
|
||||
F: block/file-win32.c
|
||||
F: block/win32-aio.c
|
||||
|
||||
Linux io_uring
|
||||
M: Aarushi Mehta <mehta.aaru20@gmail.com>
|
||||
M: Julia Suvorova <jusual@redhat.com>
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Maintained
|
||||
F: block/io_uring.c
|
||||
F: stubs/io_uring.c
|
||||
|
||||
qcow2
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
M: Max Reitz <mreitz@redhat.com>
|
||||
@@ -2829,7 +2640,7 @@ F: tests/test-replication.c
|
||||
F: docs/block-replication.txt
|
||||
|
||||
PVRDMA
|
||||
M: Yuval Shaia <yuval.shaia.ml@gmail.com>
|
||||
M: Yuval Shaia <yuval.shaia@oracle.com>
|
||||
M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
|
||||
S: Maintained
|
||||
F: hw/rdma/*
|
||||
@@ -2851,7 +2662,6 @@ M: Alex Bennée <alex.bennee@linaro.org>
|
||||
M: Fam Zheng <fam@euphon.net>
|
||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
S: Maintained
|
||||
F: .github/lockdown.yml
|
||||
F: .travis.yml
|
||||
F: scripts/travis/
|
||||
F: .shippable.yml
|
||||
@@ -2896,7 +2706,7 @@ F: contrib/gitdm/*
|
||||
|
||||
Incompatible changes
|
||||
R: libvir-list@redhat.com
|
||||
F: docs/system/deprecated.rst
|
||||
F: qemu-deprecated.texi
|
||||
|
||||
Build System
|
||||
------------
|
||||
@@ -2905,10 +2715,6 @@ M: Daniel P. Berrange <berrange@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: scripts/git-submodule.sh
|
||||
|
||||
UI translations
|
||||
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
|
||||
F: po/*.po
|
||||
|
||||
Sphinx documentation configuration and build machinery
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
S: Maintained
|
||||
|
||||
@@ -15,6 +15,9 @@ UNCHECKED_GOALS := %clean TAGS cscope ctags dist \
|
||||
help check-help print-% \
|
||||
docker docker-% vm-help vm-test vm-build-%
|
||||
|
||||
print-%:
|
||||
@echo '$*=$($*)'
|
||||
|
||||
# All following code might depend on configuration variables
|
||||
ifneq ($(wildcard config-host.mak),)
|
||||
# Put the all: rule here so that config-host.mak can contain dependencies.
|
||||
@@ -114,7 +117,6 @@ GENERATED_QAPI_FILES += qapi/qapi-builtin-visit.h qapi/qapi-builtin-visit.c
|
||||
GENERATED_QAPI_FILES += qapi/qapi-visit.h qapi/qapi-visit.c
|
||||
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-visit-%.h)
|
||||
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-visit-%.c)
|
||||
GENERATED_QAPI_FILES += qapi/qapi-init-commands.h qapi/qapi-init-commands.c
|
||||
GENERATED_QAPI_FILES += qapi/qapi-commands.h qapi/qapi-commands.c
|
||||
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-commands-%.h)
|
||||
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-commands-%.c)
|
||||
@@ -125,28 +127,7 @@ GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-events-%.c)
|
||||
GENERATED_QAPI_FILES += qapi/qapi-introspect.c qapi/qapi-introspect.h
|
||||
GENERATED_QAPI_FILES += qapi/qapi-doc.texi
|
||||
|
||||
# The following list considers only the storage daemon main module. All other
|
||||
# modules are currently shared with the main schema, so we don't actually
|
||||
# generate additional files.
|
||||
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES = storage-daemon/qapi/qapi-commands.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-commands.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-emit-events.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-emit-events.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-events.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-events.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-init-commands.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-init-commands.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-introspect.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-introspect.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-types.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-types.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-visit.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-visit.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-doc.texi
|
||||
|
||||
generated-files-y += $(GENERATED_QAPI_FILES)
|
||||
generated-files-y += $(GENERATED_STORAGE_DAEMON_QAPI_FILES)
|
||||
|
||||
generated-files-y += trace/generated-tcg-tracers.h
|
||||
|
||||
@@ -340,14 +321,13 @@ HELPERS-y =
|
||||
|
||||
HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) = qemu-bridge-helper$(EXESUF)
|
||||
|
||||
ifeq ($(CONFIG_LINUX)$(CONFIG_VIRGL)$(CONFIG_GBM)$(CONFIG_TOOLS),yyyy)
|
||||
ifdef CONFIG_LINUX
|
||||
ifdef CONFIG_VIRGL
|
||||
ifdef CONFIG_GBM
|
||||
HELPERS-y += vhost-user-gpu$(EXESUF)
|
||||
vhost-user-json-y += contrib/vhost-user-gpu/50-qemu-gpu.json
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy)
|
||||
HELPERS-y += virtiofsd$(EXESUF)
|
||||
vhost-user-json-y += tools/virtiofsd/50-qemu-virtiofsd.json
|
||||
endif
|
||||
endif
|
||||
|
||||
# Sphinx does not allow building manuals into the same directory as
|
||||
@@ -362,23 +342,16 @@ MANUAL_BUILDDIR := docs
|
||||
endif
|
||||
|
||||
ifdef BUILD_DOCS
|
||||
DOCS+=$(MANUAL_BUILDDIR)/system/qemu.1
|
||||
DOCS+=$(MANUAL_BUILDDIR)/tools/qemu-img.1
|
||||
DOCS+=$(MANUAL_BUILDDIR)/tools/qemu-nbd.8
|
||||
DOCS+=$(MANUAL_BUILDDIR)/interop/qemu-ga.8
|
||||
ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy)
|
||||
DOCS+=$(MANUAL_BUILDDIR)/tools/virtiofsd.1
|
||||
endif
|
||||
DOCS+=$(MANUAL_BUILDDIR)/system/qemu-block-drivers.7
|
||||
DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 $(MANUAL_BUILDDIR)/interop/qemu-ga.8
|
||||
DOCS+=docs/interop/qemu-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7
|
||||
DOCS+=docs/interop/qemu-ga-ref.html docs/interop/qemu-ga-ref.txt docs/interop/qemu-ga-ref.7
|
||||
DOCS+=$(MANUAL_BUILDDIR)/system/qemu-cpu-models.7
|
||||
DOCS+=$(MANUAL_BUILDDIR)/index.html
|
||||
DOCS+=docs/qemu-block-drivers.7
|
||||
DOCS+=docs/qemu-cpu-models.7
|
||||
ifdef CONFIG_VIRTFS
|
||||
DOCS+=$(MANUAL_BUILDDIR)/tools/virtfs-proxy-helper.1
|
||||
DOCS+=fsdev/virtfs-proxy-helper.1
|
||||
endif
|
||||
ifdef CONFIG_TRACE_SYSTEMTAP
|
||||
DOCS+=$(MANUAL_BUILDDIR)/tools/qemu-trace-stap.1
|
||||
DOCS+=scripts/qemu-trace-stap.1
|
||||
endif
|
||||
else
|
||||
DOCS=
|
||||
@@ -413,16 +386,15 @@ MINIKCONF_ARGS = \
|
||||
CONFIG_OPENGL=$(CONFIG_OPENGL) \
|
||||
CONFIG_X11=$(CONFIG_X11) \
|
||||
CONFIG_VHOST_USER=$(CONFIG_VHOST_USER) \
|
||||
CONFIG_VHOST_KERNEL=$(CONFIG_VHOST_KERNEL) \
|
||||
CONFIG_VIRTFS=$(CONFIG_VIRTFS) \
|
||||
CONFIG_LINUX=$(CONFIG_LINUX) \
|
||||
CONFIG_PVRDMA=$(CONFIG_PVRDMA)
|
||||
|
||||
MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/hw/Kconfig
|
||||
MINIKCONF_DEPS = $(MINIKCONF_INPUTS) $(wildcard $(SRC_PATH)/hw/*/Kconfig)
|
||||
MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/hw/Kconfig \
|
||||
$(wildcard $(SRC_PATH)/hw/*/Kconfig)
|
||||
MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py \
|
||||
|
||||
$(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(MINIKCONF_DEPS) $(BUILD_DIR)/config-host.mak
|
||||
$(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(MINIKCONF_INPUTS) $(BUILD_DIR)/config-host.mak
|
||||
$(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) > $@.tmp, "GEN", "$@.tmp")
|
||||
$(call quiet-command, if test -f $@; then \
|
||||
if cmp -s $@.old $@; then \
|
||||
@@ -458,7 +430,6 @@ dummy := $(call unnest-vars,, \
|
||||
elf2dmp-obj-y \
|
||||
ivshmem-client-obj-y \
|
||||
ivshmem-server-obj-y \
|
||||
virtiofsd-obj-y \
|
||||
rdmacm-mux-obj-y \
|
||||
libvhost-user-obj-y \
|
||||
vhost-user-scsi-obj-y \
|
||||
@@ -468,13 +439,16 @@ dummy := $(call unnest-vars,, \
|
||||
qga-vss-dll-obj-y \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
storage-daemon-obj-y \
|
||||
storage-daemon-obj-m \
|
||||
crypto-obj-y \
|
||||
crypto-user-obj-y \
|
||||
qom-obj-y \
|
||||
io-obj-y \
|
||||
common-obj-y \
|
||||
common-obj-m \
|
||||
ui-obj-y \
|
||||
ui-obj-m \
|
||||
audio-obj-y \
|
||||
audio-obj-m \
|
||||
trace-obj-y)
|
||||
|
||||
include $(SRC_PATH)/tests/Makefile.include
|
||||
@@ -497,12 +471,11 @@ config-host.h-timestamp: config-host.mak
|
||||
qemu-options.def: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
|
||||
|
||||
TARGET_DIRS_RULES := $(foreach t, all fuzz clean install, $(addsuffix /$(t), $(TARGET_DIRS)))
|
||||
TARGET_DIRS_RULES := $(foreach t, all clean install, $(addsuffix /$(t), $(TARGET_DIRS)))
|
||||
|
||||
SOFTMMU_ALL_RULES=$(filter %-softmmu/all, $(TARGET_DIRS_RULES))
|
||||
$(SOFTMMU_ALL_RULES): $(authz-obj-y)
|
||||
$(SOFTMMU_ALL_RULES): $(block-obj-y)
|
||||
$(SOFTMMU_ALL_RULES): $(storage-daemon-obj-y)
|
||||
$(SOFTMMU_ALL_RULES): $(chardev-obj-y)
|
||||
$(SOFTMMU_ALL_RULES): $(crypto-obj-y)
|
||||
$(SOFTMMU_ALL_RULES): $(io-obj-y)
|
||||
@@ -511,15 +484,6 @@ ifdef DECOMPRESS_EDK2_BLOBS
|
||||
$(SOFTMMU_ALL_RULES): $(edk2-decompressed)
|
||||
endif
|
||||
|
||||
SOFTMMU_FUZZ_RULES=$(filter %-softmmu/fuzz, $(TARGET_DIRS_RULES))
|
||||
$(SOFTMMU_FUZZ_RULES): $(authz-obj-y)
|
||||
$(SOFTMMU_FUZZ_RULES): $(block-obj-y)
|
||||
$(SOFTMMU_FUZZ_RULES): $(chardev-obj-y)
|
||||
$(SOFTMMU_FUZZ_RULES): $(crypto-obj-y)
|
||||
$(SOFTMMU_FUZZ_RULES): $(io-obj-y)
|
||||
$(SOFTMMU_FUZZ_RULES): config-all-devices.mak
|
||||
$(SOFTMMU_FUZZ_RULES): $(edk2-decompressed)
|
||||
|
||||
.PHONY: $(TARGET_DIRS_RULES)
|
||||
# The $(TARGET_DIRS_RULES) are of the form SUBDIR/GOAL, so that
|
||||
# $(dir $@) yields the sub-directory, and $(notdir $@) yields the sub-goal
|
||||
@@ -532,7 +496,7 @@ DTC_CPPFLAGS=-I$(BUILD_DIR)/dtc -I$(SRC_PATH)/dtc -I$(SRC_PATH)/dtc/libfdt
|
||||
|
||||
.PHONY: dtc/all
|
||||
dtc/all: .git-submodule-status dtc/libfdt dtc/tests
|
||||
$(call quiet-command,$(MAKE) $(DTC_MAKE_ARGS) CPPFLAGS="$(DTC_CPPFLAGS)" CFLAGS="$(DTC_CFLAGS)" LDFLAGS="$(QEMU_LDFLAGS)" ARFLAGS="$(ARFLAGS)" CC="$(CC)" AR="$(AR)" LD="$(LD)" $(SUBDIR_MAKEFLAGS) libfdt/libfdt.a,)
|
||||
$(call quiet-command,$(MAKE) $(DTC_MAKE_ARGS) CPPFLAGS="$(DTC_CPPFLAGS)" CFLAGS="$(DTC_CFLAGS)" LDFLAGS="$(LDFLAGS)" ARFLAGS="$(ARFLAGS)" CC="$(CC)" AR="$(AR)" LD="$(LD)" $(SUBDIR_MAKEFLAGS) libfdt/libfdt.a,)
|
||||
|
||||
dtc/%: .git-submodule-status
|
||||
@mkdir -p $@
|
||||
@@ -559,7 +523,7 @@ slirp/all: .git-submodule-status
|
||||
BUILD_DIR="$(BUILD_DIR)/slirp" \
|
||||
PKG_CONFIG="$(PKG_CONFIG)" \
|
||||
CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" \
|
||||
CFLAGS="$(QEMU_CFLAGS) $(CFLAGS)" LDFLAGS="$(QEMU_LDFLAGS)")
|
||||
CFLAGS="$(QEMU_CFLAGS) $(CFLAGS)" LDFLAGS="$(LDFLAGS)")
|
||||
|
||||
# Compatibility gunk to keep make working across the rename of targets
|
||||
# for recursion, to be removed some time after 4.1.
|
||||
@@ -568,9 +532,6 @@ subdir-capstone: capstone/all
|
||||
subdir-slirp: slirp/all
|
||||
|
||||
$(filter %/all, $(TARGET_DIRS_RULES)): libqemuutil.a $(common-obj-y) \
|
||||
$(qom-obj-y)
|
||||
|
||||
$(filter %/fuzz, $(TARGET_DIRS_RULES)): libqemuutil.a $(common-obj-y) \
|
||||
$(qom-obj-y) $(crypto-user-obj-$(CONFIG_USER_ONLY))
|
||||
|
||||
ROM_DIRS = $(addprefix pc-bios/, $(ROMS))
|
||||
@@ -582,7 +543,6 @@ $(ROM_DIRS_RULES):
|
||||
|
||||
.PHONY: recurse-all recurse-clean recurse-install
|
||||
recurse-all: $(addsuffix /all, $(TARGET_DIRS) $(ROM_DIRS))
|
||||
recurse-fuzz: $(addsuffix /fuzz, $(TARGET_DIRS) $(ROM_DIRS))
|
||||
recurse-clean: $(addsuffix /clean, $(TARGET_DIRS) $(ROM_DIRS))
|
||||
recurse-install: $(addsuffix /install, $(TARGET_DIRS))
|
||||
$(addsuffix /install, $(TARGET_DIRS)): all
|
||||
@@ -607,7 +567,6 @@ qemu-img.o: qemu-img-cmds.h
|
||||
qemu-img$(EXESUF): qemu-img.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
qemu-nbd$(EXESUF): qemu-nbd.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
qemu-io$(EXESUF): qemu-io.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
qemu-storage-daemon$(EXESUF): qemu-storage-daemon.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(chardev-obj-y) $(io-obj-y) $(qom-obj-y) $(storage-daemon-obj-y) $(COMMON_LDADDS)
|
||||
|
||||
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
|
||||
|
||||
@@ -616,6 +575,7 @@ qemu-keymap$(EXESUF): qemu-keymap.o ui/input-keymap.o $(COMMON_LDADDS)
|
||||
qemu-edid$(EXESUF): qemu-edid.o hw/display/edid-generate.o $(COMMON_LDADDS)
|
||||
|
||||
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS)
|
||||
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
|
||||
|
||||
scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(authz-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
ifdef CONFIG_MPATH
|
||||
@@ -650,7 +610,6 @@ $(SRC_PATH)/scripts/qapi-gen.py
|
||||
qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h \
|
||||
qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h \
|
||||
qga/qapi-generated/qga-qapi-commands.h qga/qapi-generated/qga-qapi-commands.c \
|
||||
qga/qapi-generated/qga-qapi-init-commands.h qga/qapi-generated/qga-qapi-init-commands.c \
|
||||
qga/qapi-generated/qga-qapi-doc.texi: \
|
||||
qga/qapi-generated/qapi-gen-timestamp ;
|
||||
qga/qapi-generated/qapi-gen-timestamp: $(SRC_PATH)/qga/qapi-schema.json $(qapi-py)
|
||||
@@ -669,18 +628,7 @@ qapi-gen-timestamp: $(qapi-modules) $(qapi-py)
|
||||
"GEN","$(@:%-timestamp=%)")
|
||||
@>$@
|
||||
|
||||
qapi-modules-storage-daemon = \
|
||||
$(SRC_PATH)/storage-daemon/qapi/qapi-schema.json \
|
||||
$(QAPI_MODULES_STORAGE_DAEMON:%=$(SRC_PATH)/qapi/%.json)
|
||||
|
||||
$(GENERATED_STORAGE_DAEMON_QAPI_FILES): storage-daemon/qapi/qapi-gen-timestamp ;
|
||||
storage-daemon/qapi/qapi-gen-timestamp: $(qapi-modules-storage-daemon) $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-gen.py \
|
||||
-o "storage-daemon/qapi" $<, \
|
||||
"GEN","$(@:%-timestamp=%)")
|
||||
@>$@
|
||||
|
||||
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qapi-commands.h qga-qapi-init-commands.h)
|
||||
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qapi-commands.h)
|
||||
$(qga-obj-y): $(QGALIB_GEN)
|
||||
|
||||
qemu-ga$(EXESUF): $(qga-obj-y) $(COMMON_LDADDS)
|
||||
@@ -726,12 +674,6 @@ rdmacm-mux$(EXESUF): LIBS += "-libumad"
|
||||
rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS)
|
||||
$(call LINK, $^)
|
||||
|
||||
# relies on Linux-specific syscalls
|
||||
ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy)
|
||||
virtiofsd$(EXESUF): $(virtiofsd-obj-y) libvhost-user.a $(COMMON_LDADDS)
|
||||
$(call LINK, $^)
|
||||
endif
|
||||
|
||||
vhost-user-gpu$(EXESUF): $(vhost-user-gpu-obj-y) $(libvhost-user-obj-y) libqemuutil.a libqemustub.a
|
||||
$(call LINK, $^)
|
||||
|
||||
@@ -778,7 +720,6 @@ clean: recurse-clean
|
||||
rm -f trace/generated-tracers-dtrace.h*
|
||||
rm -f $(foreach f,$(generated-files-y),$(f) $(f)-timestamp)
|
||||
rm -f qapi-gen-timestamp
|
||||
rm -f storage-daemon/qapi/qapi-gen-timestamp
|
||||
rm -rf qga/qapi-generated
|
||||
rm -f config-all-devices.mak
|
||||
|
||||
@@ -795,12 +736,16 @@ rm -f $(MANUAL_BUILDDIR)/$1/objects.inv $(MANUAL_BUILDDIR)/$1/searchindex.js $(M
|
||||
endef
|
||||
|
||||
distclean: clean
|
||||
rm -f config-host.mak config-host.h* $(DOCS)
|
||||
rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi qemu-monitor-info.texi
|
||||
rm -f tests/tcg/config-*.mak
|
||||
rm -f config-all-devices.mak config-all-disas.mak config.status
|
||||
rm -f $(SUBDIR_DEVICES_MAK)
|
||||
rm -f po/*.mo tests/qemu-iotests/common.env
|
||||
rm -f roms/seabios/config.mak roms/vgabios/config.mak
|
||||
rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.cps
|
||||
rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
|
||||
rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp
|
||||
rm -f qemu-doc.vr qemu-doc.txt
|
||||
rm -f qemu-plugins-ld.symbols qemu-plugins-ld64.symbols
|
||||
rm -f config.log
|
||||
rm -f linux-headers/asm
|
||||
@@ -810,13 +755,12 @@ distclean: clean
|
||||
rm -f docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt
|
||||
rm -f docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.pdf
|
||||
rm -f docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html
|
||||
rm -f docs/qemu-block-drivers.7
|
||||
rm -f docs/qemu-cpu-models.7
|
||||
rm -rf .doctrees
|
||||
$(call clean-manual,devel)
|
||||
$(call clean-manual,interop)
|
||||
$(call clean-manual,specs)
|
||||
$(call clean-manual,system)
|
||||
$(call clean-manual,tools)
|
||||
$(call clean-manual,user)
|
||||
for d in $(TARGET_DIRS); do \
|
||||
rm -rf $$d || exit 1 ; \
|
||||
done
|
||||
@@ -832,7 +776,7 @@ ifdef INSTALL_BLOBS
|
||||
BLOBS=bios.bin bios-256k.bin bios-microvm.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
|
||||
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-virtio.bin \
|
||||
vgabios-ramfb.bin vgabios-bochs-display.bin vgabios-ati.bin \
|
||||
openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \
|
||||
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \
|
||||
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
|
||||
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
|
||||
efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
|
||||
@@ -848,7 +792,7 @@ u-boot.e500 u-boot-sam460-20100605.bin \
|
||||
qemu_vga.ndrv \
|
||||
edk2-licenses.txt \
|
||||
hppa-firmware.img \
|
||||
opensbi-riscv32-sifive_u-fw_jump.bin opensbi-riscv32-virt-fw_jump.bin \
|
||||
opensbi-riscv32-virt-fw_jump.bin \
|
||||
opensbi-riscv64-sifive_u-fw_jump.bin opensbi-riscv64-virt-fw_jump.bin
|
||||
|
||||
|
||||
@@ -873,29 +817,27 @@ endef
|
||||
install-sphinxdocs: sphinxdocs
|
||||
$(call install-manual,interop)
|
||||
$(call install-manual,specs)
|
||||
$(call install-manual,system)
|
||||
$(call install-manual,tools)
|
||||
$(call install-manual,user)
|
||||
|
||||
install-doc: $(DOCS) install-sphinxdocs
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/index.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) qemu-doc.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) qemu-doc.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
ifdef CONFIG_POSIX
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/system/qemu.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man7"
|
||||
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.7 "$(DESTDIR)$(mandir)/man7"
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/system/qemu-block-drivers.7 "$(DESTDIR)$(mandir)/man7"
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/system/qemu-cpu-models.7 "$(DESTDIR)$(mandir)/man7"
|
||||
$(INSTALL_DATA) docs/qemu-block-drivers.7 "$(DESTDIR)$(mandir)/man7"
|
||||
$(INSTALL_DATA) docs/qemu-cpu-models.7 "$(DESTDIR)$(mandir)/man7"
|
||||
ifeq ($(CONFIG_TOOLS),y)
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/qemu-img.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) qemu-img.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
|
||||
$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
|
||||
endif
|
||||
ifdef CONFIG_TRACE_SYSTEMTAP
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/qemu-trace-stap.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) scripts/qemu-trace-stap.1 "$(DESTDIR)$(mandir)/man1"
|
||||
endif
|
||||
ifneq (,$(findstring qemu-ga,$(TOOLS)))
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/interop/qemu-ga.8 "$(DESTDIR)$(mandir)/man8"
|
||||
@@ -906,10 +848,7 @@ endif
|
||||
endif
|
||||
ifdef CONFIG_VIRTFS
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
|
||||
endif
|
||||
ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy)
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/virtiofsd.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
|
||||
endif
|
||||
|
||||
install-datadir:
|
||||
@@ -1064,32 +1003,16 @@ docs/version.texi: $(SRC_PATH)/VERSION config-host.mak
|
||||
# and handles "don't rebuild things unless necessary" itself.
|
||||
# The '.doctrees' files are cached information to speed this up.
|
||||
.PHONY: sphinxdocs
|
||||
sphinxdocs: $(MANUAL_BUILDDIR)/devel/index.html \
|
||||
$(MANUAL_BUILDDIR)/interop/index.html \
|
||||
$(MANUAL_BUILDDIR)/specs/index.html \
|
||||
$(MANUAL_BUILDDIR)/system/index.html \
|
||||
$(MANUAL_BUILDDIR)/tools/index.html \
|
||||
$(MANUAL_BUILDDIR)/user/index.html
|
||||
sphinxdocs: $(MANUAL_BUILDDIR)/devel/index.html $(MANUAL_BUILDDIR)/interop/index.html $(MANUAL_BUILDDIR)/specs/index.html
|
||||
|
||||
# Canned command to build a single manual
|
||||
# Arguments: $1 = manual name, $2 = Sphinx builder ('html' or 'man')
|
||||
# Note the use of different doctree for each (manual, builder) tuple;
|
||||
# this works around Sphinx not handling parallel invocation on
|
||||
# a single doctree: https://github.com/sphinx-doc/sphinx/issues/2946
|
||||
build-manual = $(call quiet-command,CONFDIR="$(qemu_confdir)" $(SPHINX_BUILD) $(if $(V),,-q) $(SPHINX_WERROR) -b $2 -D version=$(VERSION) -D release="$(FULL_VERSION)" -d .doctrees/$1-$2 $(SRC_PATH)/docs/$1 $(MANUAL_BUILDDIR)/$1 ,"SPHINX","$(MANUAL_BUILDDIR)/$1")
|
||||
build-manual = $(call quiet-command,CONFDIR="$(qemu_confdir)" sphinx-build $(if $(V),,-q) -W -n -b $2 -D version=$(VERSION) -D release="$(FULL_VERSION)" -d .doctrees/$1-$2 $(SRC_PATH)/docs/$1 $(MANUAL_BUILDDIR)/$1 ,"SPHINX","$(MANUAL_BUILDDIR)/$1")
|
||||
# We assume all RST files in the manual's directory are used in it
|
||||
manual-deps = $(wildcard $(SRC_PATH)/docs/$1/*.rst $(SRC_PATH)/docs/$1/*/*.rst) \
|
||||
$(SRC_PATH)/docs/defs.rst.inc \
|
||||
$(SRC_PATH)/docs/$1/conf.py $(SRC_PATH)/docs/conf.py \
|
||||
$(SRC_PATH)/docs/sphinx/*.py
|
||||
# Macro to write out the rule and dependencies for building manpages
|
||||
# Usage: $(call define-manpage-rule,manualname,manpage1 manpage2...[,extradeps])
|
||||
# 'extradeps' is optional, and specifies extra files (eg .hx files) that
|
||||
# the manual page depends on.
|
||||
define define-manpage-rule
|
||||
$(call atomic,$(foreach manpage,$2,$(MANUAL_BUILDDIR)/$1/$(manpage)),$(call manual-deps,$1) $3)
|
||||
$(call build-manual,$1,man)
|
||||
endef
|
||||
manual-deps = $(wildcard $(SRC_PATH)/docs/$1/*.rst) $(SRC_PATH)/docs/$1/conf.py $(SRC_PATH)/docs/conf.py
|
||||
|
||||
$(MANUAL_BUILDDIR)/devel/index.html: $(call manual-deps,devel)
|
||||
$(call build-manual,devel,html)
|
||||
@@ -1100,28 +1023,20 @@ $(MANUAL_BUILDDIR)/interop/index.html: $(call manual-deps,interop)
|
||||
$(MANUAL_BUILDDIR)/specs/index.html: $(call manual-deps,specs)
|
||||
$(call build-manual,specs,html)
|
||||
|
||||
$(MANUAL_BUILDDIR)/system/index.html: $(call manual-deps,system) $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/qemu-options.hx
|
||||
$(call build-manual,system,html)
|
||||
$(MANUAL_BUILDDIR)/interop/qemu-ga.8: $(call manual-deps,interop)
|
||||
$(call build-manual,interop,man)
|
||||
|
||||
$(MANUAL_BUILDDIR)/tools/index.html: $(call manual-deps,tools) $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/docs/qemu-option-trace.rst.inc
|
||||
$(call build-manual,tools,html)
|
||||
qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||
|
||||
$(MANUAL_BUILDDIR)/user/index.html: $(call manual-deps,user)
|
||||
$(call build-manual,user,html)
|
||||
qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||
|
||||
$(call define-manpage-rule,interop,qemu-ga.8)
|
||||
qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||
|
||||
$(call define-manpage-rule,system,qemu.1 qemu-block-drivers.7 qemu-cpu-models.7)
|
||||
|
||||
$(call define-manpage-rule,tools,\
|
||||
qemu-img.1 qemu-nbd.8 qemu-trace-stap.1\
|
||||
virtiofsd.1 virtfs-proxy-helper.1,\
|
||||
$(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/docs/qemu-option-trace.rst.inc)
|
||||
|
||||
$(MANUAL_BUILDDIR)/index.html: $(SRC_PATH)/docs/index.html.in qemu-version.h
|
||||
@mkdir -p "$(MANUAL_BUILDDIR)"
|
||||
$(call quiet-command, sed "s|@@VERSION@@|${VERSION}|g" $< >$@, \
|
||||
"GEN","$@")
|
||||
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||
|
||||
docs/interop/qemu-qmp-qapi.texi: qapi/qapi-doc.texi
|
||||
@cp -p $< $@
|
||||
@@ -1129,10 +1044,26 @@ docs/interop/qemu-qmp-qapi.texi: qapi/qapi-doc.texi
|
||||
docs/interop/qemu-ga-qapi.texi: qga/qapi-generated/qga-qapi-doc.texi
|
||||
@cp -p $< $@
|
||||
|
||||
html: docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html sphinxdocs
|
||||
info: docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-ref.info
|
||||
pdf: docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.pdf
|
||||
txt: docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt
|
||||
qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
|
||||
qemu.1: qemu-option-trace.texi
|
||||
qemu-img.1: qemu-img.texi qemu-option-trace.texi qemu-img-cmds.texi
|
||||
fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
|
||||
qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi
|
||||
docs/qemu-block-drivers.7: docs/qemu-block-drivers.texi
|
||||
docs/qemu-cpu-models.7: docs/qemu-cpu-models.texi
|
||||
scripts/qemu-trace-stap.1: scripts/qemu-trace-stap.texi
|
||||
|
||||
html: qemu-doc.html docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html sphinxdocs
|
||||
info: qemu-doc.info docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-ref.info
|
||||
pdf: qemu-doc.pdf docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.pdf
|
||||
txt: qemu-doc.txt docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt
|
||||
|
||||
qemu-doc.html qemu-doc.info qemu-doc.pdf qemu-doc.txt: \
|
||||
qemu-img.texi qemu-nbd.texi qemu-options.texi \
|
||||
qemu-tech.texi qemu-option-trace.texi \
|
||||
qemu-deprecated.texi qemu-monitor.texi qemu-img-cmds.texi \
|
||||
qemu-monitor-info.texi docs/qemu-block-drivers.texi \
|
||||
docs/qemu-cpu-models.texi docs/security.texi
|
||||
|
||||
docs/interop/qemu-ga-ref.dvi docs/interop/qemu-ga-ref.html \
|
||||
docs/interop/qemu-ga-ref.info docs/interop/qemu-ga-ref.pdf \
|
||||
@@ -1235,57 +1166,50 @@ endif
|
||||
include $(SRC_PATH)/tests/docker/Makefile.include
|
||||
include $(SRC_PATH)/tests/vm/Makefile.include
|
||||
|
||||
print-help-run = printf " %-30s - %s\\n" "$1" "$2"
|
||||
print-help = $(quiet-@)$(call print-help-run,$1,$2)
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo 'Generic targets:'
|
||||
$(call print-help,all,Build all)
|
||||
@echo ' all - Build all'
|
||||
ifdef CONFIG_MODULES
|
||||
$(call print-help,modules,Build all modules)
|
||||
@echo ' modules - Build all modules'
|
||||
endif
|
||||
$(call print-help,dir/file.o,Build specified target only)
|
||||
$(call print-help,install,Install QEMU, documentation and tools)
|
||||
$(call print-help,ctags/TAGS,Generate tags file for editors)
|
||||
$(call print-help,cscope,Generate cscope index)
|
||||
@echo ' dir/file.o - Build specified target only'
|
||||
@echo ' install - Install QEMU, documentation and tools'
|
||||
@echo ' ctags/TAGS - Generate tags file for editors'
|
||||
@echo ' cscope - Generate cscope index'
|
||||
@echo ''
|
||||
@$(if $(TARGET_DIRS), \
|
||||
echo 'Architecture specific targets:'; \
|
||||
$(foreach t, $(TARGET_DIRS), \
|
||||
$(call print-help-run,$(t)/all,Build for $(t));) \
|
||||
echo '')
|
||||
@$(if $(TOOLS), \
|
||||
echo 'Tools targets:'; \
|
||||
$(foreach t, $(TOOLS), \
|
||||
$(call print-help-run,$(t),Build $(shell basename $(t)) tool);) \
|
||||
printf " %-30s - Build for %s\\n" $(t)/all $(t);) \
|
||||
echo '')
|
||||
@echo 'Cleaning targets:'
|
||||
$(call print-help,clean,Remove most generated files but keep the config)
|
||||
@echo ' clean - Remove most generated files but keep the config'
|
||||
ifdef CONFIG_GCOV
|
||||
$(call print-help,clean-coverage,Remove coverage files)
|
||||
@echo ' clean-coverage - Remove coverage files'
|
||||
endif
|
||||
$(call print-help,distclean,Remove all generated files)
|
||||
$(call print-help,dist,Build a distributable tarball)
|
||||
@echo ' distclean - Remove all generated files'
|
||||
@echo ' dist - Build a distributable tarball'
|
||||
@echo ''
|
||||
@echo 'Test targets:'
|
||||
$(call print-help,check,Run all tests (check-help for details))
|
||||
$(call print-help,docker,Help about targets running tests inside containers)
|
||||
$(call print-help,vm-help,Help about targets running tests inside VM)
|
||||
@echo ' check - Run all tests (check-help for details)'
|
||||
@echo ' docker - Help about targets running tests inside containers'
|
||||
@echo ' vm-help - Help about targets running tests inside VM'
|
||||
@echo ''
|
||||
@echo 'Documentation targets:'
|
||||
$(call print-help,html info pdf txt,Build documentation in specified format)
|
||||
@echo ' html info pdf txt'
|
||||
@echo ' - Build documentation in specified format'
|
||||
ifdef CONFIG_GCOV
|
||||
$(call print-help,coverage-report,Create code coverage report)
|
||||
@echo ' coverage-report - Create code coverage report'
|
||||
endif
|
||||
@echo ''
|
||||
ifdef CONFIG_WIN32
|
||||
@echo 'Windows targets:'
|
||||
$(call print-help,installer,Build NSIS-based installer for QEMU)
|
||||
@echo ' installer - Build NSIS-based installer for QEMU'
|
||||
ifdef QEMU_GA_MSI_ENABLED
|
||||
$(call print-help,msi,Build MSI-based installer for qemu-ga)
|
||||
@echo ' msi - Build MSI-based installer for qemu-ga'
|
||||
endif
|
||||
@echo ''
|
||||
endif
|
||||
$(call print-help,$(MAKE) [targets],(quiet build, default))
|
||||
$(call print-help,$(MAKE) V=1 [targets],(verbose build))
|
||||
@echo ' $(MAKE) [targets] (quiet build, default)'
|
||||
@echo ' $(MAKE) V=1 [targets] (verbose build)'
|
||||
+30
-27
@@ -1,18 +1,18 @@
|
||||
#######################################################################
|
||||
# Common libraries for tools and emulators
|
||||
stub-obj-y = stubs/
|
||||
util-obj-y = crypto/ util/ qobject/ qapi/
|
||||
qom-obj-y = qom/
|
||||
|
||||
#######################################################################
|
||||
# code used by both qemu system emulation and qemu-img
|
||||
|
||||
ifeq ($(call lor,$(CONFIG_SOFTMMU),$(CONFIG_TOOLS)),y)
|
||||
stub-obj-y = stubs/ util/ crypto/
|
||||
util-obj-y = util/ qobject/ qapi/
|
||||
|
||||
chardev-obj-y = chardev/
|
||||
|
||||
#######################################################################
|
||||
# authz-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
authz-obj-y = authz/
|
||||
|
||||
#######################################################################
|
||||
# block-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
block-obj-y = nbd/
|
||||
block-obj-y += block.o blockjob.o job.o
|
||||
block-obj-y += block/ scsi/
|
||||
@@ -21,20 +21,21 @@ block-obj-$(CONFIG_REPLICATION) += replication.o
|
||||
|
||||
block-obj-m = block/
|
||||
|
||||
#######################################################################
|
||||
# crypto-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
crypto-obj-y = crypto/
|
||||
|
||||
io-obj-y = io/
|
||||
|
||||
endif # CONFIG_SOFTMMU or CONFIG_TOOLS
|
||||
crypto-user-obj-y = crypto/
|
||||
|
||||
#######################################################################
|
||||
# storage-daemon-obj-y is code used by qemu-storage-daemon (these objects are
|
||||
# used for system emulation, too, but specified separately there)
|
||||
# qom-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
storage-daemon-obj-y = block/ monitor/ qapi/ qom/ storage-daemon/
|
||||
storage-daemon-obj-y += blockdev.o blockdev-nbd.o iothread.o job-qmp.o
|
||||
storage-daemon-obj-$(CONFIG_WIN32) += os-win32.o
|
||||
storage-daemon-obj-$(CONFIG_POSIX) += os-posix.o
|
||||
qom-obj-y = qom/
|
||||
|
||||
#######################################################################
|
||||
# io-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
io-obj-y = io/
|
||||
|
||||
######################################################################
|
||||
# Target independent part of system emulation. The long term path is to
|
||||
@@ -48,13 +49,12 @@ common-obj-y += dump/
|
||||
common-obj-y += job-qmp.o
|
||||
common-obj-y += monitor/
|
||||
common-obj-y += net/
|
||||
common-obj-y += qdev-monitor.o
|
||||
common-obj-y += qdev-monitor.o device-hotplug.o
|
||||
common-obj-$(CONFIG_WIN32) += os-win32.o
|
||||
common-obj-$(CONFIG_POSIX) += os-posix.o
|
||||
|
||||
common-obj-$(CONFIG_LINUX) += fsdev/
|
||||
|
||||
common-obj-y += accel/
|
||||
common-obj-y += migration/
|
||||
|
||||
common-obj-y += audio/
|
||||
@@ -65,8 +65,12 @@ common-obj-y += replay/
|
||||
|
||||
common-obj-y += ui/
|
||||
common-obj-m += ui/
|
||||
common-obj-y += bt-host.o bt-vhci.o
|
||||
bt-host.o-cflags := $(BLUEZ_CFLAGS)
|
||||
|
||||
common-obj-y += dma-helpers.o
|
||||
common-obj-y += vl.o
|
||||
vl.o-cflags := $(GPROF_CFLAGS) $(SDL_CFLAGS)
|
||||
common-obj-$(CONFIG_TPM) += tpm.o
|
||||
|
||||
common-obj-y += backends/
|
||||
@@ -78,9 +82,11 @@ qemu-seccomp.o-libs := $(SECCOMP_LIBS)
|
||||
|
||||
common-obj-$(CONFIG_FDT) += device_tree.o
|
||||
|
||||
common-obj-y += qapi/
|
||||
######################################################################
|
||||
# qapi
|
||||
|
||||
endif # CONFIG_SOFTMMU
|
||||
common-obj-y += qapi/
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
# Target-independent parts used in system and user emulation
|
||||
@@ -119,13 +125,11 @@ vhost-user-blk-obj-y = contrib/vhost-user-blk/
|
||||
rdmacm-mux-obj-y = contrib/rdmacm-mux/
|
||||
vhost-user-input-obj-y = contrib/vhost-user-input/
|
||||
vhost-user-gpu-obj-y = contrib/vhost-user-gpu/
|
||||
virtiofsd-obj-y = tools/virtiofsd/
|
||||
|
||||
######################################################################
|
||||
trace-events-subdirs =
|
||||
trace-events-subdirs += accel/kvm
|
||||
trace-events-subdirs += accel/tcg
|
||||
trace-events-subdirs += backends
|
||||
trace-events-subdirs += crypto
|
||||
trace-events-subdirs += monitor
|
||||
ifeq ($(CONFIG_USER_ONLY),y)
|
||||
@@ -139,8 +143,8 @@ trace-events-subdirs += nbd
|
||||
trace-events-subdirs += scsi
|
||||
endif
|
||||
ifeq ($(CONFIG_SOFTMMU),y)
|
||||
trace-events-subdirs += audio
|
||||
trace-events-subdirs += chardev
|
||||
trace-events-subdirs += audio
|
||||
trace-events-subdirs += hw/9pfs
|
||||
trace-events-subdirs += hw/acpi
|
||||
trace-events-subdirs += hw/alpha
|
||||
@@ -175,7 +179,6 @@ trace-events-subdirs += hw/scsi
|
||||
trace-events-subdirs += hw/sd
|
||||
trace-events-subdirs += hw/sparc
|
||||
trace-events-subdirs += hw/sparc64
|
||||
trace-events-subdirs += hw/ssi
|
||||
trace-events-subdirs += hw/timer
|
||||
trace-events-subdirs += hw/tpm
|
||||
trace-events-subdirs += hw/usb
|
||||
@@ -189,7 +192,6 @@ trace-events-subdirs += migration
|
||||
trace-events-subdirs += net
|
||||
trace-events-subdirs += ui
|
||||
endif
|
||||
trace-events-subdirs += hw/core
|
||||
trace-events-subdirs += hw/display
|
||||
trace-events-subdirs += qapi
|
||||
trace-events-subdirs += qom
|
||||
@@ -202,6 +204,7 @@ trace-events-subdirs += target/riscv
|
||||
trace-events-subdirs += target/s390x
|
||||
trace-events-subdirs += target/sparc
|
||||
trace-events-subdirs += util
|
||||
trace-events-subdirs += hw/core
|
||||
|
||||
trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)
|
||||
|
||||
|
||||
+5
-21
@@ -12,7 +12,7 @@ endif
|
||||
|
||||
$(call set-vpath, $(SRC_PATH):$(BUILD_DIR))
|
||||
ifdef CONFIG_LINUX
|
||||
QEMU_CFLAGS += -isystem ../linux-headers
|
||||
QEMU_CFLAGS += -I../linux-headers
|
||||
endif
|
||||
QEMU_CFLAGS += -iquote .. -iquote $(SRC_PATH)/target/$(TARGET_BASE_ARCH) -DNEED_CPU_H
|
||||
|
||||
@@ -128,8 +128,7 @@ ifdef CONFIG_LINUX_USER
|
||||
|
||||
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) \
|
||||
-I$(SRC_PATH)/linux-user/host/$(ARCH) \
|
||||
-I$(SRC_PATH)/linux-user \
|
||||
-Ilinux-user/$(TARGET_ABI_DIR)
|
||||
-I$(SRC_PATH)/linux-user
|
||||
|
||||
obj-y += linux-user/
|
||||
obj-y += gdbstub.o thunk.o
|
||||
@@ -161,7 +160,6 @@ obj-y += qapi/
|
||||
obj-y += memory.o
|
||||
obj-y += memory_mapping.o
|
||||
obj-y += migration/ram.o
|
||||
obj-y += softmmu/
|
||||
LIBS := $(libs_softmmu) $(LIBS)
|
||||
|
||||
# Hardware support
|
||||
@@ -186,6 +184,7 @@ dummy := $(call unnest-vars,.., \
|
||||
block-obj-m \
|
||||
chardev-obj-y \
|
||||
crypto-obj-y \
|
||||
crypto-user-obj-y \
|
||||
qom-obj-y \
|
||||
io-obj-y \
|
||||
common-obj-y \
|
||||
@@ -194,6 +193,7 @@ all-obj-y += $(common-obj-y)
|
||||
all-obj-y += $(qom-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(authz-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) $(chardev-obj-y)
|
||||
all-obj-$(CONFIG_USER_ONLY) += $(crypto-user-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y)
|
||||
|
||||
@@ -204,7 +204,7 @@ endif
|
||||
COMMON_LDADDS = ../libqemuutil.a
|
||||
|
||||
# build either PROG or PROGW
|
||||
$(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS) $(softmmu-main-y)
|
||||
$(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS)
|
||||
$(call LINK, $(filter-out %.mak, $^))
|
||||
ifdef CONFIG_DARWIN
|
||||
$(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@,"REZ","$(TARGET_DIR)$@")
|
||||
@@ -229,22 +229,6 @@ ifdef CONFIG_TRACE_SYSTEMTAP
|
||||
rm -f *.stp
|
||||
endif
|
||||
|
||||
ifdef CONFIG_FUZZ
|
||||
include $(SRC_PATH)/tests/qtest/fuzz/Makefile.include
|
||||
include $(SRC_PATH)/tests/qtest/Makefile.include
|
||||
|
||||
fuzz: fuzz-vars
|
||||
fuzz-vars: QEMU_CFLAGS := $(FUZZ_CFLAGS) $(QEMU_CFLAGS)
|
||||
fuzz-vars: QEMU_LDFLAGS := $(FUZZ_LDFLAGS) $(QEMU_LDFLAGS)
|
||||
fuzz-vars: $(QEMU_PROG_FUZZ)
|
||||
dummy := $(call unnest-vars,, fuzz-obj-y)
|
||||
|
||||
|
||||
$(QEMU_PROG_FUZZ): config-devices.mak $(all-obj-y) $(COMMON_LDADDS) $(fuzz-obj-y)
|
||||
$(call LINK, $(filter-out %.mak, $^))
|
||||
|
||||
endif
|
||||
|
||||
install: all
|
||||
ifneq ($(PROGS),)
|
||||
$(call install-prog,$(PROGS),$(DESTDIR)$(bindir))
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
common-obj-$(CONFIG_SOFTMMU) += accel.o
|
||||
obj-$(CONFIG_SOFTMMU) += accel.o
|
||||
obj-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_POSIX)) += qtest.o
|
||||
obj-$(CONFIG_KVM) += kvm/
|
||||
obj-$(CONFIG_TCG) += tcg/
|
||||
|
||||
+67
-5
@@ -28,7 +28,13 @@
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "qom/object.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
static const TypeInfo accel_type = {
|
||||
.name = TYPE_ACCEL,
|
||||
@@ -38,7 +44,7 @@ static const TypeInfo accel_type = {
|
||||
};
|
||||
|
||||
/* Lookup AccelClass from opt_name. Returns NULL if not found */
|
||||
AccelClass *accel_find(const char *opt_name)
|
||||
static AccelClass *accel_find(const char *opt_name)
|
||||
{
|
||||
char *class_name = g_strdup_printf(ACCEL_CLASS_NAME("%s"), opt_name);
|
||||
AccelClass *ac = ACCEL_CLASS(object_class_by_name(class_name));
|
||||
@@ -46,9 +52,11 @@ AccelClass *accel_find(const char *opt_name)
|
||||
return ac;
|
||||
}
|
||||
|
||||
int accel_init_machine(AccelState *accel, MachineState *ms)
|
||||
static int accel_init_machine(AccelClass *acc, MachineState *ms)
|
||||
{
|
||||
AccelClass *acc = ACCEL_GET_CLASS(accel);
|
||||
ObjectClass *oc = OBJECT_CLASS(acc);
|
||||
const char *cname = object_class_get_name(oc);
|
||||
AccelState *accel = ACCEL(object_new(cname));
|
||||
int ret;
|
||||
ms->accelerator = accel;
|
||||
*(acc->allowed) = true;
|
||||
@@ -63,9 +71,63 @@ int accel_init_machine(AccelState *accel, MachineState *ms)
|
||||
return ret;
|
||||
}
|
||||
|
||||
AccelState *current_accel(void)
|
||||
void configure_accelerator(MachineState *ms, const char *progname)
|
||||
{
|
||||
return current_machine->accelerator;
|
||||
const char *accel;
|
||||
char **accel_list, **tmp;
|
||||
int ret;
|
||||
bool accel_initialised = false;
|
||||
bool init_failed = false;
|
||||
AccelClass *acc = NULL;
|
||||
|
||||
accel = qemu_opt_get(qemu_get_machine_opts(), "accel");
|
||||
if (accel == NULL) {
|
||||
/* Select the default accelerator */
|
||||
int pnlen = strlen(progname);
|
||||
if (pnlen >= 3 && g_str_equal(&progname[pnlen - 3], "kvm")) {
|
||||
/* If the program name ends with "kvm", we prefer KVM */
|
||||
accel = "kvm:tcg";
|
||||
} else {
|
||||
#if defined(CONFIG_TCG)
|
||||
accel = "tcg";
|
||||
#elif defined(CONFIG_KVM)
|
||||
accel = "kvm";
|
||||
#else
|
||||
error_report("No accelerator selected and"
|
||||
" no default accelerator available");
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
accel_list = g_strsplit(accel, ":", 0);
|
||||
|
||||
for (tmp = accel_list; !accel_initialised && tmp && *tmp; tmp++) {
|
||||
acc = accel_find(*tmp);
|
||||
if (!acc) {
|
||||
continue;
|
||||
}
|
||||
ret = accel_init_machine(acc, ms);
|
||||
if (ret < 0) {
|
||||
init_failed = true;
|
||||
error_report("failed to initialize %s: %s",
|
||||
acc->name, strerror(-ret));
|
||||
} else {
|
||||
accel_initialised = true;
|
||||
}
|
||||
}
|
||||
g_strfreev(accel_list);
|
||||
|
||||
if (!accel_initialised) {
|
||||
if (!init_failed) {
|
||||
error_report("-machine accel=%s: No accelerator found", accel);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (init_failed) {
|
||||
error_report("Back to %s accelerator", acc->name);
|
||||
}
|
||||
}
|
||||
|
||||
void accel_setup_post(MachineState *ms)
|
||||
|
||||
+11
-135
@@ -41,9 +41,6 @@
|
||||
#include "hw/irq.h"
|
||||
#include "sysemu/sev.h"
|
||||
#include "sysemu/balloon.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi/qapi-types-common.h"
|
||||
#include "qapi/qapi-visit-common.h"
|
||||
|
||||
#include "hw/boards.h"
|
||||
|
||||
@@ -95,10 +92,6 @@ struct KVMState
|
||||
int max_nested_state_len;
|
||||
int many_ioeventfds;
|
||||
int intx_set_mask;
|
||||
int kvm_shadow_mem;
|
||||
bool kernel_irqchip_allowed;
|
||||
bool kernel_irqchip_required;
|
||||
OnOffAuto kernel_irqchip_split;
|
||||
bool sync_mmu;
|
||||
bool manual_dirty_log_protect;
|
||||
/* The man page (and posix) say ioctl numbers are signed int, but
|
||||
@@ -164,7 +157,7 @@ static NotifierList kvm_irqchip_change_notifiers =
|
||||
|
||||
int kvm_get_max_memslots(void)
|
||||
{
|
||||
KVMState *s = KVM_STATE(current_accel());
|
||||
KVMState *s = KVM_STATE(current_machine->accelerator);
|
||||
|
||||
return s->nr_slots;
|
||||
}
|
||||
@@ -308,23 +301,13 @@ static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot, boo
|
||||
/* Set the slot size to 0 before setting the slot to the desired
|
||||
* value. This is needed based on KVM commit 75d61fbc. */
|
||||
mem.memory_size = 0;
|
||||
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
||||
}
|
||||
mem.memory_size = slot->memory_size;
|
||||
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
||||
slot->old_flags = mem.flags;
|
||||
err:
|
||||
trace_kvm_set_user_memory(mem.slot, mem.flags, mem.guest_phys_addr,
|
||||
mem.memory_size, mem.userspace_addr, ret);
|
||||
if (ret < 0) {
|
||||
error_report("%s: KVM_SET_USER_MEMORY_REGION failed, slot=%d,"
|
||||
" start=0x%" PRIx64 ", size=0x%" PRIx64 ": %s",
|
||||
__func__, mem.slot, slot->start_addr,
|
||||
(uint64_t)mem.memory_size, strerror(errno));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1789,11 +1772,10 @@ void kvm_irqchip_set_qemuirq_gsi(KVMState *s, qemu_irq irq, int gsi)
|
||||
g_hash_table_insert(s->gsimap, irq, GINT_TO_POINTER(gsi));
|
||||
}
|
||||
|
||||
static void kvm_irqchip_create(KVMState *s)
|
||||
static void kvm_irqchip_create(MachineState *machine, KVMState *s)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(s->kernel_irqchip_split != ON_OFF_AUTO_AUTO);
|
||||
if (kvm_check_extension(s, KVM_CAP_IRQCHIP)) {
|
||||
;
|
||||
} else if (kvm_check_extension(s, KVM_CAP_S390_IRQCHIP)) {
|
||||
@@ -1808,9 +1790,9 @@ static void kvm_irqchip_create(KVMState *s)
|
||||
|
||||
/* First probe and see if there's a arch-specific hook to create the
|
||||
* in-kernel irqchip for us */
|
||||
ret = kvm_arch_irqchip_create(s);
|
||||
ret = kvm_arch_irqchip_create(machine, s);
|
||||
if (ret == 0) {
|
||||
if (s->kernel_irqchip_split == ON_OFF_AUTO_ON) {
|
||||
if (machine_kernel_irqchip_split(machine)) {
|
||||
perror("Split IRQ chip mode not supported.");
|
||||
exit(1);
|
||||
} else {
|
||||
@@ -1858,7 +1840,7 @@ static int kvm_max_vcpu_id(KVMState *s)
|
||||
|
||||
bool kvm_vcpu_id_is_valid(int vcpu_id)
|
||||
{
|
||||
KVMState *s = KVM_STATE(current_accel());
|
||||
KVMState *s = KVM_STATE(current_machine->accelerator);
|
||||
return vcpu_id >= 0 && vcpu_id < kvm_max_vcpu_id(s);
|
||||
}
|
||||
|
||||
@@ -2081,12 +2063,8 @@ static int kvm_init(MachineState *ms)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (s->kernel_irqchip_split == ON_OFF_AUTO_AUTO) {
|
||||
s->kernel_irqchip_split = mc->default_kernel_irqchip_split ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
|
||||
}
|
||||
|
||||
if (s->kernel_irqchip_allowed) {
|
||||
kvm_irqchip_create(s);
|
||||
if (machine_kernel_irqchip_allowed(ms)) {
|
||||
kvm_irqchip_create(ms, s);
|
||||
}
|
||||
|
||||
if (kvm_eventfds_allowed) {
|
||||
@@ -2188,9 +2166,9 @@ void kvm_flush_coalesced_mmio_buffer(void)
|
||||
ent = &ring->coalesced_mmio[ring->first];
|
||||
|
||||
if (ent->pio == 1) {
|
||||
address_space_write(&address_space_io, ent->phys_addr,
|
||||
MEMTXATTRS_UNSPECIFIED, ent->data,
|
||||
ent->len);
|
||||
address_space_rw(&address_space_io, ent->phys_addr,
|
||||
MEMTXATTRS_UNSPECIFIED, ent->data,
|
||||
ent->len, true);
|
||||
} else {
|
||||
cpu_physical_memory_write(ent->phys_addr, ent->data, ent->len);
|
||||
}
|
||||
@@ -2976,95 +2954,6 @@ static bool kvm_accel_has_memory(MachineState *ms, AddressSpace *as,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void kvm_get_kvm_shadow_mem(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
KVMState *s = KVM_STATE(obj);
|
||||
int64_t value = s->kvm_shadow_mem;
|
||||
|
||||
visit_type_int(v, name, &value, errp);
|
||||
}
|
||||
|
||||
static void kvm_set_kvm_shadow_mem(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
KVMState *s = KVM_STATE(obj);
|
||||
Error *error = NULL;
|
||||
int64_t value;
|
||||
|
||||
visit_type_int(v, name, &value, &error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
return;
|
||||
}
|
||||
|
||||
s->kvm_shadow_mem = value;
|
||||
}
|
||||
|
||||
static void kvm_set_kernel_irqchip(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
KVMState *s = KVM_STATE(obj);
|
||||
OnOffSplit mode;
|
||||
|
||||
visit_type_OnOffSplit(v, name, &mode, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
} else {
|
||||
switch (mode) {
|
||||
case ON_OFF_SPLIT_ON:
|
||||
s->kernel_irqchip_allowed = true;
|
||||
s->kernel_irqchip_required = true;
|
||||
s->kernel_irqchip_split = ON_OFF_AUTO_OFF;
|
||||
break;
|
||||
case ON_OFF_SPLIT_OFF:
|
||||
s->kernel_irqchip_allowed = false;
|
||||
s->kernel_irqchip_required = false;
|
||||
s->kernel_irqchip_split = ON_OFF_AUTO_OFF;
|
||||
break;
|
||||
case ON_OFF_SPLIT_SPLIT:
|
||||
s->kernel_irqchip_allowed = true;
|
||||
s->kernel_irqchip_required = true;
|
||||
s->kernel_irqchip_split = ON_OFF_AUTO_ON;
|
||||
break;
|
||||
default:
|
||||
/* The value was checked in visit_type_OnOffSplit() above. If
|
||||
* we get here, then something is wrong in QEMU.
|
||||
*/
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool kvm_kernel_irqchip_allowed(void)
|
||||
{
|
||||
return kvm_state->kernel_irqchip_allowed;
|
||||
}
|
||||
|
||||
bool kvm_kernel_irqchip_required(void)
|
||||
{
|
||||
return kvm_state->kernel_irqchip_required;
|
||||
}
|
||||
|
||||
bool kvm_kernel_irqchip_split(void)
|
||||
{
|
||||
return kvm_state->kernel_irqchip_split == ON_OFF_AUTO_ON;
|
||||
}
|
||||
|
||||
static void kvm_accel_instance_init(Object *obj)
|
||||
{
|
||||
KVMState *s = KVM_STATE(obj);
|
||||
|
||||
s->kvm_shadow_mem = -1;
|
||||
s->kernel_irqchip_allowed = true;
|
||||
s->kernel_irqchip_split = ON_OFF_AUTO_AUTO;
|
||||
}
|
||||
|
||||
static void kvm_accel_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelClass *ac = ACCEL_CLASS(oc);
|
||||
@@ -3072,24 +2961,11 @@ static void kvm_accel_class_init(ObjectClass *oc, void *data)
|
||||
ac->init_machine = kvm_init;
|
||||
ac->has_memory = kvm_accel_has_memory;
|
||||
ac->allowed = &kvm_allowed;
|
||||
|
||||
object_class_property_add(oc, "kernel-irqchip", "on|off|split",
|
||||
NULL, kvm_set_kernel_irqchip,
|
||||
NULL, NULL, &error_abort);
|
||||
object_class_property_set_description(oc, "kernel-irqchip",
|
||||
"Configure KVM in-kernel irqchip", &error_abort);
|
||||
|
||||
object_class_property_add(oc, "kvm-shadow-mem", "int",
|
||||
kvm_get_kvm_shadow_mem, kvm_set_kvm_shadow_mem,
|
||||
NULL, NULL, &error_abort);
|
||||
object_class_property_set_description(oc, "kvm-shadow-mem",
|
||||
"KVM shadow MMU size", &error_abort);
|
||||
}
|
||||
|
||||
static const TypeInfo kvm_accel_type = {
|
||||
.name = TYPE_KVM_ACCEL,
|
||||
.parent = TYPE_ACCEL,
|
||||
.instance_init = kvm_accel_instance_init,
|
||||
.class_init = kvm_accel_class_init,
|
||||
.instance_size = sizeof(KVMState),
|
||||
};
|
||||
|
||||
+43
-24
@@ -64,10 +64,13 @@
|
||||
the ATOMIC_NAME macro, and redefined below. */
|
||||
#if DATA_SIZE == 1
|
||||
# define END
|
||||
# define MEND _be /* either le or be would be fine */
|
||||
#elif defined(HOST_WORDS_BIGENDIAN)
|
||||
# define END _be
|
||||
# define MEND _be
|
||||
#else
|
||||
# define END _le
|
||||
# define MEND _le
|
||||
#endif
|
||||
|
||||
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
@@ -76,8 +79,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
DATA_TYPE ret;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
#if DATA_SIZE == 16
|
||||
@@ -96,8 +99,8 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
|
||||
{
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_ld_pre(env, addr, info);
|
||||
val = atomic16_read(haddr);
|
||||
@@ -111,8 +114,8 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
|
||||
{
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, true,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_st_pre(env, addr, info);
|
||||
atomic16_set(haddr, val);
|
||||
@@ -127,8 +130,8 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
DATA_TYPE ret;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
ret = atomic_xchg__nocheck(haddr, val);
|
||||
@@ -144,8 +147,10 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ATOMIC_MMU_DECLS; \
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
|
||||
DATA_TYPE ret; \
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \
|
||||
false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
\
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
ret = atomic_##X(haddr, val); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
@@ -178,8 +183,10 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ATOMIC_MMU_DECLS; \
|
||||
XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
|
||||
XDATA_TYPE cmp, old, new, val = xval; \
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \
|
||||
false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
\
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
smp_mb(); \
|
||||
cmp = atomic_read__nocheck(haddr); \
|
||||
@@ -206,6 +213,7 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
|
||||
#endif /* DATA SIZE >= 16 */
|
||||
|
||||
#undef END
|
||||
#undef MEND
|
||||
|
||||
#if DATA_SIZE > 1
|
||||
|
||||
@@ -213,8 +221,10 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
|
||||
within the ATOMIC_NAME macro. */
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
# define END _le
|
||||
# define MEND _le
|
||||
#else
|
||||
# define END _be
|
||||
# define MEND _be
|
||||
#endif
|
||||
|
||||
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
@@ -223,8 +233,9 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
DATA_TYPE ret;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
|
||||
false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
#if DATA_SIZE == 16
|
||||
@@ -243,8 +254,9 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
|
||||
{
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
|
||||
false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_ld_pre(env, addr, info);
|
||||
val = atomic16_read(haddr);
|
||||
@@ -258,8 +270,9 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
|
||||
{
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, true,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
|
||||
true,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
val = BSWAP(val);
|
||||
atomic_trace_st_pre(env, addr, info);
|
||||
@@ -276,8 +289,9 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
ABI_TYPE ret;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
|
||||
false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
ret = atomic_xchg__nocheck(haddr, BSWAP(val));
|
||||
@@ -293,8 +307,10 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ATOMIC_MMU_DECLS; \
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
|
||||
DATA_TYPE ret; \
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \
|
||||
false, ATOMIC_MMU_IDX); \
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \
|
||||
false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
\
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
ret = atomic_##X(haddr, BSWAP(val)); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
@@ -325,8 +341,10 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ATOMIC_MMU_DECLS; \
|
||||
XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
|
||||
XDATA_TYPE ldo, ldn, old, new, val = xval; \
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \
|
||||
false, ATOMIC_MMU_IDX); \
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \
|
||||
false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
\
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
smp_mb(); \
|
||||
ldn = atomic_read__nocheck(haddr); \
|
||||
@@ -360,6 +378,7 @@ GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
|
||||
#endif /* DATA_SIZE >= 16 */
|
||||
|
||||
#undef END
|
||||
#undef MEND
|
||||
#endif /* DATA_SIZE > 1 */
|
||||
|
||||
#undef BSWAP
|
||||
|
||||
+13
-14
@@ -23,7 +23,7 @@
|
||||
#include "trace.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "tcg.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "qemu/timer.h"
|
||||
@@ -156,7 +156,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
||||
#if defined(DEBUG_DISAS)
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)
|
||||
&& qemu_log_in_addr_range(itb->pc)) {
|
||||
FILE *logfile = qemu_log_lock();
|
||||
qemu_log_lock();
|
||||
int flags = 0;
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_FPU)) {
|
||||
flags |= CPU_DUMP_FPU;
|
||||
@@ -165,7 +165,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
||||
flags |= CPU_DUMP_CCOP;
|
||||
#endif
|
||||
log_cpu_state(cpu, flags);
|
||||
qemu_log_unlock(logfile);
|
||||
qemu_log_unlock();
|
||||
}
|
||||
#endif /* DEBUG_DISAS */
|
||||
|
||||
@@ -240,8 +240,6 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
||||
uint32_t cf_mask = cflags & CF_HASH_MASK;
|
||||
|
||||
if (sigsetjmp(cpu->jmp_env, 0) == 0) {
|
||||
start_exclusive();
|
||||
|
||||
tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags, cf_mask);
|
||||
if (tb == NULL) {
|
||||
mmap_lock();
|
||||
@@ -249,6 +247,8 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
||||
mmap_unlock();
|
||||
}
|
||||
|
||||
start_exclusive();
|
||||
|
||||
/* Since we got here, we know that parallel_cpus must be true. */
|
||||
parallel_cpus = false;
|
||||
cc->cpu_exec_enter(cpu);
|
||||
@@ -271,15 +271,14 @@ 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
|
||||
* the execution.
|
||||
*/
|
||||
g_assert(cpu_in_exclusive_context(cpu));
|
||||
parallel_cpus = true;
|
||||
end_exclusive();
|
||||
if (cpu_in_exclusive_context(cpu)) {
|
||||
/* We might longjump out of either the codegen or the
|
||||
* execution, so must make sure we only end the exclusive
|
||||
* region if we started it.
|
||||
*/
|
||||
parallel_cpus = true;
|
||||
end_exclusive();
|
||||
}
|
||||
}
|
||||
|
||||
struct tb_desc {
|
||||
|
||||
+162
-440
@@ -34,8 +34,6 @@
|
||||
#include "qemu/atomic.h"
|
||||
#include "qemu/atomic128.h"
|
||||
#include "translate-all.h"
|
||||
#include "trace-root.h"
|
||||
#include "trace/mem.h"
|
||||
#ifdef CONFIG_PLUGIN
|
||||
#include "qemu/plugin-memory.h"
|
||||
#endif
|
||||
@@ -80,14 +78,9 @@ QEMU_BUILD_BUG_ON(sizeof(target_ulong) > sizeof(run_on_cpu_data));
|
||||
QEMU_BUILD_BUG_ON(NB_MMU_MODES > 16);
|
||||
#define ALL_MMUIDX_BITS ((1 << NB_MMU_MODES) - 1)
|
||||
|
||||
static inline size_t tlb_n_entries(CPUTLBDescFast *fast)
|
||||
static inline size_t sizeof_tlb(CPUArchState *env, uintptr_t mmu_idx)
|
||||
{
|
||||
return (fast->mask >> CPU_TLB_ENTRY_BITS) + 1;
|
||||
}
|
||||
|
||||
static inline size_t sizeof_tlb(CPUTLBDescFast *fast)
|
||||
{
|
||||
return fast->mask + (1 << CPU_TLB_ENTRY_BITS);
|
||||
return env_tlb(env)->f[mmu_idx].mask + (1 << CPU_TLB_ENTRY_BITS);
|
||||
}
|
||||
|
||||
static void tlb_window_reset(CPUTLBDesc *desc, int64_t ns,
|
||||
@@ -97,10 +90,26 @@ static void tlb_window_reset(CPUTLBDesc *desc, int64_t ns,
|
||||
desc->window_max_entries = max_entries;
|
||||
}
|
||||
|
||||
static void tlb_dyn_init(CPUArchState *env)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NB_MMU_MODES; i++) {
|
||||
CPUTLBDesc *desc = &env_tlb(env)->d[i];
|
||||
size_t n_entries = 1 << CPU_TLB_DYN_DEFAULT_BITS;
|
||||
|
||||
tlb_window_reset(desc, get_clock_realtime(), 0);
|
||||
desc->n_used_entries = 0;
|
||||
env_tlb(env)->f[i].mask = (n_entries - 1) << CPU_TLB_ENTRY_BITS;
|
||||
env_tlb(env)->f[i].table = g_new(CPUTLBEntry, n_entries);
|
||||
env_tlb(env)->d[i].iotlb = g_new(CPUIOTLBEntry, n_entries);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tlb_mmu_resize_locked() - perform TLB resize bookkeeping; resize if necessary
|
||||
* @desc: The CPUTLBDesc portion of the TLB
|
||||
* @fast: The CPUTLBDescFast portion of the same TLB
|
||||
* @env: CPU that owns the TLB
|
||||
* @mmu_idx: MMU index of the TLB
|
||||
*
|
||||
* Called with tlb_lock_held.
|
||||
*
|
||||
@@ -137,12 +146,13 @@ static void tlb_window_reset(CPUTLBDesc *desc, int64_t ns,
|
||||
* high), since otherwise we are likely to have a significant amount of
|
||||
* conflict misses.
|
||||
*/
|
||||
static void tlb_mmu_resize_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast,
|
||||
int64_t now)
|
||||
static void tlb_mmu_resize_locked(CPUArchState *env, int mmu_idx)
|
||||
{
|
||||
size_t old_size = tlb_n_entries(fast);
|
||||
CPUTLBDesc *desc = &env_tlb(env)->d[mmu_idx];
|
||||
size_t old_size = tlb_n_entries(env, mmu_idx);
|
||||
size_t rate;
|
||||
size_t new_size = old_size;
|
||||
int64_t now = get_clock_realtime();
|
||||
int64_t window_len_ms = 100;
|
||||
int64_t window_len_ns = window_len_ms * 1000 * 1000;
|
||||
bool window_expired = now > desc->window_begin_ns + window_len_ns;
|
||||
@@ -181,15 +191,14 @@ static void tlb_mmu_resize_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast,
|
||||
return;
|
||||
}
|
||||
|
||||
g_free(fast->table);
|
||||
g_free(desc->iotlb);
|
||||
g_free(env_tlb(env)->f[mmu_idx].table);
|
||||
g_free(env_tlb(env)->d[mmu_idx].iotlb);
|
||||
|
||||
tlb_window_reset(desc, now, 0);
|
||||
/* desc->n_used_entries is cleared by the caller */
|
||||
fast->mask = (new_size - 1) << CPU_TLB_ENTRY_BITS;
|
||||
fast->table = g_try_new(CPUTLBEntry, new_size);
|
||||
desc->iotlb = g_try_new(CPUIOTLBEntry, new_size);
|
||||
|
||||
env_tlb(env)->f[mmu_idx].mask = (new_size - 1) << CPU_TLB_ENTRY_BITS;
|
||||
env_tlb(env)->f[mmu_idx].table = g_try_new(CPUTLBEntry, new_size);
|
||||
env_tlb(env)->d[mmu_idx].iotlb = g_try_new(CPUIOTLBEntry, new_size);
|
||||
/*
|
||||
* If the allocations fail, try smaller sizes. We just freed some
|
||||
* memory, so going back to half of new_size has a good chance of working.
|
||||
@@ -197,51 +206,27 @@ static void tlb_mmu_resize_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast,
|
||||
* allocations to fail though, so we progressively reduce the allocation
|
||||
* size, aborting if we cannot even allocate the smallest TLB we support.
|
||||
*/
|
||||
while (fast->table == NULL || desc->iotlb == NULL) {
|
||||
while (env_tlb(env)->f[mmu_idx].table == NULL ||
|
||||
env_tlb(env)->d[mmu_idx].iotlb == NULL) {
|
||||
if (new_size == (1 << CPU_TLB_DYN_MIN_BITS)) {
|
||||
error_report("%s: %s", __func__, strerror(errno));
|
||||
abort();
|
||||
}
|
||||
new_size = MAX(new_size >> 1, 1 << CPU_TLB_DYN_MIN_BITS);
|
||||
fast->mask = (new_size - 1) << CPU_TLB_ENTRY_BITS;
|
||||
env_tlb(env)->f[mmu_idx].mask = (new_size - 1) << CPU_TLB_ENTRY_BITS;
|
||||
|
||||
g_free(fast->table);
|
||||
g_free(desc->iotlb);
|
||||
fast->table = g_try_new(CPUTLBEntry, new_size);
|
||||
desc->iotlb = g_try_new(CPUIOTLBEntry, new_size);
|
||||
g_free(env_tlb(env)->f[mmu_idx].table);
|
||||
g_free(env_tlb(env)->d[mmu_idx].iotlb);
|
||||
env_tlb(env)->f[mmu_idx].table = g_try_new(CPUTLBEntry, new_size);
|
||||
env_tlb(env)->d[mmu_idx].iotlb = g_try_new(CPUIOTLBEntry, new_size);
|
||||
}
|
||||
}
|
||||
|
||||
static void tlb_mmu_flush_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast)
|
||||
static inline void tlb_table_flush_by_mmuidx(CPUArchState *env, int mmu_idx)
|
||||
{
|
||||
desc->n_used_entries = 0;
|
||||
desc->large_page_addr = -1;
|
||||
desc->large_page_mask = -1;
|
||||
desc->vindex = 0;
|
||||
memset(fast->table, -1, sizeof_tlb(fast));
|
||||
memset(desc->vtable, -1, sizeof(desc->vtable));
|
||||
}
|
||||
|
||||
static void tlb_flush_one_mmuidx_locked(CPUArchState *env, int mmu_idx,
|
||||
int64_t now)
|
||||
{
|
||||
CPUTLBDesc *desc = &env_tlb(env)->d[mmu_idx];
|
||||
CPUTLBDescFast *fast = &env_tlb(env)->f[mmu_idx];
|
||||
|
||||
tlb_mmu_resize_locked(desc, fast, now);
|
||||
tlb_mmu_flush_locked(desc, fast);
|
||||
}
|
||||
|
||||
static void tlb_mmu_init(CPUTLBDesc *desc, CPUTLBDescFast *fast, int64_t now)
|
||||
{
|
||||
size_t n_entries = 1 << CPU_TLB_DYN_DEFAULT_BITS;
|
||||
|
||||
tlb_window_reset(desc, now, 0);
|
||||
desc->n_used_entries = 0;
|
||||
fast->mask = (n_entries - 1) << CPU_TLB_ENTRY_BITS;
|
||||
fast->table = g_new(CPUTLBEntry, n_entries);
|
||||
desc->iotlb = g_new(CPUIOTLBEntry, n_entries);
|
||||
tlb_mmu_flush_locked(desc, fast);
|
||||
tlb_mmu_resize_locked(env, mmu_idx);
|
||||
memset(env_tlb(env)->f[mmu_idx].table, -1, sizeof_tlb(env, mmu_idx));
|
||||
env_tlb(env)->d[mmu_idx].n_used_entries = 0;
|
||||
}
|
||||
|
||||
static inline void tlb_n_used_entries_inc(CPUArchState *env, uintptr_t mmu_idx)
|
||||
@@ -257,17 +242,13 @@ static inline void tlb_n_used_entries_dec(CPUArchState *env, uintptr_t mmu_idx)
|
||||
void tlb_init(CPUState *cpu)
|
||||
{
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
int64_t now = get_clock_realtime();
|
||||
int i;
|
||||
|
||||
qemu_spin_init(&env_tlb(env)->c.lock);
|
||||
|
||||
/* All tlbs are initialized flushed. */
|
||||
env_tlb(env)->c.dirty = 0;
|
||||
/* Ensure that cpu_reset performs a full flush. */
|
||||
env_tlb(env)->c.dirty = ALL_MMUIDX_BITS;
|
||||
|
||||
for (i = 0; i < NB_MMU_MODES; i++) {
|
||||
tlb_mmu_init(&env_tlb(env)->d[i], &env_tlb(env)->f[i], now);
|
||||
}
|
||||
tlb_dyn_init(env);
|
||||
}
|
||||
|
||||
/* flush_all_helper: run fn across all cpus
|
||||
@@ -306,12 +287,21 @@ void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide)
|
||||
*pelide = elide;
|
||||
}
|
||||
|
||||
static void tlb_flush_one_mmuidx_locked(CPUArchState *env, int mmu_idx)
|
||||
{
|
||||
tlb_table_flush_by_mmuidx(env, mmu_idx);
|
||||
env_tlb(env)->d[mmu_idx].large_page_addr = -1;
|
||||
env_tlb(env)->d[mmu_idx].large_page_mask = -1;
|
||||
env_tlb(env)->d[mmu_idx].vindex = 0;
|
||||
memset(env_tlb(env)->d[mmu_idx].vtable, -1,
|
||||
sizeof(env_tlb(env)->d[0].vtable));
|
||||
}
|
||||
|
||||
static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data)
|
||||
{
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
uint16_t asked = data.host_int;
|
||||
uint16_t all_dirty, work, to_clean;
|
||||
int64_t now = get_clock_realtime();
|
||||
|
||||
assert_cpu_is_self(cpu);
|
||||
|
||||
@@ -326,7 +316,7 @@ static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data)
|
||||
|
||||
for (work = to_clean; work != 0; work &= work - 1) {
|
||||
int mmu_idx = ctz32(work);
|
||||
tlb_flush_one_mmuidx_locked(env, mmu_idx, now);
|
||||
tlb_flush_one_mmuidx_locked(env, mmu_idx);
|
||||
}
|
||||
|
||||
qemu_spin_unlock(&env_tlb(env)->c.lock);
|
||||
@@ -448,7 +438,7 @@ static void tlb_flush_page_locked(CPUArchState *env, int midx,
|
||||
tlb_debug("forcing full flush midx %d ("
|
||||
TARGET_FMT_lx "/" TARGET_FMT_lx ")\n",
|
||||
midx, lp_addr, lp_mask);
|
||||
tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime());
|
||||
tlb_flush_one_mmuidx_locked(env, midx);
|
||||
} else {
|
||||
if (tlb_flush_entry_locked(tlb_entry(env, midx, page), page)) {
|
||||
tlb_n_used_entries_dec(env, midx);
|
||||
@@ -457,29 +447,28 @@ static void tlb_flush_page_locked(CPUArchState *env, int midx,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tlb_flush_page_by_mmuidx_async_0:
|
||||
* @cpu: cpu on which to flush
|
||||
* @addr: page of virtual address to flush
|
||||
* @idxmap: set of mmu_idx to flush
|
||||
*
|
||||
* Helper for tlb_flush_page_by_mmuidx and friends, flush one page
|
||||
* at @addr from the tlbs indicated by @idxmap from @cpu.
|
||||
/* As we are going to hijack the bottom bits of the page address for a
|
||||
* mmuidx bit mask we need to fail to build if we can't do that
|
||||
*/
|
||||
static void tlb_flush_page_by_mmuidx_async_0(CPUState *cpu,
|
||||
target_ulong addr,
|
||||
uint16_t idxmap)
|
||||
QEMU_BUILD_BUG_ON(NB_MMU_MODES > TARGET_PAGE_BITS_MIN);
|
||||
|
||||
static void tlb_flush_page_by_mmuidx_async_work(CPUState *cpu,
|
||||
run_on_cpu_data data)
|
||||
{
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
target_ulong addr_and_mmuidx = (target_ulong) data.target_ptr;
|
||||
target_ulong addr = addr_and_mmuidx & TARGET_PAGE_MASK;
|
||||
unsigned long mmu_idx_bitmap = addr_and_mmuidx & ALL_MMUIDX_BITS;
|
||||
int mmu_idx;
|
||||
|
||||
assert_cpu_is_self(cpu);
|
||||
|
||||
tlb_debug("page addr:" TARGET_FMT_lx " mmu_map:0x%x\n", addr, idxmap);
|
||||
tlb_debug("page addr:" TARGET_FMT_lx " mmu_map:0x%lx\n",
|
||||
addr, mmu_idx_bitmap);
|
||||
|
||||
qemu_spin_lock(&env_tlb(env)->c.lock);
|
||||
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
|
||||
if ((idxmap >> mmu_idx) & 1) {
|
||||
if (test_bit(mmu_idx, &mmu_idx_bitmap)) {
|
||||
tlb_flush_page_locked(env, mmu_idx, addr);
|
||||
}
|
||||
}
|
||||
@@ -488,75 +477,22 @@ static void tlb_flush_page_by_mmuidx_async_0(CPUState *cpu,
|
||||
tb_flush_jmp_cache(cpu, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* tlb_flush_page_by_mmuidx_async_1:
|
||||
* @cpu: cpu on which to flush
|
||||
* @data: encoded addr + idxmap
|
||||
*
|
||||
* Helper for tlb_flush_page_by_mmuidx and friends, called through
|
||||
* async_run_on_cpu. The idxmap parameter is encoded in the page
|
||||
* offset of the target_ptr field. This limits the set of mmu_idx
|
||||
* that can be passed via this method.
|
||||
*/
|
||||
static void tlb_flush_page_by_mmuidx_async_1(CPUState *cpu,
|
||||
run_on_cpu_data data)
|
||||
{
|
||||
target_ulong addr_and_idxmap = (target_ulong) data.target_ptr;
|
||||
target_ulong addr = addr_and_idxmap & TARGET_PAGE_MASK;
|
||||
uint16_t idxmap = addr_and_idxmap & ~TARGET_PAGE_MASK;
|
||||
|
||||
tlb_flush_page_by_mmuidx_async_0(cpu, addr, idxmap);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
target_ulong addr;
|
||||
uint16_t idxmap;
|
||||
} TLBFlushPageByMMUIdxData;
|
||||
|
||||
/**
|
||||
* tlb_flush_page_by_mmuidx_async_2:
|
||||
* @cpu: cpu on which to flush
|
||||
* @data: allocated addr + idxmap
|
||||
*
|
||||
* Helper for tlb_flush_page_by_mmuidx and friends, called through
|
||||
* async_run_on_cpu. The addr+idxmap parameters are stored in a
|
||||
* TLBFlushPageByMMUIdxData structure that has been allocated
|
||||
* specifically for this helper. Free the structure when done.
|
||||
*/
|
||||
static void tlb_flush_page_by_mmuidx_async_2(CPUState *cpu,
|
||||
run_on_cpu_data data)
|
||||
{
|
||||
TLBFlushPageByMMUIdxData *d = data.host_ptr;
|
||||
|
||||
tlb_flush_page_by_mmuidx_async_0(cpu, d->addr, d->idxmap);
|
||||
g_free(d);
|
||||
}
|
||||
|
||||
void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, uint16_t idxmap)
|
||||
{
|
||||
target_ulong addr_and_mmu_idx;
|
||||
|
||||
tlb_debug("addr: "TARGET_FMT_lx" mmu_idx:%" PRIx16 "\n", addr, idxmap);
|
||||
|
||||
/* This should already be page aligned */
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
addr_and_mmu_idx = addr & TARGET_PAGE_MASK;
|
||||
addr_and_mmu_idx |= idxmap;
|
||||
|
||||
if (qemu_cpu_is_self(cpu)) {
|
||||
tlb_flush_page_by_mmuidx_async_0(cpu, addr, idxmap);
|
||||
} else if (idxmap < TARGET_PAGE_SIZE) {
|
||||
/*
|
||||
* Most targets have only a few mmu_idx. In the case where
|
||||
* we can stuff idxmap into the low TARGET_PAGE_BITS, avoid
|
||||
* allocating memory for this operation.
|
||||
*/
|
||||
async_run_on_cpu(cpu, tlb_flush_page_by_mmuidx_async_1,
|
||||
RUN_ON_CPU_TARGET_PTR(addr | idxmap));
|
||||
if (!qemu_cpu_is_self(cpu)) {
|
||||
async_run_on_cpu(cpu, tlb_flush_page_by_mmuidx_async_work,
|
||||
RUN_ON_CPU_TARGET_PTR(addr_and_mmu_idx));
|
||||
} else {
|
||||
TLBFlushPageByMMUIdxData *d = g_new(TLBFlushPageByMMUIdxData, 1);
|
||||
|
||||
/* Otherwise allocate a structure, freed by the worker. */
|
||||
d->addr = addr;
|
||||
d->idxmap = idxmap;
|
||||
async_run_on_cpu(cpu, tlb_flush_page_by_mmuidx_async_2,
|
||||
RUN_ON_CPU_HOST_PTR(d));
|
||||
tlb_flush_page_by_mmuidx_async_work(
|
||||
cpu, RUN_ON_CPU_TARGET_PTR(addr_and_mmu_idx));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,36 +504,17 @@ void tlb_flush_page(CPUState *cpu, target_ulong addr)
|
||||
void tlb_flush_page_by_mmuidx_all_cpus(CPUState *src_cpu, target_ulong addr,
|
||||
uint16_t idxmap)
|
||||
{
|
||||
const run_on_cpu_func fn = tlb_flush_page_by_mmuidx_async_work;
|
||||
target_ulong addr_and_mmu_idx;
|
||||
|
||||
tlb_debug("addr: "TARGET_FMT_lx" mmu_idx:%"PRIx16"\n", addr, idxmap);
|
||||
|
||||
/* This should already be page aligned */
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
addr_and_mmu_idx = addr & TARGET_PAGE_MASK;
|
||||
addr_and_mmu_idx |= idxmap;
|
||||
|
||||
/*
|
||||
* Allocate memory to hold addr+idxmap only when needed.
|
||||
* See tlb_flush_page_by_mmuidx for details.
|
||||
*/
|
||||
if (idxmap < TARGET_PAGE_SIZE) {
|
||||
flush_all_helper(src_cpu, tlb_flush_page_by_mmuidx_async_1,
|
||||
RUN_ON_CPU_TARGET_PTR(addr | idxmap));
|
||||
} else {
|
||||
CPUState *dst_cpu;
|
||||
|
||||
/* Allocate a separate data block for each destination cpu. */
|
||||
CPU_FOREACH(dst_cpu) {
|
||||
if (dst_cpu != src_cpu) {
|
||||
TLBFlushPageByMMUIdxData *d
|
||||
= g_new(TLBFlushPageByMMUIdxData, 1);
|
||||
|
||||
d->addr = addr;
|
||||
d->idxmap = idxmap;
|
||||
async_run_on_cpu(dst_cpu, tlb_flush_page_by_mmuidx_async_2,
|
||||
RUN_ON_CPU_HOST_PTR(d));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tlb_flush_page_by_mmuidx_async_0(src_cpu, addr, idxmap);
|
||||
flush_all_helper(src_cpu, fn, RUN_ON_CPU_TARGET_PTR(addr_and_mmu_idx));
|
||||
fn(src_cpu, RUN_ON_CPU_TARGET_PTR(addr_and_mmu_idx));
|
||||
}
|
||||
|
||||
void tlb_flush_page_all_cpus(CPUState *src, target_ulong addr)
|
||||
@@ -609,41 +526,17 @@ void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *src_cpu,
|
||||
target_ulong addr,
|
||||
uint16_t idxmap)
|
||||
{
|
||||
const run_on_cpu_func fn = tlb_flush_page_by_mmuidx_async_work;
|
||||
target_ulong addr_and_mmu_idx;
|
||||
|
||||
tlb_debug("addr: "TARGET_FMT_lx" mmu_idx:%"PRIx16"\n", addr, idxmap);
|
||||
|
||||
/* This should already be page aligned */
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
addr_and_mmu_idx = addr & TARGET_PAGE_MASK;
|
||||
addr_and_mmu_idx |= idxmap;
|
||||
|
||||
/*
|
||||
* Allocate memory to hold addr+idxmap only when needed.
|
||||
* See tlb_flush_page_by_mmuidx for details.
|
||||
*/
|
||||
if (idxmap < TARGET_PAGE_SIZE) {
|
||||
flush_all_helper(src_cpu, tlb_flush_page_by_mmuidx_async_1,
|
||||
RUN_ON_CPU_TARGET_PTR(addr | idxmap));
|
||||
async_safe_run_on_cpu(src_cpu, tlb_flush_page_by_mmuidx_async_1,
|
||||
RUN_ON_CPU_TARGET_PTR(addr | idxmap));
|
||||
} else {
|
||||
CPUState *dst_cpu;
|
||||
TLBFlushPageByMMUIdxData *d;
|
||||
|
||||
/* Allocate a separate data block for each destination cpu. */
|
||||
CPU_FOREACH(dst_cpu) {
|
||||
if (dst_cpu != src_cpu) {
|
||||
d = g_new(TLBFlushPageByMMUIdxData, 1);
|
||||
d->addr = addr;
|
||||
d->idxmap = idxmap;
|
||||
async_run_on_cpu(dst_cpu, tlb_flush_page_by_mmuidx_async_2,
|
||||
RUN_ON_CPU_HOST_PTR(d));
|
||||
}
|
||||
}
|
||||
|
||||
d = g_new(TLBFlushPageByMMUIdxData, 1);
|
||||
d->addr = addr;
|
||||
d->idxmap = idxmap;
|
||||
async_safe_run_on_cpu(src_cpu, tlb_flush_page_by_mmuidx_async_2,
|
||||
RUN_ON_CPU_HOST_PTR(d));
|
||||
}
|
||||
flush_all_helper(src_cpu, fn, RUN_ON_CPU_TARGET_PTR(addr_and_mmu_idx));
|
||||
async_safe_run_on_cpu(src_cpu, fn, RUN_ON_CPU_TARGET_PTR(addr_and_mmu_idx));
|
||||
}
|
||||
|
||||
void tlb_flush_page_all_cpus_synced(CPUState *src, target_ulong addr)
|
||||
@@ -727,7 +620,7 @@ void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length)
|
||||
qemu_spin_lock(&env_tlb(env)->c.lock);
|
||||
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
|
||||
unsigned int i;
|
||||
unsigned int n = tlb_n_entries(&env_tlb(env)->f[mmu_idx]);
|
||||
unsigned int n = tlb_n_entries(env, mmu_idx);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
tlb_reset_dirty_range_locked(&env_tlb(env)->f[mmu_idx].table[i],
|
||||
@@ -1732,137 +1625,6 @@ tcg_target_ulong helper_be_ldsl_mmu(CPUArchState *env, target_ulong addr,
|
||||
return (int32_t)helper_be_ldul_mmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Load helpers for cpu_ldst.h.
|
||||
*/
|
||||
|
||||
static inline uint64_t cpu_load_helper(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t retaddr,
|
||||
MemOp op, FullLoadHelper *full_load)
|
||||
{
|
||||
uint16_t meminfo;
|
||||
TCGMemOpIdx oi;
|
||||
uint64_t ret;
|
||||
|
||||
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, meminfo);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return cpu_load_helper(env, addr, mmu_idx, ra, MO_UB, full_ldub_mmu);
|
||||
}
|
||||
|
||||
int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return (int8_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_SB,
|
||||
full_ldub_mmu);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return cpu_load_helper(env, addr, mmu_idx, ra, MO_TEUW,
|
||||
MO_TE == MO_LE
|
||||
? full_le_lduw_mmu : full_be_lduw_mmu);
|
||||
}
|
||||
|
||||
int cpu_ldsw_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return (int16_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_TESW,
|
||||
MO_TE == MO_LE
|
||||
? full_le_lduw_mmu : full_be_lduw_mmu);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return cpu_load_helper(env, addr, mmu_idx, ra, MO_TEUL,
|
||||
MO_TE == MO_LE
|
||||
? full_le_ldul_mmu : full_be_ldul_mmu);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return cpu_load_helper(env, addr, mmu_idx, ra, MO_TEQ,
|
||||
MO_TE == MO_LE
|
||||
? helper_le_ldq_mmu : helper_be_ldq_mmu);
|
||||
}
|
||||
|
||||
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_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
return cpu_lduw_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
int cpu_ldsw_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
|
||||
{
|
||||
return cpu_ldsw_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
|
||||
{
|
||||
return cpu_ldl_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
|
||||
{
|
||||
return cpu_ldq_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_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_lduw_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
int cpu_ldsw_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_ldsw_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_ldl_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_data(CPUArchState *env, target_ulong ptr)
|
||||
{
|
||||
return cpu_ldq_data_ra(env, ptr, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Store Helpers
|
||||
*/
|
||||
@@ -2092,94 +1854,6 @@ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
store_helper(env, addr, val, oi, retaddr, MO_BEQ);
|
||||
}
|
||||
|
||||
/*
|
||||
* Store Helpers for cpu_ldst.h
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
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_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_UB);
|
||||
}
|
||||
|
||||
void cpu_stw_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_TEUW);
|
||||
}
|
||||
|
||||
void cpu_stl_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_TEUL);
|
||||
}
|
||||
|
||||
void cpu_stq_mmuidx_ra(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_TEQ);
|
||||
}
|
||||
|
||||
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_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
cpu_stw_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
void cpu_stl_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
cpu_stl_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
void cpu_stq_data_ra(CPUArchState *env, target_ulong ptr,
|
||||
uint64_t val, uintptr_t retaddr)
|
||||
{
|
||||
cpu_stq_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
|
||||
}
|
||||
|
||||
void cpu_stb_data(CPUArchState *env, target_ulong ptr, uint32_t val)
|
||||
{
|
||||
cpu_stb_data_ra(env, ptr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stw_data(CPUArchState *env, target_ulong ptr, uint32_t val)
|
||||
{
|
||||
cpu_stw_data_ra(env, ptr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stl_data(CPUArchState *env, target_ulong ptr, uint32_t val)
|
||||
{
|
||||
cpu_stl_data_ra(env, ptr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stq_data(CPUArchState *env, target_ulong ptr, uint64_t val)
|
||||
{
|
||||
cpu_stq_data_ra(env, ptr, val, 0);
|
||||
}
|
||||
|
||||
/* First set of helpers allows passing in of OI and RETADDR. This makes
|
||||
them callable from other helpers. */
|
||||
|
||||
@@ -2238,50 +1912,98 @@ void cpu_stq_data(CPUArchState *env, target_ulong ptr, uint64_t val)
|
||||
|
||||
/* Code access functions. */
|
||||
|
||||
static uint64_t full_ldub_code(CPUArchState *env, target_ulong addr,
|
||||
static uint64_t full_ldub_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_8, true, full_ldub_code);
|
||||
return load_helper(env, addr, oi, retaddr, MO_8, true, full_ldub_cmmu);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr)
|
||||
uint8_t helper_ret_ldub_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
TCGMemOpIdx oi = make_memop_idx(MO_UB, cpu_mmu_index(env, true));
|
||||
return full_ldub_code(env, addr, oi, 0);
|
||||
return full_ldub_cmmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
static uint64_t full_lduw_code(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
int8_t helper_ret_ldsb_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_TEUW, true, full_lduw_code);
|
||||
return (int8_t) full_ldub_cmmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr)
|
||||
static uint64_t full_le_lduw_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
TCGMemOpIdx oi = make_memop_idx(MO_TEUW, cpu_mmu_index(env, true));
|
||||
return full_lduw_code(env, addr, oi, 0);
|
||||
return load_helper(env, addr, oi, retaddr, MO_LEUW, true,
|
||||
full_le_lduw_cmmu);
|
||||
}
|
||||
|
||||
static uint64_t full_ldl_code(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
uint16_t helper_le_lduw_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_TEUL, true, full_ldl_code);
|
||||
return full_le_lduw_cmmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr)
|
||||
int16_t helper_le_ldsw_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
TCGMemOpIdx oi = make_memop_idx(MO_TEUL, cpu_mmu_index(env, true));
|
||||
return full_ldl_code(env, addr, oi, 0);
|
||||
return (int16_t) full_le_lduw_cmmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
static uint64_t full_ldq_code(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
static uint64_t full_be_lduw_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_TEQ, true, full_ldq_code);
|
||||
return load_helper(env, addr, oi, retaddr, MO_BEUW, true,
|
||||
full_be_lduw_cmmu);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr)
|
||||
uint16_t helper_be_lduw_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
TCGMemOpIdx oi = make_memop_idx(MO_TEQ, cpu_mmu_index(env, true));
|
||||
return full_ldq_code(env, addr, oi, 0);
|
||||
return full_be_lduw_cmmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
int16_t helper_be_ldsw_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return (int16_t) full_be_lduw_cmmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
static uint64_t full_le_ldul_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_LEUL, true,
|
||||
full_le_ldul_cmmu);
|
||||
}
|
||||
|
||||
uint32_t helper_le_ldl_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return full_le_ldul_cmmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
static uint64_t full_be_ldul_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_BEUL, true,
|
||||
full_be_ldul_cmmu);
|
||||
}
|
||||
|
||||
uint32_t helper_be_ldl_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return full_be_ldul_cmmu(env, addr, oi, retaddr);
|
||||
}
|
||||
|
||||
uint64_t helper_le_ldq_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_LEQ, true,
|
||||
helper_le_ldq_cmmu);
|
||||
}
|
||||
|
||||
uint64_t helper_be_ldq_cmmu(CPUArchState *env, target_ulong addr,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_BEQ, true,
|
||||
helper_be_ldq_cmmu);
|
||||
}
|
||||
+4
-145
@@ -30,23 +30,8 @@
|
||||
#include "cpu.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qapi/qapi-builtin-visit.h"
|
||||
|
||||
typedef struct TCGState {
|
||||
AccelState parent_obj;
|
||||
|
||||
bool mttcg_enabled;
|
||||
unsigned long tb_size;
|
||||
} TCGState;
|
||||
|
||||
#define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg")
|
||||
|
||||
#define TCG_STATE(obj) \
|
||||
OBJECT_CHECK(TCGState, (obj), TYPE_TCG_ACCEL)
|
||||
unsigned long tcg_tb_size;
|
||||
|
||||
/* mask must never be zero, except for A20 change call */
|
||||
static void tcg_handle_interrupt(CPUState *cpu, int mask)
|
||||
@@ -73,153 +58,27 @@ static void tcg_handle_interrupt(CPUState *cpu, int mask)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We default to false if we know other options have been enabled
|
||||
* which are currently incompatible with MTTCG. Otherwise when each
|
||||
* guest (target) has been updated to support:
|
||||
* - atomic instructions
|
||||
* - memory ordering primitives (barriers)
|
||||
* they can set the appropriate CONFIG flags in ${target}-softmmu.mak
|
||||
*
|
||||
* Once a guest architecture has been converted to the new primitives
|
||||
* there are two remaining limitations to check.
|
||||
*
|
||||
* - The guest can't be oversized (e.g. 64 bit guest on 32 bit host)
|
||||
* - The host must have a stronger memory order than the guest
|
||||
*
|
||||
* It may be possible in future to support strong guests on weak hosts
|
||||
* but that will require tagging all load/stores in a guest with their
|
||||
* implicit memory order requirements which would likely slow things
|
||||
* down a lot.
|
||||
*/
|
||||
|
||||
static bool check_tcg_memory_orders_compatible(void)
|
||||
{
|
||||
#if defined(TCG_GUEST_DEFAULT_MO) && defined(TCG_TARGET_DEFAULT_MO)
|
||||
return (TCG_GUEST_DEFAULT_MO & ~TCG_TARGET_DEFAULT_MO) == 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool default_mttcg_enabled(void)
|
||||
{
|
||||
if (use_icount || TCG_OVERSIZED_GUEST) {
|
||||
return false;
|
||||
} else {
|
||||
#ifdef TARGET_SUPPORTS_MTTCG
|
||||
return check_tcg_memory_orders_compatible();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_accel_instance_init(Object *obj)
|
||||
{
|
||||
TCGState *s = TCG_STATE(obj);
|
||||
|
||||
s->mttcg_enabled = default_mttcg_enabled();
|
||||
}
|
||||
|
||||
static int tcg_init(MachineState *ms)
|
||||
{
|
||||
TCGState *s = TCG_STATE(current_accel());
|
||||
|
||||
tcg_exec_init(s->tb_size * 1024 * 1024);
|
||||
tcg_exec_init(tcg_tb_size * 1024 * 1024);
|
||||
cpu_interrupt_handler = tcg_handle_interrupt;
|
||||
mttcg_enabled = s->mttcg_enabled;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *tcg_get_thread(Object *obj, Error **errp)
|
||||
{
|
||||
TCGState *s = TCG_STATE(obj);
|
||||
|
||||
return g_strdup(s->mttcg_enabled ? "multi" : "single");
|
||||
}
|
||||
|
||||
static void tcg_set_thread(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
TCGState *s = TCG_STATE(obj);
|
||||
|
||||
if (strcmp(value, "multi") == 0) {
|
||||
if (TCG_OVERSIZED_GUEST) {
|
||||
error_setg(errp, "No MTTCG when guest word size > hosts");
|
||||
} else if (use_icount) {
|
||||
error_setg(errp, "No MTTCG when icount is enabled");
|
||||
} else {
|
||||
#ifndef TARGET_SUPPORTS_MTTCG
|
||||
warn_report("Guest not yet converted to MTTCG - "
|
||||
"you may get unexpected results");
|
||||
#endif
|
||||
if (!check_tcg_memory_orders_compatible()) {
|
||||
warn_report("Guest expects a stronger memory ordering "
|
||||
"than the host provides");
|
||||
error_printf("This may cause strange/hard to debug errors\n");
|
||||
}
|
||||
s->mttcg_enabled = true;
|
||||
}
|
||||
} else if (strcmp(value, "single") == 0) {
|
||||
s->mttcg_enabled = false;
|
||||
} else {
|
||||
error_setg(errp, "Invalid 'thread' setting %s", value);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_get_tb_size(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
TCGState *s = TCG_STATE(obj);
|
||||
uint32_t value = s->tb_size;
|
||||
|
||||
visit_type_uint32(v, name, &value, errp);
|
||||
}
|
||||
|
||||
static void tcg_set_tb_size(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
TCGState *s = TCG_STATE(obj);
|
||||
Error *error = NULL;
|
||||
uint32_t value;
|
||||
|
||||
visit_type_uint32(v, name, &value, &error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
return;
|
||||
}
|
||||
|
||||
s->tb_size = value;
|
||||
}
|
||||
|
||||
static void tcg_accel_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelClass *ac = ACCEL_CLASS(oc);
|
||||
ac->name = "tcg";
|
||||
ac->init_machine = tcg_init;
|
||||
ac->allowed = &tcg_allowed;
|
||||
|
||||
object_class_property_add_str(oc, "thread",
|
||||
tcg_get_thread,
|
||||
tcg_set_thread,
|
||||
NULL);
|
||||
|
||||
object_class_property_add(oc, "tb-size", "int",
|
||||
tcg_get_tb_size, tcg_set_tb_size,
|
||||
NULL, NULL, &error_abort);
|
||||
object_class_property_set_description(oc, "tb-size",
|
||||
"TCG translation block cache size", &error_abort);
|
||||
|
||||
}
|
||||
|
||||
#define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg")
|
||||
|
||||
static const TypeInfo tcg_accel_type = {
|
||||
.name = TYPE_TCG_ACCEL,
|
||||
.parent = TYPE_ACCEL,
|
||||
.instance_init = tcg_accel_instance_init,
|
||||
.class_init = tcg_accel_class_init,
|
||||
.instance_size = sizeof(TCGState),
|
||||
};
|
||||
|
||||
static void register_accel_types(void)
|
||||
|
||||
+183
-117
@@ -21,9 +21,51 @@
|
||||
#include "qemu/host-utils.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "tcg/tcg-gvec-desc.h"
|
||||
#include "tcg-gvec-desc.h"
|
||||
|
||||
|
||||
/* Virtually all hosts support 16-byte vectors. Those that don't can emulate
|
||||
* them via GCC's generic vector extension. This turns out to be simpler and
|
||||
* more reliable than getting the compiler to autovectorize.
|
||||
*
|
||||
* In tcg-op-gvec.c, we asserted that both the size and alignment of the data
|
||||
* are multiples of 16.
|
||||
*
|
||||
* When the compiler does not support all of the operations we require, the
|
||||
* loops are written so that we can always fall back on the base types.
|
||||
*/
|
||||
#ifdef CONFIG_VECTOR16
|
||||
typedef uint8_t vec8 __attribute__((vector_size(16)));
|
||||
typedef uint16_t vec16 __attribute__((vector_size(16)));
|
||||
typedef uint32_t vec32 __attribute__((vector_size(16)));
|
||||
typedef uint64_t vec64 __attribute__((vector_size(16)));
|
||||
|
||||
typedef int8_t svec8 __attribute__((vector_size(16)));
|
||||
typedef int16_t svec16 __attribute__((vector_size(16)));
|
||||
typedef int32_t svec32 __attribute__((vector_size(16)));
|
||||
typedef int64_t svec64 __attribute__((vector_size(16)));
|
||||
|
||||
#define DUP16(X) { X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X }
|
||||
#define DUP8(X) { X, X, X, X, X, X, X, X }
|
||||
#define DUP4(X) { X, X, X, X }
|
||||
#define DUP2(X) { X, X }
|
||||
#else
|
||||
typedef uint8_t vec8;
|
||||
typedef uint16_t vec16;
|
||||
typedef uint32_t vec32;
|
||||
typedef uint64_t vec64;
|
||||
|
||||
typedef int8_t svec8;
|
||||
typedef int16_t svec16;
|
||||
typedef int32_t svec32;
|
||||
typedef int64_t svec64;
|
||||
|
||||
#define DUP16(X) X
|
||||
#define DUP8(X) X
|
||||
#define DUP4(X) X
|
||||
#define DUP2(X) X
|
||||
#endif /* CONFIG_VECTOR16 */
|
||||
|
||||
static inline void clear_high(void *d, intptr_t oprsz, uint32_t desc)
|
||||
{
|
||||
intptr_t maxsz = simd_maxsz(desc);
|
||||
@@ -41,8 +83,8 @@ void HELPER(gvec_add8)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) + *(uint8_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) + *(vec8 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -52,8 +94,8 @@ void HELPER(gvec_add16)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) + *(uint16_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) + *(vec16 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -63,8 +105,8 @@ void HELPER(gvec_add32)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) + *(uint32_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) + *(vec32 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -74,8 +116,8 @@ void HELPER(gvec_add64)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) + *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) + *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -83,10 +125,11 @@ void HELPER(gvec_add64)(void *d, void *a, void *b, uint32_t desc)
|
||||
void HELPER(gvec_adds8)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec8 vecb = (vec8)DUP16(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) + (uint8_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) + vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -94,10 +137,11 @@ void HELPER(gvec_adds8)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_adds16)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec16 vecb = (vec16)DUP8(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) + (uint16_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) + vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -105,10 +149,11 @@ void HELPER(gvec_adds16)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_adds32)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec32 vecb = (vec32)DUP4(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) + (uint32_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) + vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -116,10 +161,11 @@ void HELPER(gvec_adds32)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_adds64)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec64 vecb = (vec64)DUP2(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) + b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) + vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -129,8 +175,8 @@ void HELPER(gvec_sub8)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) - *(uint8_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) - *(vec8 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -140,8 +186,8 @@ void HELPER(gvec_sub16)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) - *(uint16_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) - *(vec16 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -151,8 +197,8 @@ void HELPER(gvec_sub32)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) - *(uint32_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) - *(vec32 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -162,8 +208,8 @@ void HELPER(gvec_sub64)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) - *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) - *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -171,10 +217,11 @@ void HELPER(gvec_sub64)(void *d, void *a, void *b, uint32_t desc)
|
||||
void HELPER(gvec_subs8)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec8 vecb = (vec8)DUP16(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) - (uint8_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) - vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -182,10 +229,11 @@ void HELPER(gvec_subs8)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_subs16)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec16 vecb = (vec16)DUP8(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) - (uint16_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) - vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -193,10 +241,11 @@ void HELPER(gvec_subs16)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_subs32)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec32 vecb = (vec32)DUP4(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) - (uint32_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) - vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -204,10 +253,11 @@ void HELPER(gvec_subs32)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_subs64)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec64 vecb = (vec64)DUP2(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) - b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) - vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -217,8 +267,8 @@ void HELPER(gvec_mul8)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) * *(uint8_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) * *(vec8 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -228,8 +278,8 @@ void HELPER(gvec_mul16)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) * *(uint16_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) * *(vec16 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -239,8 +289,8 @@ void HELPER(gvec_mul32)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) * *(uint32_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) * *(vec32 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -250,8 +300,8 @@ void HELPER(gvec_mul64)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) * *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) * *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -259,10 +309,11 @@ void HELPER(gvec_mul64)(void *d, void *a, void *b, uint32_t desc)
|
||||
void HELPER(gvec_muls8)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec8 vecb = (vec8)DUP16(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) * (uint8_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) * vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -270,10 +321,11 @@ void HELPER(gvec_muls8)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_muls16)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec16 vecb = (vec16)DUP8(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) * (uint16_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) * vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -281,10 +333,11 @@ void HELPER(gvec_muls16)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_muls32)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec32 vecb = (vec32)DUP4(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) * (uint32_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) * vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -292,10 +345,11 @@ void HELPER(gvec_muls32)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_muls64)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec64 vecb = (vec64)DUP2(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) * b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) * vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -305,8 +359,8 @@ void HELPER(gvec_neg8)(void *d, void *a, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = -*(uint8_t *)(a + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = -*(vec8 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -316,8 +370,8 @@ void HELPER(gvec_neg16)(void *d, void *a, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = -*(uint16_t *)(a + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = -*(vec16 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -327,8 +381,8 @@ void HELPER(gvec_neg32)(void *d, void *a, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = -*(uint32_t *)(a + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = -*(vec32 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -338,8 +392,8 @@ void HELPER(gvec_neg64)(void *d, void *a, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = -*(uint64_t *)(a + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = -*(vec64 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -445,8 +499,8 @@ void HELPER(gvec_not)(void *d, void *a, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = ~*(uint64_t *)(a + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = ~*(vec64 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -456,8 +510,8 @@ void HELPER(gvec_and)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) & *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) & *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -467,8 +521,8 @@ void HELPER(gvec_or)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) | *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) | *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -478,8 +532,8 @@ void HELPER(gvec_xor)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) ^ *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) ^ *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -489,8 +543,8 @@ void HELPER(gvec_andc)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) &~ *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) &~ *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -500,8 +554,8 @@ void HELPER(gvec_orc)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) |~ *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) |~ *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -511,8 +565,8 @@ void HELPER(gvec_nand)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = ~(*(uint64_t *)(a + i) & *(uint64_t *)(b + i));
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = ~(*(vec64 *)(a + i) & *(vec64 *)(b + i));
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -522,8 +576,8 @@ void HELPER(gvec_nor)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = ~(*(uint64_t *)(a + i) | *(uint64_t *)(b + i));
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = ~(*(vec64 *)(a + i) | *(vec64 *)(b + i));
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -533,8 +587,8 @@ void HELPER(gvec_eqv)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = ~(*(uint64_t *)(a + i) ^ *(uint64_t *)(b + i));
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = ~(*(vec64 *)(a + i) ^ *(vec64 *)(b + i));
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -542,10 +596,11 @@ void HELPER(gvec_eqv)(void *d, void *a, void *b, uint32_t desc)
|
||||
void HELPER(gvec_ands)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec64 vecb = (vec64)DUP2(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) & b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) & vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -553,10 +608,11 @@ void HELPER(gvec_ands)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_xors)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec64 vecb = (vec64)DUP2(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) ^ b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) ^ vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -564,10 +620,11 @@ void HELPER(gvec_xors)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_ors)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec64 vecb = (vec64)DUP2(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) | b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) | vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -578,8 +635,8 @@ void HELPER(gvec_shl8i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) << shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) << shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -590,8 +647,8 @@ void HELPER(gvec_shl16i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) << shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) << shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -602,8 +659,8 @@ void HELPER(gvec_shl32i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) << shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) << shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -614,8 +671,8 @@ void HELPER(gvec_shl64i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) << shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) << shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -626,8 +683,8 @@ void HELPER(gvec_shr8i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -638,8 +695,8 @@ void HELPER(gvec_shr16i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -650,8 +707,8 @@ void HELPER(gvec_shr32i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -662,8 +719,8 @@ void HELPER(gvec_shr64i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -674,8 +731,8 @@ void HELPER(gvec_sar8i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(int8_t *)(d + i) = *(int8_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(svec8 *)(d + i) = *(svec8 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -686,8 +743,8 @@ void HELPER(gvec_sar16i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(int16_t *)(d + i) = *(int16_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(svec16 *)(d + i) = *(svec16 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -698,8 +755,8 @@ void HELPER(gvec_sar32i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(int32_t *)(d + i) = *(int32_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(svec32 *)(d + i) = *(svec32 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -710,8 +767,8 @@ void HELPER(gvec_sar64i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(int64_t *)(d + i) = *(int64_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(svec64 *)(d + i) = *(svec64 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -860,30 +917,39 @@ void HELPER(gvec_sar64v)(void *d, void *a, void *b, uint32_t desc)
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
/* If vectors are enabled, the compiler fills in -1 for true.
|
||||
Otherwise, we must take care of this by hand. */
|
||||
#ifdef CONFIG_VECTOR16
|
||||
# define DO_CMP0(X) X
|
||||
#else
|
||||
# define DO_CMP0(X) -(X)
|
||||
#endif
|
||||
|
||||
#define DO_CMP1(NAME, TYPE, OP) \
|
||||
void HELPER(NAME)(void *d, void *a, void *b, uint32_t desc) \
|
||||
{ \
|
||||
intptr_t oprsz = simd_oprsz(desc); \
|
||||
intptr_t i; \
|
||||
for (i = 0; i < oprsz; i += sizeof(TYPE)) { \
|
||||
*(TYPE *)(d + i) = -(*(TYPE *)(a + i) OP *(TYPE *)(b + i)); \
|
||||
*(TYPE *)(d + i) = DO_CMP0(*(TYPE *)(a + i) OP *(TYPE *)(b + i)); \
|
||||
} \
|
||||
clear_high(d, oprsz, desc); \
|
||||
}
|
||||
|
||||
#define DO_CMP2(SZ) \
|
||||
DO_CMP1(gvec_eq##SZ, uint##SZ##_t, ==) \
|
||||
DO_CMP1(gvec_ne##SZ, uint##SZ##_t, !=) \
|
||||
DO_CMP1(gvec_lt##SZ, int##SZ##_t, <) \
|
||||
DO_CMP1(gvec_le##SZ, int##SZ##_t, <=) \
|
||||
DO_CMP1(gvec_ltu##SZ, uint##SZ##_t, <) \
|
||||
DO_CMP1(gvec_leu##SZ, uint##SZ##_t, <=)
|
||||
DO_CMP1(gvec_eq##SZ, vec##SZ, ==) \
|
||||
DO_CMP1(gvec_ne##SZ, vec##SZ, !=) \
|
||||
DO_CMP1(gvec_lt##SZ, svec##SZ, <) \
|
||||
DO_CMP1(gvec_le##SZ, svec##SZ, <=) \
|
||||
DO_CMP1(gvec_ltu##SZ, vec##SZ, <) \
|
||||
DO_CMP1(gvec_leu##SZ, vec##SZ, <=)
|
||||
|
||||
DO_CMP2(8)
|
||||
DO_CMP2(16)
|
||||
DO_CMP2(32)
|
||||
DO_CMP2(64)
|
||||
|
||||
#undef DO_CMP0
|
||||
#undef DO_CMP1
|
||||
#undef DO_CMP2
|
||||
|
||||
@@ -1384,11 +1450,11 @@ void HELPER(gvec_bitsel)(void *d, void *a, void *b, void *c, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
uint64_t aa = *(uint64_t *)(a + i);
|
||||
uint64_t bb = *(uint64_t *)(b + i);
|
||||
uint64_t cc = *(uint64_t *)(c + i);
|
||||
*(uint64_t *)(d + i) = (bb & aa) | (cc & ~aa);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
vec64 aa = *(vec64 *)(a + i);
|
||||
vec64 bb = *(vec64 *)(b + i);
|
||||
vec64 cc = *(vec64 *)(c + i);
|
||||
*(vec64 *)(d + i) = (bb & aa) | (cc & ~aa);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "exec/tb-lookup.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/log.h"
|
||||
#include "tcg/tcg.h"
|
||||
|
||||
/* 32-bit helpers */
|
||||
|
||||
|
||||
+60
-44
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu-common.h"
|
||||
|
||||
#define NO_CPU_IO_DEFS
|
||||
@@ -26,7 +25,7 @@
|
||||
#include "trace.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "tcg.h"
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#include "qemu.h"
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
@@ -892,61 +891,43 @@ static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
/* Currently it is not recommended to allocate big chunks of data in
|
||||
user mode. It will change when a dedicated libc will be used. */
|
||||
/* ??? 64-bit hosts ought to have no problem mmaping data outside the
|
||||
region in which the guest needs to run. Revisit this. */
|
||||
#define USE_STATIC_CODE_GEN_BUFFER
|
||||
#endif
|
||||
|
||||
/* Minimum size of the code gen buffer. This number is randomly chosen,
|
||||
but not so small that we can't have a fair number of TB's live. */
|
||||
#define MIN_CODE_GEN_BUFFER_SIZE (1 * MiB)
|
||||
#define MIN_CODE_GEN_BUFFER_SIZE (1024u * 1024)
|
||||
|
||||
/* Maximum size of the code gen buffer we'd like to use. Unless otherwise
|
||||
indicated, this is constrained by the range of direct branches on the
|
||||
host cpu, as used by the TCG implementation of goto_tb. */
|
||||
#if defined(__x86_64__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024)
|
||||
#elif defined(__sparc__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024)
|
||||
#elif defined(__powerpc64__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024)
|
||||
#elif defined(__powerpc__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (32 * MiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (32u * 1024 * 1024)
|
||||
#elif defined(__aarch64__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024)
|
||||
#elif defined(__s390x__)
|
||||
/* We have a +- 4GB range on the branches; leave some slop. */
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (3 * GiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (3ul * 1024 * 1024 * 1024)
|
||||
#elif defined(__mips__)
|
||||
/* We have a 256MB branch region, but leave room to make sure the
|
||||
main executable is also within that region. */
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (128 * MiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (128ul * 1024 * 1024)
|
||||
#else
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
|
||||
#endif
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (32 * MiB)
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/*
|
||||
* For user mode on smaller 32 bit systems we may run into trouble
|
||||
* allocating big chunks of data in the right place. On these systems
|
||||
* we utilise a static code generation buffer directly in the binary.
|
||||
*/
|
||||
#define USE_STATIC_CODE_GEN_BUFFER
|
||||
#endif
|
||||
#else /* TCG_TARGET_REG_BITS == 64 */
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/*
|
||||
* As user-mode emulation typically means running multiple instances
|
||||
* of the translator don't go too nuts with our default code gen
|
||||
* buffer lest we make things too hard for the OS.
|
||||
*/
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (128 * MiB)
|
||||
#else
|
||||
/*
|
||||
* We expect most system emulation to run one or two guests per host.
|
||||
* Users running large scale system emulation may want to tweak their
|
||||
* runtime setup via the tb-size control on the command line.
|
||||
*/
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (1 * GiB)
|
||||
#endif
|
||||
#endif
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (32u * 1024 * 1024)
|
||||
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE \
|
||||
(DEFAULT_CODE_GEN_BUFFER_SIZE_1 < MAX_CODE_GEN_BUFFER_SIZE \
|
||||
@@ -956,7 +937,15 @@ static inline size_t size_code_gen_buffer(size_t tb_size)
|
||||
{
|
||||
/* Size the buffer. */
|
||||
if (tb_size == 0) {
|
||||
#ifdef USE_STATIC_CODE_GEN_BUFFER
|
||||
tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
|
||||
#else
|
||||
/* ??? Needs adjustments. */
|
||||
/* ??? If we relax the requirement that CONFIG_USER_ONLY use the
|
||||
static buffer, we could size this on RESERVED_VA, on the text
|
||||
segment size of the executable, or continue to use the default. */
|
||||
tb_size = (unsigned long)(ram_size / 4);
|
||||
#endif
|
||||
}
|
||||
if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) {
|
||||
tb_size = MIN_CODE_GEN_BUFFER_SIZE;
|
||||
@@ -1043,20 +1032,47 @@ static inline void *alloc_code_gen_buffer(void)
|
||||
{
|
||||
int prot = PROT_WRITE | PROT_READ | PROT_EXEC;
|
||||
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
uintptr_t start = 0;
|
||||
size_t size = tcg_ctx->code_gen_buffer_size;
|
||||
void *buf;
|
||||
|
||||
buf = mmap(NULL, size, prot, flags, -1, 0);
|
||||
/* Constrain the position of the buffer based on the host cpu.
|
||||
Note that these addresses are chosen in concert with the
|
||||
addresses assigned in the relevant linker script file. */
|
||||
# if defined(__PIE__) || defined(__PIC__)
|
||||
/* Don't bother setting a preferred location if we're building
|
||||
a position-independent executable. We're more likely to get
|
||||
an address near the main executable if we let the kernel
|
||||
choose the address. */
|
||||
# elif defined(__x86_64__) && defined(MAP_32BIT)
|
||||
/* Force the memory down into low memory with the executable.
|
||||
Leave the choice of exact location with the kernel. */
|
||||
flags |= MAP_32BIT;
|
||||
/* Cannot expect to map more than 800MB in low memory. */
|
||||
if (size > 800u * 1024 * 1024) {
|
||||
tcg_ctx->code_gen_buffer_size = size = 800u * 1024 * 1024;
|
||||
}
|
||||
# elif defined(__sparc__)
|
||||
start = 0x40000000ul;
|
||||
# elif defined(__s390x__)
|
||||
start = 0x90000000ul;
|
||||
# elif defined(__mips__)
|
||||
# if _MIPS_SIM == _ABI64
|
||||
start = 0x128000000ul;
|
||||
# else
|
||||
start = 0x08000000ul;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
buf = mmap((void *)start, size, prot, flags, -1, 0);
|
||||
if (buf == MAP_FAILED) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef __mips__
|
||||
if (cross_256mb(buf, size)) {
|
||||
/*
|
||||
* Try again, with the original still mapped, to avoid re-acquiring
|
||||
* the same 256mb crossing.
|
||||
*/
|
||||
/* Try again, with the original still mapped, to avoid re-acquiring
|
||||
that 256mb crossing. This time don't specify an address. */
|
||||
size_t size2;
|
||||
void *buf2 = mmap(NULL, size, prot, flags, -1, 0);
|
||||
switch ((int)(buf2 != MAP_FAILED)) {
|
||||
@@ -1788,7 +1804,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
#ifdef DEBUG_DISAS
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM) &&
|
||||
qemu_log_in_addr_range(tb->pc)) {
|
||||
FILE *logfile = qemu_log_lock();
|
||||
qemu_log_lock();
|
||||
qemu_log("OUT: [size=%d]\n", gen_code_size);
|
||||
if (tcg_ctx->data_gen_ptr) {
|
||||
size_t code_size = tcg_ctx->data_gen_ptr - tb->tc.ptr;
|
||||
@@ -1813,7 +1829,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
}
|
||||
qemu_log("\n");
|
||||
qemu_log_flush();
|
||||
qemu_log_unlock(logfile);
|
||||
qemu_log_unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -138,11 +138,11 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
#ifdef DEBUG_DISAS
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
|
||||
&& qemu_log_in_addr_range(db->pc_first)) {
|
||||
FILE *logfile = qemu_log_lock();
|
||||
qemu_log_lock();
|
||||
qemu_log("----------------\n");
|
||||
ops->disas_log(db, cpu);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock(logfile);
|
||||
qemu_log_unlock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
+1
-237
@@ -20,14 +20,12 @@
|
||||
#include "cpu.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "tcg.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "translate-all.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "qemu/atomic128.h"
|
||||
#include "trace-root.h"
|
||||
#include "trace/mem.h"
|
||||
|
||||
#undef EAX
|
||||
#undef ECX
|
||||
@@ -736,240 +734,6 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
|
||||
/* The softmmu versions of these helpers are in cputlb.c. */
|
||||
|
||||
uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_UB, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldub_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cpu_ldsb_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
int ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_SB, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldsb_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_TEUW, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = lduw_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cpu_ldsw_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
int ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_TESW, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldsw_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_TEUL, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldl_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint64_t ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_TEQ, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldq_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_ldub_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_ldub_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cpu_ldsb_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_ldsb_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_lduw_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cpu_ldsw_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_ldsw_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_ldl_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
uint64_t ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_ldq_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cpu_stb_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
|
||||
{
|
||||
uint16_t meminfo = trace_mem_get_info(MO_UB, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stb_p(g2h(ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
void cpu_stw_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
|
||||
{
|
||||
uint16_t meminfo = trace_mem_get_info(MO_TEUW, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stw_p(g2h(ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
void cpu_stl_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
|
||||
{
|
||||
uint16_t meminfo = trace_mem_get_info(MO_TEUL, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stl_p(g2h(ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
void cpu_stq_data(CPUArchState *env, abi_ptr ptr, uint64_t val)
|
||||
{
|
||||
uint16_t meminfo = trace_mem_get_info(MO_TEQ, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stq_p(g2h(ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
void cpu_stb_data_ra(CPUArchState *env, abi_ptr ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
set_helper_retaddr(retaddr);
|
||||
cpu_stb_data(env, ptr, val);
|
||||
clear_helper_retaddr();
|
||||
}
|
||||
|
||||
void cpu_stw_data_ra(CPUArchState *env, abi_ptr ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
set_helper_retaddr(retaddr);
|
||||
cpu_stw_data(env, ptr, val);
|
||||
clear_helper_retaddr();
|
||||
}
|
||||
|
||||
void cpu_stl_data_ra(CPUArchState *env, abi_ptr ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
set_helper_retaddr(retaddr);
|
||||
cpu_stl_data(env, ptr, val);
|
||||
clear_helper_retaddr();
|
||||
}
|
||||
|
||||
void cpu_stq_data_ra(CPUArchState *env, abi_ptr ptr,
|
||||
uint64_t val, uintptr_t retaddr)
|
||||
{
|
||||
set_helper_retaddr(retaddr);
|
||||
cpu_stq_data(env, ptr, val);
|
||||
clear_helper_retaddr();
|
||||
}
|
||||
|
||||
uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(1);
|
||||
ret = ldub_p(g2h(ptr));
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(1);
|
||||
ret = lduw_p(g2h(ptr));
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(1);
|
||||
ret = ldl_p(g2h(ptr));
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint64_t ret;
|
||||
|
||||
set_helper_retaddr(1);
|
||||
ret = ldq_p(g2h(ptr));
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Do not allow unaligned operations to proceed. Return the host address. */
|
||||
static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
|
||||
int size, uintptr_t retaddr)
|
||||
|
||||
@@ -77,8 +77,6 @@ int graphic_depth = 32;
|
||||
#define QEMU_ARCH QEMU_ARCH_PPC
|
||||
#elif defined(TARGET_RISCV)
|
||||
#define QEMU_ARCH QEMU_ARCH_RISCV
|
||||
#elif defined(TARGET_RX)
|
||||
#define QEMU_ARCH QEMU_ARCH_RX
|
||||
#elif defined(TARGET_S390X)
|
||||
#define QEMU_ARCH QEMU_ARCH_S390X
|
||||
#elif defined(TARGET_SH4)
|
||||
|
||||
+2
-20
@@ -307,13 +307,6 @@ static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
|
||||
return SND_PCM_FORMAT_U32_LE;
|
||||
}
|
||||
|
||||
case AUDIO_FORMAT_F32:
|
||||
if (endianness) {
|
||||
return SND_PCM_FORMAT_FLOAT_BE;
|
||||
} else {
|
||||
return SND_PCM_FORMAT_FLOAT_LE;
|
||||
}
|
||||
|
||||
default:
|
||||
dolog ("Internal logic error: Bad audio format %d\n", fmt);
|
||||
#ifdef DEBUG_AUDIO
|
||||
@@ -377,16 +370,6 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt,
|
||||
*fmt = AUDIO_FORMAT_U32;
|
||||
break;
|
||||
|
||||
case SND_PCM_FORMAT_FLOAT_LE:
|
||||
*endianness = 0;
|
||||
*fmt = AUDIO_FORMAT_F32;
|
||||
break;
|
||||
|
||||
case SND_PCM_FORMAT_FLOAT_BE:
|
||||
*endianness = 1;
|
||||
*fmt = AUDIO_FORMAT_F32;
|
||||
break;
|
||||
|
||||
default:
|
||||
dolog ("Unrecognized audio format %d\n", alsafmt);
|
||||
return -1;
|
||||
@@ -819,7 +802,7 @@ static size_t alsa_read(HWVoiceIn *hw, void *buf, size_t len)
|
||||
switch (nread) {
|
||||
case 0:
|
||||
trace_alsa_read_zero(len);
|
||||
return pos;
|
||||
return pos;;
|
||||
|
||||
case -EPIPE:
|
||||
if (alsa_recover(alsa->handle)) {
|
||||
@@ -835,7 +818,7 @@ static size_t alsa_read(HWVoiceIn *hw, void *buf, size_t len)
|
||||
default:
|
||||
alsa_logerr(nread, "Failed to read %zu frames to %p\n",
|
||||
len, dst);
|
||||
return pos;
|
||||
return pos;;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -923,7 +906,6 @@ static struct audio_pcm_ops alsa_pcm_ops = {
|
||||
.init_out = alsa_init_out,
|
||||
.fini_out = alsa_fini_out,
|
||||
.write = alsa_write,
|
||||
.run_buffer_out = audio_generic_run_buffer_out,
|
||||
.enable_out = alsa_enable_out,
|
||||
|
||||
.init_in = alsa_init_in,
|
||||
|
||||
+65
-79
@@ -218,9 +218,6 @@ static void audio_print_settings (struct audsettings *as)
|
||||
case AUDIO_FORMAT_U32:
|
||||
AUD_log (NULL, "U32");
|
||||
break;
|
||||
case AUDIO_FORMAT_F32:
|
||||
AUD_log (NULL, "F32");
|
||||
break;
|
||||
default:
|
||||
AUD_log (NULL, "invalid(%d)", as->fmt);
|
||||
break;
|
||||
@@ -255,7 +252,6 @@ static int audio_validate_settings (struct audsettings *as)
|
||||
case AUDIO_FORMAT_U16:
|
||||
case AUDIO_FORMAT_S32:
|
||||
case AUDIO_FORMAT_U32:
|
||||
case AUDIO_FORMAT_F32:
|
||||
break;
|
||||
default:
|
||||
invalid = 1;
|
||||
@@ -268,28 +264,24 @@ static int audio_validate_settings (struct audsettings *as)
|
||||
|
||||
static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *as)
|
||||
{
|
||||
int bits = 8;
|
||||
bool is_signed = false, is_float = false;
|
||||
int bits = 8, sign = 0;
|
||||
|
||||
switch (as->fmt) {
|
||||
case AUDIO_FORMAT_S8:
|
||||
is_signed = true;
|
||||
sign = 1;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_U8:
|
||||
break;
|
||||
|
||||
case AUDIO_FORMAT_S16:
|
||||
is_signed = true;
|
||||
sign = 1;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_U16:
|
||||
bits = 16;
|
||||
break;
|
||||
|
||||
case AUDIO_FORMAT_F32:
|
||||
is_float = true;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_S32:
|
||||
is_signed = true;
|
||||
sign = 1;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_U32:
|
||||
bits = 32;
|
||||
@@ -300,38 +292,32 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *a
|
||||
}
|
||||
return info->freq == as->freq
|
||||
&& info->nchannels == as->nchannels
|
||||
&& info->is_signed == is_signed
|
||||
&& info->is_float == is_float
|
||||
&& info->sign == sign
|
||||
&& info->bits == bits
|
||||
&& info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
|
||||
}
|
||||
|
||||
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
||||
{
|
||||
int bits = 8, mul;
|
||||
bool is_signed = false, is_float = false;
|
||||
int bits = 8, sign = 0, mul;
|
||||
|
||||
switch (as->fmt) {
|
||||
case AUDIO_FORMAT_S8:
|
||||
is_signed = true;
|
||||
/* fall through */
|
||||
sign = 1;
|
||||
case AUDIO_FORMAT_U8:
|
||||
mul = 1;
|
||||
break;
|
||||
|
||||
case AUDIO_FORMAT_S16:
|
||||
is_signed = true;
|
||||
sign = 1;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_U16:
|
||||
bits = 16;
|
||||
mul = 2;
|
||||
break;
|
||||
|
||||
case AUDIO_FORMAT_F32:
|
||||
is_float = true;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_S32:
|
||||
is_signed = true;
|
||||
sign = 1;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_U32:
|
||||
bits = 32;
|
||||
@@ -344,8 +330,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
||||
|
||||
info->freq = as->freq;
|
||||
info->bits = bits;
|
||||
info->is_signed = is_signed;
|
||||
info->is_float = is_float;
|
||||
info->sign = sign;
|
||||
info->nchannels = as->nchannels;
|
||||
info->bytes_per_frame = as->nchannels * mul;
|
||||
info->bytes_per_second = info->freq * info->bytes_per_frame;
|
||||
@@ -358,7 +343,7 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->is_signed || info->is_float) {
|
||||
if (info->sign) {
|
||||
memset(buf, 0x00, len * info->bytes_per_frame);
|
||||
}
|
||||
else {
|
||||
@@ -784,9 +769,8 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
|
||||
#ifdef DEBUG_AUDIO
|
||||
static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
|
||||
{
|
||||
dolog("%s: bits %d, sign %d, float %d, freq %d, nchan %d\n",
|
||||
cap, info->bits, info->is_signed, info->is_float, info->freq,
|
||||
info->nchannels);
|
||||
dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n",
|
||||
cap, info->bits, info->sign, info->freq, info->nchannels);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -894,9 +878,9 @@ size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
int AUD_get_buffer_size_out(SWVoiceOut *sw)
|
||||
int AUD_get_buffer_size_out (SWVoiceOut *sw)
|
||||
{
|
||||
return sw->hw->samples * sw->hw->info.bytes_per_frame;
|
||||
return sw->hw->mix_buf->size * sw->hw->info.bytes_per_frame;
|
||||
}
|
||||
|
||||
void AUD_set_active_out (SWVoiceOut *sw, int on)
|
||||
@@ -1091,8 +1075,10 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
|
||||
while (live) {
|
||||
size_t size, decr, proc;
|
||||
void *buf = hw->pcm_ops->get_buffer_out(hw, &size);
|
||||
if (!buf || size == 0) {
|
||||
break;
|
||||
if (!buf) {
|
||||
/* retrying will likely won't help, drop everything. */
|
||||
hw->mix_buf->pos = (hw->mix_buf->pos + live) % hw->mix_buf->size;
|
||||
return clipped + live;
|
||||
}
|
||||
|
||||
decr = MIN(size / hw->info.bytes_per_frame, live);
|
||||
@@ -1110,10 +1096,6 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
|
||||
}
|
||||
}
|
||||
|
||||
if (hw->pcm_ops->run_buffer_out) {
|
||||
hw->pcm_ops->run_buffer_out(hw);
|
||||
}
|
||||
|
||||
return clipped;
|
||||
}
|
||||
|
||||
@@ -1420,8 +1402,7 @@ void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
||||
}
|
||||
assert(start >= 0 && start < hw->size_emul);
|
||||
|
||||
*size = MIN(*size, hw->pending_emul);
|
||||
*size = MIN(*size, hw->size_emul - start);
|
||||
*size = MIN(hw->pending_emul, hw->size_emul - start);
|
||||
return hw->buf_emul + start;
|
||||
}
|
||||
|
||||
@@ -1431,28 +1412,6 @@ void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
|
||||
hw->pending_emul -= size;
|
||||
}
|
||||
|
||||
void audio_generic_run_buffer_out(HWVoiceOut *hw)
|
||||
{
|
||||
while (hw->pending_emul) {
|
||||
size_t write_len, written;
|
||||
ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
|
||||
|
||||
if (start < 0) {
|
||||
start += hw->size_emul;
|
||||
}
|
||||
assert(start >= 0 && start < hw->size_emul);
|
||||
|
||||
write_len = MIN(hw->pending_emul, hw->size_emul - start);
|
||||
|
||||
written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);
|
||||
hw->pending_emul -= written;
|
||||
|
||||
if (written < write_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||
{
|
||||
if (unlikely(!hw->buf_emul)) {
|
||||
@@ -1468,7 +1427,8 @@ void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||
return hw->buf_emul + hw->pos_emul;
|
||||
}
|
||||
|
||||
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
|
||||
size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
|
||||
size_t size)
|
||||
{
|
||||
assert(buf == hw->buf_emul + hw->pos_emul &&
|
||||
size + hw->pending_emul <= hw->size_emul);
|
||||
@@ -1479,6 +1439,35 @@ size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
|
||||
{
|
||||
audio_generic_put_buffer_out_nowrite(hw, buf, size);
|
||||
|
||||
while (hw->pending_emul) {
|
||||
size_t write_len, written;
|
||||
ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
|
||||
if (start < 0) {
|
||||
start += hw->size_emul;
|
||||
}
|
||||
assert(start >= 0 && start < hw->size_emul);
|
||||
|
||||
write_len = MIN(hw->pending_emul, hw->size_emul - start);
|
||||
|
||||
written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);
|
||||
hw->pending_emul -= written;
|
||||
|
||||
if (written < write_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fake we have written everything. non-written data remain in pending_emul,
|
||||
* so we do not have to clip them multiple times
|
||||
*/
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
|
||||
{
|
||||
size_t dst_size, copy_size;
|
||||
@@ -1486,19 +1475,21 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
|
||||
copy_size = MIN(size, dst_size);
|
||||
|
||||
memcpy(dst, buf, copy_size);
|
||||
return hw->pcm_ops->put_buffer_out(hw, dst, copy_size);
|
||||
return hw->pcm_ops->put_buffer_out(hw, buf, copy_size);
|
||||
}
|
||||
|
||||
size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
|
||||
{
|
||||
void *src = hw->pcm_ops->get_buffer_in(hw, &size);
|
||||
size_t dst_size, copy_size;
|
||||
void *dst = hw->pcm_ops->get_buffer_in(hw, &dst_size);
|
||||
copy_size = MIN(size, dst_size);
|
||||
|
||||
memcpy(buf, src, size);
|
||||
hw->pcm_ops->put_buffer_in(hw, src, size);
|
||||
|
||||
return size;
|
||||
memcpy(dst, buf, copy_size);
|
||||
hw->pcm_ops->put_buffer_in(hw, buf, copy_size);
|
||||
return copy_size;
|
||||
}
|
||||
|
||||
|
||||
static int audio_driver_init(AudioState *s, struct audio_driver *drv,
|
||||
bool msg, Audiodev *dev)
|
||||
{
|
||||
@@ -1747,7 +1738,7 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
|
||||
if (dev->timer_period <= 0) {
|
||||
s->period_ticks = 1;
|
||||
} else {
|
||||
s->period_ticks = dev->timer_period * (int64_t)SCALE_US;
|
||||
s->period_ticks = dev->timer_period * SCALE_US;
|
||||
}
|
||||
|
||||
e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
|
||||
@@ -1845,15 +1836,11 @@ CaptureVoiceOut *AUD_add_capture(
|
||||
|
||||
cap->buf = g_malloc0_n(hw->mix_buf->size, hw->info.bytes_per_frame);
|
||||
|
||||
if (hw->info.is_float) {
|
||||
hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
|
||||
} else {
|
||||
hw->clip = mixeng_clip
|
||||
[hw->info.nchannels == 2]
|
||||
[hw->info.is_signed]
|
||||
[hw->info.swap_endianness]
|
||||
[audio_bits_to_index(hw->info.bits)];
|
||||
}
|
||||
hw->clip = mixeng_clip
|
||||
[hw->info.nchannels == 2]
|
||||
[hw->info.sign]
|
||||
[hw->info.swap_endianness]
|
||||
[audio_bits_to_index (hw->info.bits)];
|
||||
|
||||
QLIST_INSERT_HEAD (&s->cap_head, cap, entries);
|
||||
QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
|
||||
@@ -2092,7 +2079,6 @@ int audioformat_bytes_per_sample(AudioFormat fmt)
|
||||
|
||||
case AUDIO_FORMAT_U32:
|
||||
case AUDIO_FORMAT_S32:
|
||||
case AUDIO_FORMAT_F32:
|
||||
return 4;
|
||||
|
||||
case AUDIO_FORMAT__MAX:
|
||||
|
||||
+3
-4
@@ -40,8 +40,7 @@ struct audio_callback {
|
||||
|
||||
struct audio_pcm_info {
|
||||
int bits;
|
||||
bool is_signed;
|
||||
bool is_float;
|
||||
int sign;
|
||||
int freq;
|
||||
int nchannels;
|
||||
int bytes_per_frame;
|
||||
@@ -153,7 +152,6 @@ struct audio_pcm_ops {
|
||||
int (*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
|
||||
void (*fini_out)(HWVoiceOut *hw);
|
||||
size_t (*write) (HWVoiceOut *hw, void *buf, size_t size);
|
||||
void (*run_buffer_out)(HWVoiceOut *hw);
|
||||
/*
|
||||
* get a buffer that after later can be passed to put_buffer_out; optional
|
||||
* returns the buffer, and writes it's size to size (in bytes)
|
||||
@@ -180,9 +178,10 @@ struct audio_pcm_ops {
|
||||
|
||||
void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
|
||||
void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
|
||||
void audio_generic_run_buffer_out(HWVoiceOut *hw);
|
||||
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
|
||||
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
|
||||
size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
|
||||
size_t size);
|
||||
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
|
||||
size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size);
|
||||
|
||||
|
||||
+12
-28
@@ -153,23 +153,15 @@ static int glue (audio_pcm_sw_init_, TYPE) (
|
||||
sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
|
||||
#endif
|
||||
|
||||
if (sw->info.is_float) {
|
||||
#ifdef DAC
|
||||
sw->conv = mixeng_conv_float[sw->info.nchannels == 2];
|
||||
sw->conv = mixeng_conv
|
||||
#else
|
||||
sw->clip = mixeng_clip_float[sw->info.nchannels == 2];
|
||||
sw->clip = mixeng_clip
|
||||
#endif
|
||||
} else {
|
||||
#ifdef DAC
|
||||
sw->conv = mixeng_conv
|
||||
#else
|
||||
sw->clip = mixeng_clip
|
||||
#endif
|
||||
[sw->info.nchannels == 2]
|
||||
[sw->info.is_signed]
|
||||
[sw->info.swap_endianness]
|
||||
[audio_bits_to_index(sw->info.bits)];
|
||||
}
|
||||
[sw->info.nchannels == 2]
|
||||
[sw->info.sign]
|
||||
[sw->info.swap_endianness]
|
||||
[audio_bits_to_index (sw->info.bits)];
|
||||
|
||||
sw->name = g_strdup (name);
|
||||
err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
|
||||
@@ -284,23 +276,15 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
|
||||
goto err1;
|
||||
}
|
||||
|
||||
if (hw->info.is_float) {
|
||||
#ifdef DAC
|
||||
hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
|
||||
hw->clip = mixeng_clip
|
||||
#else
|
||||
hw->conv = mixeng_conv_float[hw->info.nchannels == 2];
|
||||
hw->conv = mixeng_conv
|
||||
#endif
|
||||
} else {
|
||||
#ifdef DAC
|
||||
hw->clip = mixeng_clip
|
||||
#else
|
||||
hw->conv = mixeng_conv
|
||||
#endif
|
||||
[hw->info.nchannels == 2]
|
||||
[hw->info.is_signed]
|
||||
[hw->info.swap_endianness]
|
||||
[audio_bits_to_index(hw->info.bits)];
|
||||
}
|
||||
[hw->info.nchannels == 2]
|
||||
[hw->info.sign]
|
||||
[hw->info.swap_endianness]
|
||||
[audio_bits_to_index (hw->info.bits)];
|
||||
|
||||
glue(audio_pcm_hw_alloc_resources_, TYPE)(hw);
|
||||
|
||||
|
||||
+25
-9
@@ -411,7 +411,7 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
|
||||
}
|
||||
COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
|
||||
(hw, size))
|
||||
COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
|
||||
COREAUDIO_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
|
||||
(HWVoiceOut *hw, void *buf, size_t size),
|
||||
(hw, buf, size))
|
||||
COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
|
||||
@@ -471,6 +471,20 @@ static OSStatus audioDeviceIOProc(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UInt32 coreaudio_get_flags(struct audio_pcm_info *info,
|
||||
struct audsettings *as)
|
||||
{
|
||||
UInt32 flags = info->sign ? kAudioFormatFlagIsSignedInteger : 0;
|
||||
if (as->endianness) { /* 0 = little, 1 = big */
|
||||
flags |= kAudioFormatFlagIsBigEndian;
|
||||
}
|
||||
|
||||
if (flags == 0) { /* must not be 0 */
|
||||
flags = kAudioFormatFlagsAreAllClear;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
void *drv_opaque)
|
||||
{
|
||||
@@ -482,7 +496,6 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
Audiodev *dev = drv_opaque;
|
||||
AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
|
||||
int frames;
|
||||
struct audsettings fake_as;
|
||||
|
||||
/* create mutex */
|
||||
err = pthread_mutex_init(&core->mutex, NULL);
|
||||
@@ -491,9 +504,6 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
return -1;
|
||||
}
|
||||
|
||||
fake_as = *as;
|
||||
as = &fake_as;
|
||||
as->fmt = AUDIO_FORMAT_F32;
|
||||
audio_pcm_init_info (&hw->info, as);
|
||||
|
||||
status = coreaudio_get_voice(&core->outputDeviceID);
|
||||
@@ -562,6 +572,15 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
|
||||
/* set Samplerate */
|
||||
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
|
||||
core->outputStreamBasicDescription.mFormatID = kAudioFormatLinearPCM;
|
||||
core->outputStreamBasicDescription.mFormatFlags =
|
||||
coreaudio_get_flags(&hw->info, as);
|
||||
core->outputStreamBasicDescription.mBytesPerPacket =
|
||||
core->outputStreamBasicDescription.mBytesPerFrame =
|
||||
hw->info.nchannels * hw->info.bits / 8;
|
||||
core->outputStreamBasicDescription.mFramesPerPacket = 1;
|
||||
core->outputStreamBasicDescription.mChannelsPerFrame = hw->info.nchannels;
|
||||
core->outputStreamBasicDescription.mBitsPerChannel = hw->info.bits;
|
||||
|
||||
status = coreaudio_set_streamformat(core->outputDeviceID,
|
||||
&core->outputStreamBasicDescription);
|
||||
@@ -668,12 +687,9 @@ static void coreaudio_audio_fini (void *opaque)
|
||||
static struct audio_pcm_ops coreaudio_pcm_ops = {
|
||||
.init_out = coreaudio_init_out,
|
||||
.fini_out = coreaudio_fini_out,
|
||||
/* wrapper for audio_generic_write */
|
||||
.write = coreaudio_write,
|
||||
/* wrapper for audio_generic_get_buffer_out */
|
||||
.get_buffer_out = coreaudio_get_buffer_out,
|
||||
/* wrapper for audio_generic_put_buffer_out */
|
||||
.put_buffer_out = coreaudio_put_buffer_out,
|
||||
.put_buffer_out = coreaudio_put_buffer_out_nowrite,
|
||||
.enable_out = coreaudio_enable_out
|
||||
};
|
||||
|
||||
|
||||
@@ -244,7 +244,6 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
ds->first_time = true;
|
||||
obt_as.endianness = 0;
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
|
||||
|
||||
+6
-30
@@ -53,14 +53,12 @@ typedef struct {
|
||||
typedef struct {
|
||||
HWVoiceOut hw;
|
||||
LPDIRECTSOUNDBUFFER dsound_buffer;
|
||||
bool first_time;
|
||||
dsound *s;
|
||||
} DSoundVoiceOut;
|
||||
|
||||
typedef struct {
|
||||
HWVoiceIn hw;
|
||||
LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
|
||||
bool first_time;
|
||||
dsound *s;
|
||||
} DSoundVoiceIn;
|
||||
|
||||
@@ -279,7 +277,7 @@ static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*statusp & DSBSTATUS_BUFFERLOST) {
|
||||
if (*statusp & DSERR_BUFFERLOST) {
|
||||
dsound_restore_out(dsb, s);
|
||||
return -1;
|
||||
}
|
||||
@@ -416,32 +414,21 @@ static void *dsound_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
|
||||
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
|
||||
HRESULT hr;
|
||||
DWORD ppos, wpos, act_size;
|
||||
DWORD ppos, act_size;
|
||||
size_t req_size;
|
||||
int err;
|
||||
void *ret;
|
||||
|
||||
hr = IDirectSoundBuffer_GetCurrentPosition(
|
||||
dsb, &ppos, ds->first_time ? &wpos : NULL);
|
||||
hr = IDirectSoundBuffer_GetCurrentPosition(dsb, &ppos, NULL);
|
||||
if (FAILED(hr)) {
|
||||
dsound_logerr(hr, "Could not get playback buffer position\n");
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ds->first_time) {
|
||||
hw->pos_emul = wpos;
|
||||
ds->first_time = false;
|
||||
}
|
||||
|
||||
req_size = audio_ring_dist(ppos, hw->pos_emul, hw->size_emul);
|
||||
req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
|
||||
|
||||
if (req_size == 0) {
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = dsound_lock_out(dsb, &hw->info, hw->pos_emul, req_size, &ret, NULL,
|
||||
&act_size, NULL, false, ds->s);
|
||||
if (err) {
|
||||
@@ -521,31 +508,20 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
||||
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
|
||||
LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
|
||||
HRESULT hr;
|
||||
DWORD cpos, rpos, act_size;
|
||||
DWORD cpos, act_size;
|
||||
size_t req_size;
|
||||
int err;
|
||||
void *ret;
|
||||
|
||||
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(
|
||||
dscb, &cpos, ds->first_time ? &rpos : NULL);
|
||||
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(dscb, &cpos, NULL);
|
||||
if (FAILED(hr)) {
|
||||
dsound_logerr(hr, "Could not get capture buffer position\n");
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ds->first_time) {
|
||||
hw->pos_emul = rpos;
|
||||
ds->first_time = false;
|
||||
}
|
||||
|
||||
req_size = audio_ring_dist(cpos, hw->pos_emul, hw->size_emul);
|
||||
req_size = MIN(*size, MIN(req_size, hw->size_emul - hw->pos_emul));
|
||||
|
||||
if (req_size == 0) {
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
|
||||
|
||||
err = dsound_lock_in(dscb, &hw->info, hw->pos_emul, req_size, &ret, NULL,
|
||||
&act_size, NULL, false, ds->s);
|
||||
|
||||
@@ -267,76 +267,6 @@ f_sample *mixeng_clip[2][2][2][3] = {
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef FLOAT_MIXENG
|
||||
#define CONV_NATURAL_FLOAT(x) (x)
|
||||
#define CLIP_NATURAL_FLOAT(x) (x)
|
||||
#else
|
||||
static const float float_scale = UINT_MAX / 2.f;
|
||||
#define CONV_NATURAL_FLOAT(x) ((x) * float_scale)
|
||||
|
||||
#ifdef RECIPROCAL
|
||||
static const float float_scale_reciprocal = 2.f / UINT_MAX;
|
||||
#define CLIP_NATURAL_FLOAT(x) ((x) * float_scale_reciprocal)
|
||||
#else
|
||||
#define CLIP_NATURAL_FLOAT(x) ((x) / float_scale)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void conv_natural_float_to_mono(struct st_sample *dst, const void *src,
|
||||
int samples)
|
||||
{
|
||||
float *in = (float *)src;
|
||||
|
||||
while (samples--) {
|
||||
dst->r = dst->l = CONV_NATURAL_FLOAT(*in++);
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
static void conv_natural_float_to_stereo(struct st_sample *dst, const void *src,
|
||||
int samples)
|
||||
{
|
||||
float *in = (float *)src;
|
||||
|
||||
while (samples--) {
|
||||
dst->l = CONV_NATURAL_FLOAT(*in++);
|
||||
dst->r = CONV_NATURAL_FLOAT(*in++);
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
t_sample *mixeng_conv_float[2] = {
|
||||
conv_natural_float_to_mono,
|
||||
conv_natural_float_to_stereo,
|
||||
};
|
||||
|
||||
static void clip_natural_float_from_mono(void *dst, const struct st_sample *src,
|
||||
int samples)
|
||||
{
|
||||
float *out = (float *)dst;
|
||||
|
||||
while (samples--) {
|
||||
*out++ = CLIP_NATURAL_FLOAT(src->l + src->r);
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
static void clip_natural_float_from_stereo(
|
||||
void *dst, const struct st_sample *src, int samples)
|
||||
{
|
||||
float *out = (float *)dst;
|
||||
|
||||
while (samples--) {
|
||||
*out++ = CLIP_NATURAL_FLOAT(src->l);
|
||||
*out++ = CLIP_NATURAL_FLOAT(src->r);
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
f_sample *mixeng_clip_float[2] = {
|
||||
clip_natural_float_from_mono,
|
||||
clip_natural_float_from_stereo,
|
||||
};
|
||||
|
||||
void audio_sample_to_uint64(void *samples, int pos,
|
||||
uint64_t *left, uint64_t *right)
|
||||
|
||||
@@ -38,14 +38,9 @@ typedef struct st_sample st_sample;
|
||||
typedef void (t_sample) (struct st_sample *dst, const void *src, int samples);
|
||||
typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
|
||||
|
||||
/* indices: [stereo][signed][swap endiannes][8, 16 or 32-bits] */
|
||||
extern t_sample *mixeng_conv[2][2][2][3];
|
||||
extern f_sample *mixeng_clip[2][2][2][3];
|
||||
|
||||
/* indices: [stereo] */
|
||||
extern t_sample *mixeng_conv_float[2];
|
||||
extern f_sample *mixeng_clip_float[2];
|
||||
|
||||
void *st_rate_start (int inrate, int outrate);
|
||||
void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
|
||||
size_t *isamp, size_t *osamp);
|
||||
|
||||
+12
-10
@@ -41,31 +41,32 @@ static inline mixeng_real glue (conv_, ET) (IN_T v)
|
||||
|
||||
#ifdef RECIPROCAL
|
||||
#ifdef SIGNED
|
||||
return nv * (2.f / ((mixeng_real)IN_MAX - IN_MIN));
|
||||
return nv * (1.f / (mixeng_real) (IN_MAX - IN_MIN));
|
||||
#else
|
||||
return (nv - HALF) * (2.f / (mixeng_real)IN_MAX);
|
||||
return (nv - HALF) * (1.f / (mixeng_real) IN_MAX);
|
||||
#endif
|
||||
#else /* !RECIPROCAL */
|
||||
#ifdef SIGNED
|
||||
return nv / (((mixeng_real)IN_MAX - IN_MIN) / 2.f);
|
||||
return nv / (mixeng_real) ((mixeng_real) IN_MAX - IN_MIN);
|
||||
#else
|
||||
return (nv - HALF) / ((mixeng_real)IN_MAX / 2.f);
|
||||
return (nv - HALF) / (mixeng_real) IN_MAX;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline IN_T glue (clip_, ET) (mixeng_real v)
|
||||
{
|
||||
if (v >= 1.f) {
|
||||
if (v >= 0.5) {
|
||||
return IN_MAX;
|
||||
} else if (v < -1.f) {
|
||||
}
|
||||
else if (v < -0.5) {
|
||||
return IN_MIN;
|
||||
}
|
||||
|
||||
#ifdef SIGNED
|
||||
return ENDIAN_CONVERT((IN_T)(v * (((mixeng_real)IN_MAX - IN_MIN) / 2.f)));
|
||||
return ENDIAN_CONVERT ((IN_T) (v * ((mixeng_real) IN_MAX - IN_MIN)));
|
||||
#else
|
||||
return ENDIAN_CONVERT((IN_T)((v * ((mixeng_real)IN_MAX / 2.f)) + HALF));
|
||||
return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -83,9 +84,10 @@ static inline int64_t glue (conv_, ET) (IN_T v)
|
||||
|
||||
static inline IN_T glue (clip_, ET) (int64_t v)
|
||||
{
|
||||
if (v >= 0x7fffffffLL) {
|
||||
if (v >= 0x7f000000) {
|
||||
return IN_MAX;
|
||||
} else if (v < -2147483648LL) {
|
||||
}
|
||||
else if (v < -2147483648LL) {
|
||||
return IN_MIN;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,6 @@ static struct audio_pcm_ops no_pcm_ops = {
|
||||
.init_out = no_init_out,
|
||||
.fini_out = no_fini_out,
|
||||
.write = no_write,
|
||||
.run_buffer_out = audio_generic_run_buffer_out,
|
||||
.enable_out = no_enable_out,
|
||||
|
||||
.init_in = no_init_in,
|
||||
|
||||
+10
-16
@@ -382,15 +382,6 @@ static size_t oss_get_available_bytes(OSSVoiceOut *oss)
|
||||
return audio_ring_dist(cntinfo.ptr, oss->hw.pos_emul, oss->hw.size_emul);
|
||||
}
|
||||
|
||||
static void oss_run_buffer_out(HWVoiceOut *hw)
|
||||
{
|
||||
OSSVoiceOut *oss = (OSSVoiceOut *)hw;
|
||||
|
||||
if (!oss->mmapped) {
|
||||
audio_generic_run_buffer_out(hw);
|
||||
}
|
||||
}
|
||||
|
||||
static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||
{
|
||||
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
|
||||
@@ -579,18 +570,20 @@ static void oss_enable_out(HWVoiceOut *hw, bool enable)
|
||||
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
|
||||
|
||||
if (enable) {
|
||||
hw->poll_mode = opdo->try_poll;
|
||||
bool poll_mode = opdo->try_poll;
|
||||
|
||||
ldebug("enabling voice\n");
|
||||
if (hw->poll_mode) {
|
||||
if (poll_mode) {
|
||||
oss_poll_out(hw);
|
||||
poll_mode = 0;
|
||||
}
|
||||
hw->poll_mode = poll_mode;
|
||||
|
||||
if (!oss->mmapped) {
|
||||
return;
|
||||
}
|
||||
|
||||
audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->samples);
|
||||
audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->mix_buf->size);
|
||||
trig = PCM_ENABLE_OUTPUT;
|
||||
if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
|
||||
oss_logerr(errno,
|
||||
@@ -706,15 +699,17 @@ static void oss_enable_in(HWVoiceIn *hw, bool enable)
|
||||
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
|
||||
|
||||
if (enable) {
|
||||
hw->poll_mode = opdo->try_poll;
|
||||
bool poll_mode = opdo->try_poll;
|
||||
|
||||
if (hw->poll_mode) {
|
||||
if (poll_mode) {
|
||||
oss_poll_in(hw);
|
||||
poll_mode = 0;
|
||||
}
|
||||
hw->poll_mode = poll_mode;
|
||||
} else {
|
||||
if (hw->poll_mode) {
|
||||
qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
|
||||
hw->poll_mode = 0;
|
||||
qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -753,7 +748,6 @@ static struct audio_pcm_ops oss_pcm_ops = {
|
||||
.init_out = oss_init_out,
|
||||
.fini_out = oss_fini_out,
|
||||
.write = oss_write,
|
||||
.run_buffer_out = oss_run_buffer_out,
|
||||
.get_buffer_out = oss_get_buffer_out,
|
||||
.put_buffer_out = oss_put_buffer_out,
|
||||
.enable_out = oss_enable_out,
|
||||
|
||||
+24
-59
@@ -32,6 +32,7 @@ typedef struct {
|
||||
HWVoiceOut hw;
|
||||
pa_stream *stream;
|
||||
paaudio *g;
|
||||
size_t samples;
|
||||
} PAVoiceOut;
|
||||
|
||||
typedef struct {
|
||||
@@ -40,6 +41,7 @@ typedef struct {
|
||||
const void *read_data;
|
||||
size_t read_length;
|
||||
paaudio *g;
|
||||
size_t samples;
|
||||
} PAVoiceIn;
|
||||
|
||||
static void qpa_conn_fini(PAConnection *c);
|
||||
@@ -154,48 +156,34 @@ static size_t qpa_read(HWVoiceIn *hw, void *data, size_t length)
|
||||
{
|
||||
PAVoiceIn *p = (PAVoiceIn *) hw;
|
||||
PAConnection *c = p->g->conn;
|
||||
size_t total = 0;
|
||||
size_t l;
|
||||
int r;
|
||||
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
|
||||
CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
|
||||
"pa_threaded_mainloop_lock failed\n");
|
||||
if (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
|
||||
/* wait for stream to become ready */
|
||||
goto unlock;
|
||||
|
||||
if (!p->read_length) {
|
||||
r = pa_stream_peek(p->stream, &p->read_data, &p->read_length);
|
||||
CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
|
||||
"pa_stream_peek failed\n");
|
||||
}
|
||||
|
||||
while (total < length) {
|
||||
size_t l;
|
||||
int r;
|
||||
l = MIN(p->read_length, length);
|
||||
memcpy(data, p->read_data, l);
|
||||
|
||||
if (!p->read_length) {
|
||||
r = pa_stream_peek(p->stream, &p->read_data, &p->read_length);
|
||||
CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
|
||||
"pa_stream_peek failed\n");
|
||||
if (!p->read_length) {
|
||||
/* buffer is empty */
|
||||
break;
|
||||
}
|
||||
}
|
||||
p->read_data += l;
|
||||
p->read_length -= l;
|
||||
|
||||
l = MIN(p->read_length, length - total);
|
||||
memcpy((char *)data + total, p->read_data, l);
|
||||
|
||||
p->read_data += l;
|
||||
p->read_length -= l;
|
||||
total += l;
|
||||
|
||||
if (!p->read_length) {
|
||||
r = pa_stream_drop(p->stream);
|
||||
CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
|
||||
"pa_stream_drop failed\n");
|
||||
}
|
||||
if (!p->read_length) {
|
||||
r = pa_stream_drop(p->stream);
|
||||
CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
|
||||
"pa_stream_drop failed\n");
|
||||
}
|
||||
|
||||
unlock:
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
return total;
|
||||
return l;
|
||||
|
||||
unlock_and_fail:
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
@@ -277,9 +265,6 @@ static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness)
|
||||
case AUDIO_FORMAT_U32:
|
||||
format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
|
||||
break;
|
||||
case AUDIO_FORMAT_F32:
|
||||
format = endianness ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE;
|
||||
break;
|
||||
default:
|
||||
dolog ("Internal logic error: Bad audio format %d\n", afmt);
|
||||
format = PA_SAMPLE_U8;
|
||||
@@ -305,12 +290,6 @@ static AudioFormat pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
|
||||
case PA_SAMPLE_S32LE:
|
||||
*endianness = 0;
|
||||
return AUDIO_FORMAT_S32;
|
||||
case PA_SAMPLE_FLOAT32BE:
|
||||
*endianness = 1;
|
||||
return AUDIO_FORMAT_F32;
|
||||
case PA_SAMPLE_FLOAT32LE:
|
||||
*endianness = 0;
|
||||
return AUDIO_FORMAT_F32;
|
||||
default:
|
||||
dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
|
||||
return AUDIO_FORMAT_U8;
|
||||
@@ -495,7 +474,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
}
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
hw->samples = audio_buffer_samples(
|
||||
hw->samples = pa->samples = audio_buffer_samples(
|
||||
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
|
||||
&obt_as, ppdo->buffer_length);
|
||||
|
||||
@@ -543,7 +522,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
}
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
hw->samples = audio_buffer_samples(
|
||||
hw->samples = pa->samples = audio_buffer_samples(
|
||||
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
|
||||
&obt_as, ppdo->buffer_length);
|
||||
|
||||
@@ -557,6 +536,7 @@ static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
|
||||
{
|
||||
int err;
|
||||
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
/*
|
||||
* wait until actually connects. workaround pa bug #247
|
||||
* https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/247
|
||||
@@ -570,6 +550,7 @@ static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
|
||||
dolog("Failed to disconnect! err=%d\n", err);
|
||||
}
|
||||
pa_stream_unref(stream);
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
}
|
||||
|
||||
static void qpa_fini_out (HWVoiceOut *hw)
|
||||
@@ -577,12 +558,8 @@ static void qpa_fini_out (HWVoiceOut *hw)
|
||||
PAVoiceOut *pa = (PAVoiceOut *) hw;
|
||||
|
||||
if (pa->stream) {
|
||||
PAConnection *c = pa->g->conn;
|
||||
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
qpa_simple_disconnect(c, pa->stream);
|
||||
qpa_simple_disconnect(pa->g->conn, pa->stream);
|
||||
pa->stream = NULL;
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,20 +568,8 @@ static void qpa_fini_in (HWVoiceIn *hw)
|
||||
PAVoiceIn *pa = (PAVoiceIn *) hw;
|
||||
|
||||
if (pa->stream) {
|
||||
PAConnection *c = pa->g->conn;
|
||||
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
if (pa->read_length) {
|
||||
int r = pa_stream_drop(pa->stream);
|
||||
if (r) {
|
||||
qpa_logerr(pa_context_errno(c->context),
|
||||
"pa_stream_drop failed\n");
|
||||
}
|
||||
pa->read_length = 0;
|
||||
}
|
||||
qpa_simple_disconnect(c, pa->stream);
|
||||
qpa_simple_disconnect(pa->g->conn, pa->stream);
|
||||
pa->stream = NULL;
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-33
@@ -77,14 +77,6 @@ static int aud_to_sdlfmt (AudioFormat fmt)
|
||||
case AUDIO_FORMAT_U16:
|
||||
return AUDIO_U16LSB;
|
||||
|
||||
case AUDIO_FORMAT_S32:
|
||||
return AUDIO_S32LSB;
|
||||
|
||||
/* no unsigned 32-bit support in SDL */
|
||||
|
||||
case AUDIO_FORMAT_F32:
|
||||
return AUDIO_F32LSB;
|
||||
|
||||
default:
|
||||
dolog ("Internal logic error: Bad audio format %d\n", fmt);
|
||||
#ifdef DEBUG_AUDIO
|
||||
@@ -127,26 +119,6 @@ static int sdl_to_audfmt(int sdlfmt, AudioFormat *fmt, int *endianness)
|
||||
*fmt = AUDIO_FORMAT_U16;
|
||||
break;
|
||||
|
||||
case AUDIO_S32LSB:
|
||||
*endianness = 0;
|
||||
*fmt = AUDIO_FORMAT_S32;
|
||||
break;
|
||||
|
||||
case AUDIO_S32MSB:
|
||||
*endianness = 1;
|
||||
*fmt = AUDIO_FORMAT_S32;
|
||||
break;
|
||||
|
||||
case AUDIO_F32LSB:
|
||||
*endianness = 0;
|
||||
*fmt = AUDIO_FORMAT_F32;
|
||||
break;
|
||||
|
||||
case AUDIO_F32MSB:
|
||||
*endianness = 1;
|
||||
*fmt = AUDIO_FORMAT_F32;
|
||||
break;
|
||||
|
||||
default:
|
||||
dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
|
||||
return -1;
|
||||
@@ -255,7 +227,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||
|
||||
SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
|
||||
(hw, size), *size = 0, sdl_unlock)
|
||||
SDL_WRAPPER_FUNC(put_buffer_out, size_t,
|
||||
SDL_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
|
||||
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size),
|
||||
/*nothing*/, sdl_unlock_and_post)
|
||||
SDL_WRAPPER_FUNC(write, size_t,
|
||||
@@ -348,12 +320,9 @@ static void sdl_audio_fini (void *opaque)
|
||||
static struct audio_pcm_ops sdl_pcm_ops = {
|
||||
.init_out = sdl_init_out,
|
||||
.fini_out = sdl_fini_out,
|
||||
/* wrapper for audio_generic_write */
|
||||
.write = sdl_write,
|
||||
/* wrapper for audio_generic_get_buffer_out */
|
||||
.get_buffer_out = sdl_get_buffer_out,
|
||||
/* wrapper for audio_generic_put_buffer_out */
|
||||
.put_buffer_out = sdl_put_buffer_out,
|
||||
.put_buffer_out = sdl_put_buffer_out_nowrite,
|
||||
.enable_out = sdl_enable_out,
|
||||
};
|
||||
|
||||
|
||||
@@ -197,7 +197,6 @@ static struct audio_pcm_ops wav_pcm_ops = {
|
||||
.init_out = wav_init_out,
|
||||
.fini_out = wav_fini_out,
|
||||
.write = wav_write_out,
|
||||
.run_buffer_out = audio_generic_run_buffer_out,
|
||||
.enable_out = wav_enable_out,
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -239,7 +239,7 @@ qauthz_list_file_init(Object *obj)
|
||||
|
||||
authz->file_watch = -1;
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
authz->refresh = true;
|
||||
authz->refresh = TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,3 @@ endif
|
||||
common-obj-$(call land,$(CONFIG_VHOST_USER),$(CONFIG_VIRTIO)) += vhost-user.o
|
||||
|
||||
common-obj-$(CONFIG_LINUX) += hostmem-memfd.o
|
||||
|
||||
common-obj-$(CONFIG_GIO) += dbus-vmstate.o
|
||||
dbus-vmstate.o-cflags = $(GIO_CFLAGS)
|
||||
dbus-vmstate.o-libs = $(GIO_LIBS)
|
||||
@@ -152,7 +152,7 @@ cryptodev_vhost_claim_chardev(CryptoDevBackendVhostUser *s,
|
||||
return chr;
|
||||
}
|
||||
|
||||
static void cryptodev_vhost_user_event(void *opaque, QEMUChrEvent event)
|
||||
static void cryptodev_vhost_user_event(void *opaque, int event)
|
||||
{
|
||||
CryptoDevBackendVhostUser *s = opaque;
|
||||
CryptoDevBackend *b = CRYPTODEV_BACKEND(s);
|
||||
@@ -171,11 +171,6 @@ static void cryptodev_vhost_user_event(void *opaque, QEMUChrEvent event)
|
||||
b->ready = false;
|
||||
cryptodev_vhost_user_stop(queues, s);
|
||||
break;
|
||||
case CHR_EVENT_BREAK:
|
||||
case CHR_EVENT_MUX_IN:
|
||||
case CHR_EVENT_MUX_OUT:
|
||||
/* Ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -176,10 +176,19 @@ cryptodev_backend_complete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc);
|
||||
CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (bc->init) {
|
||||
bc->init(backend, errp);
|
||||
bc->init(backend, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used)
|
||||
|
||||
@@ -1,511 +0,0 @@
|
||||
/*
|
||||
* QEMU dbus-vmstate
|
||||
*
|
||||
* Copyright (C) 2019 Red Hat Inc
|
||||
*
|
||||
* Authors:
|
||||
* Marc-André Lureau <marcandre.lureau@redhat.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 "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/dbus.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
|
||||
typedef struct DBusVMState DBusVMState;
|
||||
typedef struct DBusVMStateClass DBusVMStateClass;
|
||||
|
||||
#define TYPE_DBUS_VMSTATE "dbus-vmstate"
|
||||
#define DBUS_VMSTATE(obj) \
|
||||
OBJECT_CHECK(DBusVMState, (obj), TYPE_DBUS_VMSTATE)
|
||||
#define DBUS_VMSTATE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(DBusVMStateClass, (obj), TYPE_DBUS_VMSTATE)
|
||||
#define DBUS_VMSTATE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(DBusVMStateClass, (klass), TYPE_DBUS_VMSTATE)
|
||||
|
||||
struct DBusVMStateClass {
|
||||
ObjectClass parent_class;
|
||||
};
|
||||
|
||||
struct DBusVMState {
|
||||
Object parent;
|
||||
|
||||
GDBusConnection *bus;
|
||||
char *dbus_addr;
|
||||
char *id_list;
|
||||
|
||||
uint32_t data_size;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
static const GDBusPropertyInfo vmstate_property_info[] = {
|
||||
{ -1, (char *) "Id", (char *) "s",
|
||||
G_DBUS_PROPERTY_INFO_FLAGS_READABLE, NULL },
|
||||
};
|
||||
|
||||
static const GDBusPropertyInfo * const vmstate_property_info_pointers[] = {
|
||||
&vmstate_property_info[0],
|
||||
NULL
|
||||
};
|
||||
|
||||
static const GDBusInterfaceInfo vmstate1_interface_info = {
|
||||
-1,
|
||||
(char *) "org.qemu.VMState1",
|
||||
(GDBusMethodInfo **) NULL,
|
||||
(GDBusSignalInfo **) NULL,
|
||||
(GDBusPropertyInfo **) &vmstate_property_info_pointers,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#define DBUS_VMSTATE_SIZE_LIMIT (1 * MiB)
|
||||
|
||||
static GHashTable *
|
||||
get_id_list_set(DBusVMState *self)
|
||||
{
|
||||
g_auto(GStrv) ids = NULL;
|
||||
g_autoptr(GHashTable) set = NULL;
|
||||
int i;
|
||||
|
||||
if (!self->id_list) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ids = g_strsplit(self->id_list, ",", -1);
|
||||
set = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
|
||||
for (i = 0; ids[i]; i++) {
|
||||
g_hash_table_add(set, ids[i]);
|
||||
ids[i] = NULL;
|
||||
}
|
||||
|
||||
return g_steal_pointer(&set);
|
||||
}
|
||||
|
||||
static GHashTable *
|
||||
dbus_get_proxies(DBusVMState *self, GError **err)
|
||||
{
|
||||
g_autoptr(GHashTable) proxies = NULL;
|
||||
g_autoptr(GHashTable) ids = NULL;
|
||||
g_auto(GStrv) names = NULL;
|
||||
Error *error = NULL;
|
||||
size_t i;
|
||||
|
||||
ids = get_id_list_set(self);
|
||||
proxies = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, g_object_unref);
|
||||
|
||||
names = qemu_dbus_get_queued_owners(self->bus, "org.qemu.VMState1", &error);
|
||||
if (!names) {
|
||||
g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
|
||||
error_get_pretty(error));
|
||||
error_free(error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; names[i]; i++) {
|
||||
g_autoptr(GDBusProxy) proxy = NULL;
|
||||
g_autoptr(GVariant) result = NULL;
|
||||
g_autofree char *id = NULL;
|
||||
size_t size;
|
||||
|
||||
proxy = g_dbus_proxy_new_sync(self->bus, G_DBUS_PROXY_FLAGS_NONE,
|
||||
(GDBusInterfaceInfo *) &vmstate1_interface_info,
|
||||
names[i],
|
||||
"/org/qemu/VMState1",
|
||||
"org.qemu.VMState1",
|
||||
NULL, err);
|
||||
if (!proxy) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = g_dbus_proxy_get_cached_property(proxy, "Id");
|
||||
if (!result) {
|
||||
g_set_error_literal(err, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"VMState Id property is missing.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
id = g_variant_dup_string(result, &size);
|
||||
if (ids && !g_hash_table_remove(ids, id)) {
|
||||
g_clear_pointer(&id, g_free);
|
||||
g_clear_object(&proxy);
|
||||
continue;
|
||||
}
|
||||
if (size == 0 || size >= 256) {
|
||||
g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"VMState Id '%s' is invalid.", id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!g_hash_table_insert(proxies, id, proxy)) {
|
||||
g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Duplicated VMState Id '%s'", id);
|
||||
return NULL;
|
||||
}
|
||||
id = NULL;
|
||||
proxy = NULL;
|
||||
|
||||
g_clear_pointer(&result, g_variant_unref);
|
||||
}
|
||||
|
||||
if (ids) {
|
||||
g_autofree char **left = NULL;
|
||||
|
||||
left = (char **)g_hash_table_get_keys_as_array(ids, NULL);
|
||||
if (*left) {
|
||||
g_autofree char *leftids = g_strjoinv(",", left);
|
||||
g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Required VMState Id are missing: %s", leftids);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return g_steal_pointer(&proxies);
|
||||
}
|
||||
|
||||
static int
|
||||
dbus_load_state_proxy(GDBusProxy *proxy, const uint8_t *data, size_t size)
|
||||
{
|
||||
g_autoptr(GError) err = NULL;
|
||||
g_autoptr(GVariant) result = NULL;
|
||||
g_autoptr(GVariant) value = NULL;
|
||||
|
||||
value = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
|
||||
data, size, sizeof(char));
|
||||
result = g_dbus_proxy_call_sync(proxy, "Load",
|
||||
g_variant_new("(@ay)",
|
||||
g_steal_pointer(&value)),
|
||||
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
||||
-1, NULL, &err);
|
||||
if (!result) {
|
||||
error_report("%s: Failed to Load: %s", __func__, err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dbus_vmstate_post_load(void *opaque, int version_id)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(opaque);
|
||||
g_autoptr(GInputStream) m = NULL;
|
||||
g_autoptr(GDataInputStream) s = NULL;
|
||||
g_autoptr(GError) err = NULL;
|
||||
g_autoptr(GHashTable) proxies = NULL;
|
||||
uint32_t nelem;
|
||||
|
||||
trace_dbus_vmstate_post_load(version_id);
|
||||
|
||||
proxies = dbus_get_proxies(self, &err);
|
||||
if (!proxies) {
|
||||
error_report("%s: Failed to get proxies: %s", __func__, err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
m = g_memory_input_stream_new_from_data(self->data, self->data_size, NULL);
|
||||
s = g_data_input_stream_new(m);
|
||||
g_data_input_stream_set_byte_order(s, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN);
|
||||
|
||||
nelem = g_data_input_stream_read_uint32(s, NULL, &err);
|
||||
if (err) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (nelem > 0) {
|
||||
GDBusProxy *proxy = NULL;
|
||||
uint32_t len;
|
||||
gsize bytes_read, avail;
|
||||
char id[256];
|
||||
|
||||
len = g_data_input_stream_read_uint32(s, NULL, &err);
|
||||
if (err) {
|
||||
goto error;
|
||||
}
|
||||
if (len >= 256) {
|
||||
error_report("%s: Invalid DBus vmstate proxy name %u",
|
||||
__func__, len);
|
||||
return -1;
|
||||
}
|
||||
if (!g_input_stream_read_all(G_INPUT_STREAM(s), id, len,
|
||||
&bytes_read, NULL, &err)) {
|
||||
goto error;
|
||||
}
|
||||
g_return_val_if_fail(bytes_read == len, -1);
|
||||
id[len] = 0;
|
||||
|
||||
trace_dbus_vmstate_loading(id);
|
||||
|
||||
proxy = g_hash_table_lookup(proxies, id);
|
||||
if (!proxy) {
|
||||
error_report("%s: Failed to find proxy Id '%s'", __func__, id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = g_data_input_stream_read_uint32(s, NULL, &err);
|
||||
avail = g_buffered_input_stream_get_available(
|
||||
G_BUFFERED_INPUT_STREAM(s));
|
||||
|
||||
if (len > DBUS_VMSTATE_SIZE_LIMIT || len > avail) {
|
||||
error_report("%s: Invalid vmstate size: %u", __func__, len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dbus_load_state_proxy(proxy,
|
||||
g_buffered_input_stream_peek_buffer(G_BUFFERED_INPUT_STREAM(s),
|
||||
NULL),
|
||||
len) < 0) {
|
||||
error_report("%s: Failed to restore Id '%s'", __func__, id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!g_seekable_seek(G_SEEKABLE(s), len, G_SEEK_CUR, NULL, &err)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
nelem -= 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
error_report("%s: Failed to read from stream: %s", __func__, err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_save_state_proxy(gpointer key,
|
||||
gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDataOutputStream *s = user_data;
|
||||
const char *id = key;
|
||||
GDBusProxy *proxy = value;
|
||||
g_autoptr(GVariant) result = NULL;
|
||||
g_autoptr(GVariant) child = NULL;
|
||||
g_autoptr(GError) err = NULL;
|
||||
const uint8_t *data;
|
||||
gsize size;
|
||||
|
||||
trace_dbus_vmstate_saving(id);
|
||||
|
||||
result = g_dbus_proxy_call_sync(proxy, "Save",
|
||||
NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
||||
-1, NULL, &err);
|
||||
if (!result) {
|
||||
error_report("%s: Failed to Save: %s", __func__, err->message);
|
||||
return;
|
||||
}
|
||||
|
||||
child = g_variant_get_child_value(result, 0);
|
||||
data = g_variant_get_fixed_array(child, &size, sizeof(char));
|
||||
if (!data) {
|
||||
error_report("%s: Failed to Save: not a byte array", __func__);
|
||||
return;
|
||||
}
|
||||
if (size > DBUS_VMSTATE_SIZE_LIMIT) {
|
||||
error_report("%s: Too large vmstate data to save: %zu",
|
||||
__func__, (size_t)size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_data_output_stream_put_uint32(s, strlen(id), NULL, &err) ||
|
||||
!g_data_output_stream_put_string(s, id, NULL, &err) ||
|
||||
!g_data_output_stream_put_uint32(s, size, NULL, &err) ||
|
||||
!g_output_stream_write_all(G_OUTPUT_STREAM(s),
|
||||
data, size, NULL, NULL, &err)) {
|
||||
error_report("%s: Failed to write to stream: %s",
|
||||
__func__, err->message);
|
||||
}
|
||||
}
|
||||
|
||||
static int dbus_vmstate_pre_save(void *opaque)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(opaque);
|
||||
g_autoptr(GOutputStream) m = NULL;
|
||||
g_autoptr(GDataOutputStream) s = NULL;
|
||||
g_autoptr(GHashTable) proxies = NULL;
|
||||
g_autoptr(GError) err = NULL;
|
||||
|
||||
trace_dbus_vmstate_pre_save();
|
||||
|
||||
proxies = dbus_get_proxies(self, &err);
|
||||
if (!proxies) {
|
||||
error_report("%s: Failed to get proxies: %s", __func__, err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
m = g_memory_output_stream_new_resizable();
|
||||
s = g_data_output_stream_new(m);
|
||||
g_data_output_stream_set_byte_order(s, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN);
|
||||
|
||||
if (!g_data_output_stream_put_uint32(s, g_hash_table_size(proxies),
|
||||
NULL, &err)) {
|
||||
error_report("%s: Failed to write to stream: %s",
|
||||
__func__, err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_hash_table_foreach(proxies, dbus_save_state_proxy, s);
|
||||
|
||||
if (g_memory_output_stream_get_size(G_MEMORY_OUTPUT_STREAM(m))
|
||||
> UINT32_MAX) {
|
||||
error_report("%s: DBus vmstate buffer is too large", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!g_output_stream_close(G_OUTPUT_STREAM(m), NULL, &err)) {
|
||||
error_report("%s: Failed to close stream: %s", __func__, err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_free(self->data);
|
||||
self->data_size =
|
||||
g_memory_output_stream_get_size(G_MEMORY_OUTPUT_STREAM(m));
|
||||
self->data =
|
||||
g_memory_output_stream_steal_data(G_MEMORY_OUTPUT_STREAM(m));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription dbus_vmstate = {
|
||||
.name = TYPE_DBUS_VMSTATE,
|
||||
.version_id = 0,
|
||||
.pre_save = dbus_vmstate_pre_save,
|
||||
.post_load = dbus_vmstate_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(data_size, DBusVMState),
|
||||
VMSTATE_VBUFFER_ALLOC_UINT32(data, DBusVMState, 0, 0, data_size),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
dbus_vmstate_complete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(uc);
|
||||
g_autoptr(GError) err = NULL;
|
||||
|
||||
if (!object_resolve_path_type("", TYPE_DBUS_VMSTATE, NULL)) {
|
||||
error_setg(errp, "There is already an instance of %s",
|
||||
TYPE_DBUS_VMSTATE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self->dbus_addr) {
|
||||
error_setg(errp, QERR_MISSING_PARAMETER, "addr");
|
||||
return;
|
||||
}
|
||||
|
||||
self->bus = g_dbus_connection_new_for_address_sync(self->dbus_addr,
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
|
||||
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
|
||||
NULL, NULL, &err);
|
||||
if (err) {
|
||||
error_setg(errp, "failed to connect to DBus: '%s'", err->message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vmstate_register(VMSTATE_IF(self), VMSTATE_INSTANCE_ID_ANY,
|
||||
&dbus_vmstate, self) < 0) {
|
||||
error_setg(errp, "Failed to register vmstate");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_vmstate_finalize(Object *o)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(o);
|
||||
|
||||
vmstate_unregister(VMSTATE_IF(self), &dbus_vmstate, self);
|
||||
|
||||
g_clear_object(&self->bus);
|
||||
g_free(self->dbus_addr);
|
||||
g_free(self->id_list);
|
||||
g_free(self->data);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_dbus_addr(Object *o, Error **errp)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(o);
|
||||
|
||||
return g_strdup(self->dbus_addr);
|
||||
}
|
||||
|
||||
static void
|
||||
set_dbus_addr(Object *o, const char *str, Error **errp)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(o);
|
||||
|
||||
g_free(self->dbus_addr);
|
||||
self->dbus_addr = g_strdup(str);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_id_list(Object *o, Error **errp)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(o);
|
||||
|
||||
return g_strdup(self->id_list);
|
||||
}
|
||||
|
||||
static void
|
||||
set_id_list(Object *o, const char *str, Error **errp)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(o);
|
||||
|
||||
g_free(self->id_list);
|
||||
self->id_list = g_strdup(str);
|
||||
}
|
||||
|
||||
static char *
|
||||
dbus_vmstate_get_id(VMStateIf *vmif)
|
||||
{
|
||||
return g_strdup(TYPE_DBUS_VMSTATE);
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_vmstate_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||
VMStateIfClass *vc = VMSTATE_IF_CLASS(oc);
|
||||
|
||||
ucc->complete = dbus_vmstate_complete;
|
||||
vc->get_id = dbus_vmstate_get_id;
|
||||
|
||||
object_class_property_add_str(oc, "addr",
|
||||
get_dbus_addr, set_dbus_addr,
|
||||
&error_abort);
|
||||
object_class_property_add_str(oc, "id-list",
|
||||
get_id_list, set_id_list,
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static const TypeInfo dbus_vmstate_info = {
|
||||
.name = TYPE_DBUS_VMSTATE,
|
||||
.parent = TYPE_OBJECT,
|
||||
.instance_size = sizeof(DBusVMState),
|
||||
.instance_finalize = dbus_vmstate_finalize,
|
||||
.class_size = sizeof(DBusVMStateClass),
|
||||
.class_init = dbus_vmstate_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_USER_CREATABLE },
|
||||
{ TYPE_VMSTATE_IF },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
register_types(void)
|
||||
{
|
||||
type_register_static(&dbus_vmstate_info);
|
||||
}
|
||||
|
||||
type_init(register_types);
|
||||
@@ -18,6 +18,13 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
|
||||
/* hostmem-file.c */
|
||||
/**
|
||||
* @TYPE_MEMORY_BACKEND_FILE:
|
||||
* name of backend that uses mmap on a file descriptor
|
||||
*/
|
||||
#define TYPE_MEMORY_BACKEND_FILE "memory-backend-file"
|
||||
|
||||
#define MEMORY_BACKEND_FILE(obj) \
|
||||
OBJECT_CHECK(HostMemoryBackendFile, (obj), TYPE_MEMORY_BACKEND_FILE)
|
||||
|
||||
@@ -51,6 +58,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
backend->force_prealloc = mem_prealloc;
|
||||
name = host_memory_backend_get_name(backend);
|
||||
memory_region_init_ram_from_file(&backend->mr, OBJECT(backend),
|
||||
name,
|
||||
|
||||
@@ -45,6 +45,7 @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
backend->force_prealloc = mem_prealloc;
|
||||
fd = qemu_memfd_create(TYPE_MEMORY_BACKEND_MEMFD, backend->size,
|
||||
m->hugetlb, m->hugetlbsize, m->seal ?
|
||||
F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL : 0,
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
|
||||
#define TYPE_MEMORY_BACKEND_RAM "memory-backend-ram"
|
||||
|
||||
static void
|
||||
ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
{
|
||||
|
||||
+14
-40
@@ -215,7 +215,7 @@ static bool host_memory_backend_get_prealloc(Object *obj, Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
|
||||
return backend->prealloc;
|
||||
return backend->prealloc || backend->force_prealloc;
|
||||
}
|
||||
|
||||
static void host_memory_backend_set_prealloc(Object *obj, bool value,
|
||||
@@ -223,6 +223,15 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value,
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
|
||||
if (backend->force_prealloc) {
|
||||
if (value) {
|
||||
error_setg(errp,
|
||||
"remove -mem-prealloc to use the prealloc property");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!host_memory_backend_mr_inited(backend)) {
|
||||
backend->prealloc = value;
|
||||
@@ -234,7 +243,7 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value,
|
||||
void *ptr = memory_region_get_ram_ptr(&backend->mr);
|
||||
uint64_t sz = memory_region_size(&backend->mr);
|
||||
|
||||
os_mem_prealloc(fd, ptr, sz, backend->prealloc_threads, &local_err);
|
||||
os_mem_prealloc(fd, ptr, sz, ms->smp.cpus, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
@@ -243,44 +252,14 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value,
|
||||
}
|
||||
}
|
||||
|
||||
static void host_memory_backend_get_prealloc_threads(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque, Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
visit_type_uint32(v, name, &backend->prealloc_threads, errp);
|
||||
}
|
||||
|
||||
static void host_memory_backend_set_prealloc_threads(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque, Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
Error *local_err = NULL;
|
||||
uint32_t value;
|
||||
|
||||
visit_type_uint32(v, name, &value, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
if (value <= 0) {
|
||||
error_setg(&local_err,
|
||||
"property '%s' of %s doesn't take value '%d'",
|
||||
name, object_get_typename(obj), value);
|
||||
goto out;
|
||||
}
|
||||
backend->prealloc_threads = value;
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static void host_memory_backend_init(Object *obj)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
|
||||
/* TODO: convert access to globals to compat properties */
|
||||
backend->merge = machine_mem_merge(machine);
|
||||
backend->dump = machine_dump_guest_core(machine);
|
||||
backend->prealloc_threads = 1;
|
||||
backend->prealloc = mem_prealloc;
|
||||
}
|
||||
|
||||
static void host_memory_backend_post_init(Object *obj)
|
||||
@@ -334,6 +313,7 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(uc);
|
||||
HostMemoryBackendClass *bc = MEMORY_BACKEND_GET_CLASS(uc);
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
Error *local_err = NULL;
|
||||
void *ptr;
|
||||
uint64_t sz;
|
||||
@@ -400,7 +380,7 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
|
||||
*/
|
||||
if (backend->prealloc) {
|
||||
os_mem_prealloc(memory_region_get_fd(&backend->mr), ptr, sz,
|
||||
backend->prealloc_threads, &local_err);
|
||||
ms->smp.cpus, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
@@ -478,12 +458,6 @@ host_memory_backend_class_init(ObjectClass *oc, void *data)
|
||||
host_memory_backend_set_prealloc, &error_abort);
|
||||
object_class_property_set_description(oc, "prealloc",
|
||||
"Preallocate memory", &error_abort);
|
||||
object_class_property_add(oc, "prealloc-threads", "int",
|
||||
host_memory_backend_get_prealloc_threads,
|
||||
host_memory_backend_set_prealloc_threads,
|
||||
NULL, NULL, &error_abort);
|
||||
object_class_property_set_description(oc, "prealloc-threads",
|
||||
"Number of CPU threads to use for prealloc", &error_abort);
|
||||
object_class_property_add(oc, "size", "int",
|
||||
host_memory_backend_get_size,
|
||||
host_memory_backend_set_size,
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# dbus-vmstate.c
|
||||
dbus_vmstate_pre_save(void)
|
||||
dbus_vmstate_post_load(int version_id) "version_id: %d"
|
||||
dbus_vmstate_loading(const char *id) "id: %s"
|
||||
dbus_vmstate_saving(const char *id) "id: %s"
|
||||
@@ -363,7 +363,6 @@ char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp)
|
||||
|
||||
void bdrv_register(BlockDriver *bdrv)
|
||||
{
|
||||
assert(bdrv->format_name);
|
||||
QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
|
||||
}
|
||||
|
||||
@@ -483,8 +482,7 @@ static void coroutine_fn bdrv_create_co_entry(void *opaque)
|
||||
CreateCo *cco = opaque;
|
||||
assert(cco->drv);
|
||||
|
||||
ret = cco->drv->bdrv_co_create_opts(cco->drv,
|
||||
cco->filename, cco->opts, &local_err);
|
||||
ret = cco->drv->bdrv_co_create_opts(cco->filename, cco->opts, &local_err);
|
||||
error_propagate(&cco->err, local_err);
|
||||
cco->ret = ret;
|
||||
}
|
||||
@@ -534,168 +532,19 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for bdrv_create_file_fallback(): Resize @blk to at
|
||||
* least the given @minimum_size.
|
||||
*
|
||||
* On success, return @blk's actual length.
|
||||
* Otherwise, return -errno.
|
||||
*/
|
||||
static int64_t create_file_fallback_truncate(BlockBackend *blk,
|
||||
int64_t minimum_size, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int64_t size;
|
||||
int ret;
|
||||
|
||||
ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err);
|
||||
if (ret < 0 && ret != -ENOTSUP) {
|
||||
error_propagate(errp, local_err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size = blk_getlength(blk);
|
||||
if (size < 0) {
|
||||
error_free(local_err);
|
||||
error_setg_errno(errp, -size,
|
||||
"Failed to inquire the new image file's length");
|
||||
return size;
|
||||
}
|
||||
|
||||
if (size < minimum_size) {
|
||||
/* Need to grow the image, but we failed to do that */
|
||||
error_propagate(errp, local_err);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
error_free(local_err);
|
||||
local_err = NULL;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for bdrv_create_file_fallback(): Zero the first
|
||||
* sector to remove any potentially pre-existing image header.
|
||||
*/
|
||||
static int create_file_fallback_zero_first_sector(BlockBackend *blk,
|
||||
int64_t current_size,
|
||||
Error **errp)
|
||||
{
|
||||
int64_t bytes_to_clear;
|
||||
int ret;
|
||||
|
||||
bytes_to_clear = MIN(current_size, BDRV_SECTOR_SIZE);
|
||||
if (bytes_to_clear) {
|
||||
ret = blk_pwrite_zeroes(blk, 0, bytes_to_clear, BDRV_REQ_MAY_UNMAP);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret,
|
||||
"Failed to clear the new image's first sector");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple implementation of bdrv_co_create_opts for protocol drivers
|
||||
* which only support creation via opening a file
|
||||
* (usually existing raw storage device)
|
||||
*/
|
||||
int coroutine_fn bdrv_co_create_opts_simple(BlockDriver *drv,
|
||||
const char *filename,
|
||||
QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
QDict *options;
|
||||
int64_t size = 0;
|
||||
char *buf = NULL;
|
||||
PreallocMode prealloc;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
|
||||
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
|
||||
prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
|
||||
PREALLOC_MODE_OFF, &local_err);
|
||||
g_free(buf);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (prealloc != PREALLOC_MODE_OFF) {
|
||||
error_setg(errp, "Unsupported preallocation mode '%s'",
|
||||
PreallocMode_str(prealloc));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
options = qdict_new();
|
||||
qdict_put_str(options, "driver", drv->format_name);
|
||||
|
||||
blk = blk_new_open(filename, NULL, options,
|
||||
BDRV_O_RDWR | BDRV_O_RESIZE, errp);
|
||||
if (!blk) {
|
||||
error_prepend(errp, "Protocol driver '%s' does not support image "
|
||||
"creation, and opening the image failed: ",
|
||||
drv->format_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size = create_file_fallback_truncate(blk, size, errp);
|
||||
if (size < 0) {
|
||||
ret = size;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = create_file_fallback_zero_first_sector(blk, size, errp);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
blk_unref(blk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp)
|
||||
{
|
||||
BlockDriver *drv;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
drv = bdrv_find_protocol(filename, true, errp);
|
||||
if (drv == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return bdrv_create(drv, filename, opts, errp);
|
||||
}
|
||||
|
||||
int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
assert(bs != NULL);
|
||||
|
||||
if (!bs->drv) {
|
||||
error_setg(errp, "Block node '%s' is not opened", bs->filename);
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
if (!bs->drv->bdrv_co_delete_file) {
|
||||
error_setg(errp, "Driver '%s' does not support image deletion",
|
||||
bs->drv->format_name);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
ret = bs->drv->bdrv_co_delete_file(bs, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
ret = bdrv_create(drv, filename, opts, &local_err);
|
||||
error_propagate(errp, local_err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -996,28 +845,6 @@ static BlockdevDetectZeroesOptions bdrv_parse_detect_zeroes(QemuOpts *opts,
|
||||
return detect_zeroes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set open flags for aio engine
|
||||
*
|
||||
* Return 0 on success, -1 if the engine specified is invalid
|
||||
*/
|
||||
int bdrv_parse_aio(const char *mode, int *flags)
|
||||
{
|
||||
if (!strcmp(mode, "threads")) {
|
||||
/* do nothing, default */
|
||||
} else if (!strcmp(mode, "native")) {
|
||||
*flags |= BDRV_O_NATIVE_AIO;
|
||||
#ifdef CONFIG_LINUX_IO_URING
|
||||
} else if (!strcmp(mode, "io_uring")) {
|
||||
*flags |= BDRV_O_IO_URING;
|
||||
#endif
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set open flags for a given discard mode
|
||||
*
|
||||
@@ -1595,24 +1422,6 @@ QemuOptsList bdrv_runtime_opts = {
|
||||
},
|
||||
};
|
||||
|
||||
QemuOptsList bdrv_create_opts_simple = {
|
||||
.name = "simple-create-opts",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(bdrv_create_opts_simple.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = BLOCK_OPT_SIZE,
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "Virtual disk size"
|
||||
},
|
||||
{
|
||||
.name = BLOCK_OPT_PREALLOC,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Preallocation mode (allowed values: off)"
|
||||
},
|
||||
{ /* end of list */ }
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Common part for opening disk images and files
|
||||
*
|
||||
@@ -1903,6 +1712,8 @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
|
||||
bool *tighten_restrictions, Error **errp);
|
||||
static void bdrv_child_abort_perm_update(BdrvChild *c);
|
||||
static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);
|
||||
static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
|
||||
uint64_t *shared_perm);
|
||||
|
||||
typedef struct BlockReopenQueueEntry {
|
||||
bool prepared;
|
||||
@@ -2126,8 +1937,8 @@ static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms,
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
|
||||
uint64_t *shared_perm)
|
||||
static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
|
||||
uint64_t *shared_perm)
|
||||
{
|
||||
BdrvChild *c;
|
||||
uint64_t cumulative_perms = 0;
|
||||
@@ -2165,19 +1976,18 @@ char *bdrv_perm_names(uint64_t perm)
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
GString *result = g_string_sized_new(30);
|
||||
char *result = g_strdup("");
|
||||
struct perm_name *p;
|
||||
|
||||
for (p = permissions; p->name; p++) {
|
||||
if (perm & p->perm) {
|
||||
if (result->len > 0) {
|
||||
g_string_append(result, ", ");
|
||||
}
|
||||
g_string_append(result, p->name);
|
||||
char *old = result;
|
||||
result = g_strdup_printf("%s%s%s", old, *old ? ", " : "", p->name);
|
||||
g_free(old);
|
||||
}
|
||||
}
|
||||
|
||||
return g_string_free(result, FALSE);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2602,13 +2412,13 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
|
||||
if (bdrv_get_aio_context(child_bs) != ctx) {
|
||||
ret = bdrv_try_set_aio_context(child_bs, ctx, &local_err);
|
||||
if (ret < 0 && child_role->can_set_aio_ctx) {
|
||||
GSList *ignore = g_slist_prepend(NULL, child);
|
||||
GSList *ignore = g_slist_prepend(NULL, child);;
|
||||
ctx = bdrv_get_aio_context(child_bs);
|
||||
if (child_role->can_set_aio_ctx(child, ctx, &ignore, NULL)) {
|
||||
error_free(local_err);
|
||||
ret = 0;
|
||||
g_slist_free(ignore);
|
||||
ignore = g_slist_prepend(NULL, child);
|
||||
ignore = g_slist_prepend(NULL, child);;
|
||||
child_role->set_aio_ctx(child, ctx, &ignore);
|
||||
}
|
||||
g_slist_free(ignore);
|
||||
@@ -2617,7 +2427,6 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
|
||||
error_propagate(errp, local_err);
|
||||
g_free(child);
|
||||
bdrv_abort_perm_update(child_bs);
|
||||
bdrv_unref(child_bs);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -2667,7 +2476,10 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
|
||||
|
||||
static void bdrv_detach_child(BdrvChild *child)
|
||||
{
|
||||
QLIST_SAFE_REMOVE(child, next);
|
||||
if (child->next.le_prev) {
|
||||
QLIST_REMOVE(child, next);
|
||||
child->next.le_prev = NULL;
|
||||
}
|
||||
|
||||
bdrv_replace_child(child, NULL);
|
||||
|
||||
@@ -3725,15 +3537,6 @@ cleanup_perm:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
|
||||
BlockDriverState *bs = bs_entry->state.bs;
|
||||
|
||||
if (bs->drv->bdrv_reopen_commit_post)
|
||||
bs->drv->bdrv_reopen_commit_post(&bs_entry->state);
|
||||
}
|
||||
}
|
||||
cleanup:
|
||||
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
|
||||
if (ret) {
|
||||
@@ -3817,29 +3620,6 @@ static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs,
|
||||
*shared = cumulative_shared_perms;
|
||||
}
|
||||
|
||||
static bool bdrv_reopen_can_attach(BlockDriverState *parent,
|
||||
BdrvChild *child,
|
||||
BlockDriverState *new_child,
|
||||
Error **errp)
|
||||
{
|
||||
AioContext *parent_ctx = bdrv_get_aio_context(parent);
|
||||
AioContext *child_ctx = bdrv_get_aio_context(new_child);
|
||||
GSList *ignore;
|
||||
bool ret;
|
||||
|
||||
ignore = g_slist_prepend(NULL, child);
|
||||
ret = bdrv_can_set_aio_context(new_child, parent_ctx, &ignore, NULL);
|
||||
g_slist_free(ignore);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ignore = g_slist_prepend(NULL, child);
|
||||
ret = bdrv_can_set_aio_context(parent, child_ctx, &ignore, errp);
|
||||
g_slist_free(ignore);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a BDRVReopenState and check if the value of 'backing' in the
|
||||
* reopen_state->options QDict is valid or not.
|
||||
@@ -3891,11 +3671,14 @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state,
|
||||
}
|
||||
|
||||
/*
|
||||
* Check AioContext compatibility so that the bdrv_set_backing_hd() call in
|
||||
* bdrv_reopen_commit() won't fail.
|
||||
* TODO: before removing the x- prefix from x-blockdev-reopen we
|
||||
* should move the new backing file into the right AioContext
|
||||
* instead of returning an error.
|
||||
*/
|
||||
if (new_backing_bs) {
|
||||
if (!bdrv_reopen_can_attach(bs, bs->backing, new_backing_bs, errp)) {
|
||||
if (bdrv_get_aio_context(new_backing_bs) != bdrv_get_aio_context(bs)) {
|
||||
error_setg(errp, "Cannot use a new backing file "
|
||||
"with a different AioContext");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
@@ -4397,7 +4180,6 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
|
||||
bdrv_ref(from);
|
||||
|
||||
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
|
||||
assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
|
||||
bdrv_drained_begin(from);
|
||||
|
||||
/* Put all parents into @list and calculate their cumulative permissions */
|
||||
@@ -5002,15 +4784,14 @@ BlockDriverState *bdrv_find_node(const char *node_name)
|
||||
}
|
||||
|
||||
/* Put this QMP function here so it can access the static graph_bdrv_states. */
|
||||
BlockDeviceInfoList *bdrv_named_nodes_list(bool flat,
|
||||
Error **errp)
|
||||
BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp)
|
||||
{
|
||||
BlockDeviceInfoList *list, *entry;
|
||||
BlockDriverState *bs;
|
||||
|
||||
list = NULL;
|
||||
QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) {
|
||||
BlockDeviceInfo *info = bdrv_block_device_info(NULL, bs, flat, errp);
|
||||
BlockDeviceInfo *info = bdrv_block_device_info(NULL, bs, errp);
|
||||
if (!info) {
|
||||
qapi_free_BlockDeviceInfoList(list);
|
||||
return NULL;
|
||||
@@ -5091,23 +4872,36 @@ static void xdbg_graph_add_node(XDbgBlockGraphConstructor *gr, void *node,
|
||||
static void xdbg_graph_add_edge(XDbgBlockGraphConstructor *gr, void *parent,
|
||||
const BdrvChild *child)
|
||||
{
|
||||
BlockPermission qapi_perm;
|
||||
typedef struct {
|
||||
unsigned int flag;
|
||||
BlockPermission num;
|
||||
} PermissionMap;
|
||||
|
||||
static const PermissionMap permissions[] = {
|
||||
{ BLK_PERM_CONSISTENT_READ, BLOCK_PERMISSION_CONSISTENT_READ },
|
||||
{ BLK_PERM_WRITE, BLOCK_PERMISSION_WRITE },
|
||||
{ BLK_PERM_WRITE_UNCHANGED, BLOCK_PERMISSION_WRITE_UNCHANGED },
|
||||
{ BLK_PERM_RESIZE, BLOCK_PERMISSION_RESIZE },
|
||||
{ BLK_PERM_GRAPH_MOD, BLOCK_PERMISSION_GRAPH_MOD },
|
||||
{ 0, 0 }
|
||||
};
|
||||
const PermissionMap *p;
|
||||
XDbgBlockGraphEdge *edge;
|
||||
|
||||
QEMU_BUILD_BUG_ON(1UL << (ARRAY_SIZE(permissions) - 1) != BLK_PERM_ALL + 1);
|
||||
|
||||
edge = g_new0(XDbgBlockGraphEdge, 1);
|
||||
|
||||
edge->parent = xdbg_graph_node_num(gr, parent);
|
||||
edge->child = xdbg_graph_node_num(gr, child->bs);
|
||||
edge->name = g_strdup(child->name);
|
||||
|
||||
for (qapi_perm = 0; qapi_perm < BLOCK_PERMISSION__MAX; qapi_perm++) {
|
||||
uint64_t flag = bdrv_qapi_perm_to_blk_perm(qapi_perm);
|
||||
|
||||
if (flag & child->perm) {
|
||||
QAPI_LIST_ADD(edge->perm, qapi_perm);
|
||||
for (p = permissions; p->flag; p++) {
|
||||
if (p->flag & child->perm) {
|
||||
QAPI_LIST_ADD(edge->perm, p->num);
|
||||
}
|
||||
if (flag & child->shared_perm) {
|
||||
QAPI_LIST_ADD(edge->shared_perm, qapi_perm);
|
||||
if (p->flag & child->shared_perm) {
|
||||
QAPI_LIST_ADD(edge->shared_perm, p->num);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5973,11 +5767,12 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create parameter list */
|
||||
create_opts = qemu_opts_append(create_opts, drv->create_opts);
|
||||
create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
|
||||
|
||||
/* Create parameter list with default values */
|
||||
opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
|
||||
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, &error_abort);
|
||||
|
||||
/* Parse -o options */
|
||||
if (options) {
|
||||
@@ -5987,13 +5782,6 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
}
|
||||
}
|
||||
|
||||
if (!qemu_opt_get(opts, BLOCK_OPT_SIZE)) {
|
||||
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, &error_abort);
|
||||
} else if (img_size != UINT64_C(-1)) {
|
||||
error_setg(errp, "The image size must be specified only once");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (base_filename) {
|
||||
qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename, &local_err);
|
||||
if (local_err) {
|
||||
@@ -6397,55 +6185,65 @@ int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts,
|
||||
return bs->drv->bdrv_amend_options(bs, opts, status_cb, cb_opaque, errp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function checks whether the given @to_replace is allowed to be
|
||||
* replaced by a node that always shows the same data as @bs. This is
|
||||
* used for example to verify whether the mirror job can replace
|
||||
* @to_replace by the target mirrored from @bs.
|
||||
* To be replaceable, @bs and @to_replace may either be guaranteed to
|
||||
* always show the same data (because they are only connected through
|
||||
* filters), or some driver may allow replacing one of its children
|
||||
* because it can guarantee that this child's data is not visible at
|
||||
* all (for example, for dissenting quorum children that have no other
|
||||
* parents).
|
||||
/* This function will be called by the bdrv_recurse_is_first_non_filter method
|
||||
* of block filter and by bdrv_is_first_non_filter.
|
||||
* It is used to test if the given bs is the candidate or recurse more in the
|
||||
* node graph.
|
||||
*/
|
||||
bool bdrv_recurse_can_replace(BlockDriverState *bs,
|
||||
BlockDriverState *to_replace)
|
||||
bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate)
|
||||
{
|
||||
/* return false if basic checks fails */
|
||||
if (!bs || !bs->drv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bs == to_replace) {
|
||||
return true;
|
||||
/* the code reached a non block filter driver -> check if the bs is
|
||||
* the same as the candidate. It's the recursion termination condition.
|
||||
*/
|
||||
if (!bs->drv->is_filter) {
|
||||
return bs == candidate;
|
||||
}
|
||||
/* Down this path the driver is a block filter driver */
|
||||
|
||||
/* If the block filter recursion method is defined use it to recurse down
|
||||
* the node graph.
|
||||
*/
|
||||
if (bs->drv->bdrv_recurse_is_first_non_filter) {
|
||||
return bs->drv->bdrv_recurse_is_first_non_filter(bs, candidate);
|
||||
}
|
||||
|
||||
/* See what the driver can do */
|
||||
if (bs->drv->bdrv_recurse_can_replace) {
|
||||
return bs->drv->bdrv_recurse_can_replace(bs, to_replace);
|
||||
}
|
||||
|
||||
/* For filters without an own implementation, we can recurse on our own */
|
||||
if (bs->drv->is_filter) {
|
||||
BdrvChild *child = bs->file ?: bs->backing;
|
||||
return bdrv_recurse_can_replace(child->bs, to_replace);
|
||||
}
|
||||
|
||||
/* Safe default */
|
||||
/* the driver is a block filter but don't allow to recurse -> return false
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the given @node_name can be replaced by a node that
|
||||
* has the same data as @parent_bs. If so, return @node_name's BDS;
|
||||
* NULL otherwise.
|
||||
*
|
||||
* @node_name must be a (recursive) *child of @parent_bs (or this
|
||||
* function will return NULL).
|
||||
*
|
||||
* The result (whether the node can be replaced or not) is only valid
|
||||
* for as long as no graph or permission changes occur.
|
||||
/* This function checks if the candidate is the first non filter bs down it's
|
||||
* bs chain. Since we don't have pointers to parents it explore all bs chains
|
||||
* from the top. Some filters can choose not to pass down the recursion.
|
||||
*/
|
||||
bool bdrv_is_first_non_filter(BlockDriverState *candidate)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BdrvNextIterator it;
|
||||
|
||||
/* walk down the bs forest recursively */
|
||||
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
||||
bool perm;
|
||||
|
||||
/* try to recurse in this top level bs */
|
||||
perm = bdrv_recurse_is_first_non_filter(bs, candidate);
|
||||
|
||||
/* candidate is the first non filter */
|
||||
if (perm) {
|
||||
bdrv_next_cleanup(&it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockDriverState *check_to_replace_node(BlockDriverState *parent_bs,
|
||||
const char *node_name, Error **errp)
|
||||
{
|
||||
@@ -6470,11 +6268,8 @@ BlockDriverState *check_to_replace_node(BlockDriverState *parent_bs,
|
||||
* Another benefit is that this tests exclude backing files which are
|
||||
* blocked by the backing blockers.
|
||||
*/
|
||||
if (!bdrv_recurse_can_replace(parent_bs, to_replace_bs)) {
|
||||
error_setg(errp, "Cannot replace '%s' by a node mirrored from '%s', "
|
||||
"because it cannot be guaranteed that doing so would not "
|
||||
"lead to an abrupt change of visible data",
|
||||
node_name, parent_bs->node_name);
|
||||
if (!bdrv_recurse_is_first_non_filter(parent_bs, to_replace_bs)) {
|
||||
error_setg(errp, "Only top most non filter can be replaced");
|
||||
to_replace_bs = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
+1
-8
@@ -18,7 +18,6 @@ block-obj-y += block-backend.o snapshot.o qapi.o
|
||||
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
|
||||
block-obj-$(CONFIG_POSIX) += file-posix.o
|
||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
block-obj-$(CONFIG_LINUX_IO_URING) += io_uring.o
|
||||
block-obj-y += null.o mirror.o commit.o io.o create.o
|
||||
block-obj-y += throttle-groups.o
|
||||
block-obj-$(CONFIG_LINUX) += nvme.o
|
||||
@@ -44,12 +43,8 @@ block-obj-y += crypto.o
|
||||
|
||||
block-obj-y += aio_task.o
|
||||
block-obj-y += backup-top.o
|
||||
block-obj-y += filter-compress.o
|
||||
common-obj-y += monitor/
|
||||
|
||||
block-obj-y += stream.o
|
||||
|
||||
common-obj-y += qapi-sysemu.o
|
||||
common-obj-y += stream.o
|
||||
|
||||
nfs.o-libs := $(LIBNFS_LIBS)
|
||||
iscsi.o-cflags := $(LIBISCSI_CFLAGS)
|
||||
@@ -70,7 +65,5 @@ block-obj-$(if $(CONFIG_LZFSE),m,n) += dmg-lzfse.o
|
||||
dmg-lzfse.o-libs := $(LZFSE_LIBS)
|
||||
qcow.o-libs := -lz
|
||||
linux-aio.o-libs := -laio
|
||||
io_uring.o-cflags := $(LINUX_IO_URING_CFLAGS)
|
||||
io_uring.o-libs := $(LINUX_IO_URING_LIBS)
|
||||
parallels.o-cflags := $(LIBXML2_CFLAGS)
|
||||
parallels.o-libs := $(LIBXML2_LIBS)
|
||||
+16
-22
@@ -38,7 +38,6 @@ typedef struct BDRVBackupTopState {
|
||||
BlockCopyState *bcs;
|
||||
BdrvChild *target;
|
||||
bool active;
|
||||
int64_t cluster_size;
|
||||
} BDRVBackupTopState;
|
||||
|
||||
static coroutine_fn int backup_top_co_preadv(
|
||||
@@ -49,17 +48,11 @@ static coroutine_fn int backup_top_co_preadv(
|
||||
}
|
||||
|
||||
static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, BdrvRequestFlags flags)
|
||||
uint64_t bytes)
|
||||
{
|
||||
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);
|
||||
uint64_t end = QEMU_ALIGN_UP(offset + bytes, s->bcs->cluster_size);
|
||||
uint64_t off = QEMU_ALIGN_DOWN(offset, s->bcs->cluster_size);
|
||||
|
||||
return block_copy(s->bcs, off, end - off, NULL);
|
||||
}
|
||||
@@ -67,7 +60,7 @@ static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
|
||||
static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
int ret = backup_top_cbw(bs, offset, bytes, 0);
|
||||
int ret = backup_top_cbw(bs, offset, bytes);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -78,7 +71,7 @@ static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs,
|
||||
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);
|
||||
int ret = backup_top_cbw(bs, offset, bytes);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -91,9 +84,11 @@ static coroutine_fn int backup_top_co_pwritev(BlockDriverState *bs,
|
||||
uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
int ret = backup_top_cbw(bs, offset, bytes, flags);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
if (!(flags & BDRV_REQ_WRITE_UNCHANGED)) {
|
||||
int ret = backup_top_cbw(bs, offset, bytes);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags);
|
||||
@@ -201,13 +196,8 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
|
||||
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);
|
||||
state = top->opaque;
|
||||
|
||||
bdrv_ref(target);
|
||||
state->target = bdrv_attach_child(top, target, "target", &child_file, errp);
|
||||
@@ -239,7 +229,6 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
state->cluster_size = cluster_size;
|
||||
state->bcs = block_copy_state_new(top->backing, state->target,
|
||||
cluster_size, write_flags, &local_err);
|
||||
if (local_err) {
|
||||
@@ -269,6 +258,9 @@ fail:
|
||||
void bdrv_backup_top_drop(BlockDriverState *bs)
|
||||
{
|
||||
BDRVBackupTopState *s = bs->opaque;
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
bdrv_drained_begin(bs);
|
||||
|
||||
@@ -282,4 +274,6 @@ void bdrv_backup_top_drop(BlockDriverState *bs)
|
||||
bdrv_drained_end(bs);
|
||||
|
||||
bdrv_unref(bs);
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
+13
-13
@@ -102,7 +102,7 @@ static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
|
||||
|
||||
if (ret < 0 && job->bitmap_mode == BITMAP_SYNC_MODE_ALWAYS) {
|
||||
/* If we failed and synced, merge in the bits we didn't copy: */
|
||||
bdrv_dirty_bitmap_merge_internal(bm, block_copy_dirty_bitmap(job->bcs),
|
||||
bdrv_dirty_bitmap_merge_internal(bm, job->bcs->copy_bitmap,
|
||||
NULL, true);
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,7 @@ static void backup_abort(Job *job)
|
||||
static void backup_clean(Job *job)
|
||||
{
|
||||
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
|
||||
|
||||
bdrv_backup_top_drop(s->backup_top);
|
||||
}
|
||||
|
||||
@@ -141,8 +142,7 @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_set_dirty_bitmap(block_copy_dirty_bitmap(backup_job->bcs), 0,
|
||||
backup_job->len);
|
||||
bdrv_set_dirty_bitmap(backup_job->bcs->copy_bitmap, 0, backup_job->len);
|
||||
}
|
||||
|
||||
static BlockErrorAction backup_error_action(BackupBlockJob *job,
|
||||
@@ -187,7 +187,7 @@ static int coroutine_fn backup_loop(BackupBlockJob *job)
|
||||
BdrvDirtyBitmapIter *bdbi;
|
||||
int ret = 0;
|
||||
|
||||
bdbi = bdrv_dirty_iter_new(block_copy_dirty_bitmap(job->bcs));
|
||||
bdbi = bdrv_dirty_iter_new(job->bcs->copy_bitmap);
|
||||
while ((offset = bdrv_dirty_iter_next(bdbi)) != -1) {
|
||||
do {
|
||||
if (yield_and_check(job)) {
|
||||
@@ -207,14 +207,14 @@ static int coroutine_fn backup_loop(BackupBlockJob *job)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void backup_init_bcs_bitmap(BackupBlockJob *job)
|
||||
static void backup_init_copy_bitmap(BackupBlockJob *job)
|
||||
{
|
||||
bool ret;
|
||||
uint64_t estimate;
|
||||
BdrvDirtyBitmap *bcs_bitmap = block_copy_dirty_bitmap(job->bcs);
|
||||
|
||||
if (job->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
|
||||
ret = bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap,
|
||||
ret = bdrv_dirty_bitmap_merge_internal(job->bcs->copy_bitmap,
|
||||
job->sync_bitmap,
|
||||
NULL, true);
|
||||
assert(ret);
|
||||
} else {
|
||||
@@ -223,12 +223,12 @@ static void backup_init_bcs_bitmap(BackupBlockJob *job)
|
||||
* 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);
|
||||
job->bcs->skip_unallocated = true;
|
||||
}
|
||||
bdrv_set_dirty_bitmap(bcs_bitmap, 0, job->len);
|
||||
bdrv_set_dirty_bitmap(job->bcs->copy_bitmap, 0, job->len);
|
||||
}
|
||||
|
||||
estimate = bdrv_get_dirty_count(bcs_bitmap);
|
||||
estimate = bdrv_get_dirty_count(job->bcs->copy_bitmap);
|
||||
job_progress_set_remaining(&job->common.job, estimate);
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
|
||||
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
|
||||
int ret = 0;
|
||||
|
||||
backup_init_bcs_bitmap(s);
|
||||
backup_init_copy_bitmap(s);
|
||||
|
||||
if (s->sync_mode == MIRROR_SYNC_MODE_TOP) {
|
||||
int64_t offset = 0;
|
||||
@@ -256,12 +256,12 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
|
||||
|
||||
offset += count;
|
||||
}
|
||||
block_copy_set_skip_unallocated(s->bcs, false);
|
||||
s->bcs->skip_unallocated = false;
|
||||
}
|
||||
|
||||
if (s->sync_mode == MIRROR_SYNC_MODE_NONE) {
|
||||
/*
|
||||
* All bits are set in bcs bitmap to allow any cluster to be copied.
|
||||
* All bits are set in copy_bitmap to allow any cluster to be copied.
|
||||
* This does not actually require them to be copied.
|
||||
*/
|
||||
while (!job_is_cancelled(job)) {
|
||||
|
||||
+10
-10
@@ -268,18 +268,18 @@ static int blkverify_co_flush(BlockDriverState *bs)
|
||||
return bdrv_co_flush(s->test_file->bs);
|
||||
}
|
||||
|
||||
static bool blkverify_recurse_can_replace(BlockDriverState *bs,
|
||||
BlockDriverState *to_replace)
|
||||
static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
|
||||
/*
|
||||
* blkverify quits the whole qemu process if there is a mismatch
|
||||
* between bs->file->bs and s->test_file->bs. Therefore, we know
|
||||
* know that both must match bs and we can recurse down to either.
|
||||
*/
|
||||
return bdrv_recurse_can_replace(bs->file->bs, to_replace) ||
|
||||
bdrv_recurse_can_replace(s->test_file->bs, to_replace);
|
||||
bool perm = bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
|
||||
|
||||
if (perm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return bdrv_recurse_is_first_non_filter(s->test_file->bs, candidate);
|
||||
}
|
||||
|
||||
static void blkverify_refresh_filename(BlockDriverState *bs)
|
||||
@@ -327,7 +327,7 @@ static BlockDriver bdrv_blkverify = {
|
||||
.bdrv_co_flush = blkverify_co_flush,
|
||||
|
||||
.is_filter = true,
|
||||
.bdrv_recurse_can_replace = blkverify_recurse_can_replace,
|
||||
.bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter,
|
||||
};
|
||||
|
||||
static void bdrv_blkverify_init(void)
|
||||
|
||||
+78
-128
@@ -1140,22 +1140,16 @@ static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
|
||||
{
|
||||
assert(blk->in_flight > 0);
|
||||
|
||||
if (blk->quiesce_counter && !blk->disable_request_queuing) {
|
||||
blk_dec_in_flight(blk);
|
||||
qemu_co_queue_wait(&blk->queued_requests, NULL);
|
||||
blk_inc_in_flight(blk);
|
||||
}
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
static int coroutine_fn
|
||||
blk_do_preadv(BlockBackend *blk, int64_t offset, unsigned int bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
|
||||
unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
BlockDriverState *bs;
|
||||
@@ -1184,24 +1178,10 @@ blk_do_preadv(BlockBackend *blk, int64_t offset, unsigned int bytes,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
|
||||
unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
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() */
|
||||
static int coroutine_fn
|
||||
blk_do_pwritev_part(BlockBackend *blk, int64_t offset, unsigned int bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset,
|
||||
unsigned int bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
BlockDriverState *bs;
|
||||
@@ -1234,20 +1214,6 @@ blk_do_pwritev_part(BlockBackend *blk, int64_t offset, unsigned int bytes,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset,
|
||||
unsigned int bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
ret = blk_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,
|
||||
unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
@@ -1268,7 +1234,7 @@ static void blk_read_entry(void *opaque)
|
||||
BlkRwCo *rwco = opaque;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
rwco->ret = blk_do_preadv(rwco->blk, rwco->offset, qiov->size,
|
||||
rwco->ret = blk_co_preadv(rwco->blk, rwco->offset, qiov->size,
|
||||
qiov, rwco->flags);
|
||||
aio_wait_kick();
|
||||
}
|
||||
@@ -1278,8 +1244,8 @@ 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);
|
||||
rwco->ret = blk_co_pwritev(rwco->blk, rwco->offset, qiov->size,
|
||||
qiov, rwco->flags);
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
@@ -1296,7 +1262,6 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
|
||||
.ret = NOT_DONE,
|
||||
};
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
if (qemu_in_coroutine()) {
|
||||
/* Fast-path if already in coroutine context */
|
||||
co_entry(&rwco);
|
||||
@@ -1305,7 +1270,6 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
|
||||
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;
|
||||
}
|
||||
@@ -1423,8 +1387,14 @@ static void blk_aio_read_entry(void *opaque)
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
if (rwco->blk->quiesce_counter) {
|
||||
blk_dec_in_flight(rwco->blk);
|
||||
blk_wait_while_drained(rwco->blk);
|
||||
blk_inc_in_flight(rwco->blk);
|
||||
}
|
||||
|
||||
assert(qiov->size == acb->bytes);
|
||||
rwco->ret = blk_do_preadv(rwco->blk, rwco->offset, acb->bytes,
|
||||
rwco->ret = blk_co_preadv(rwco->blk, rwco->offset, acb->bytes,
|
||||
qiov, rwco->flags);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
@@ -1435,9 +1405,15 @@ static void blk_aio_write_entry(void *opaque)
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
if (rwco->blk->quiesce_counter) {
|
||||
blk_dec_in_flight(rwco->blk);
|
||||
blk_wait_while_drained(rwco->blk);
|
||||
blk_inc_in_flight(rwco->blk);
|
||||
}
|
||||
|
||||
assert(!qiov || qiov->size == acb->bytes);
|
||||
rwco->ret = blk_do_pwritev_part(rwco->blk, rwco->offset, acb->bytes,
|
||||
qiov, 0, rwco->flags);
|
||||
rwco->ret = blk_co_pwritev(rwco->blk, rwco->offset, acb->bytes,
|
||||
qiov, rwco->flags);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
@@ -1512,6 +1488,38 @@ BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset,
|
||||
blk_aio_write_entry, flags, cb, opaque);
|
||||
}
|
||||
|
||||
static void blk_aio_flush_entry(void *opaque)
|
||||
{
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
|
||||
rwco->ret = blk_co_flush(rwco->blk);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_flush(BlockBackend *blk,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return blk_aio_prwv(blk, 0, 0, NULL, blk_aio_flush_entry, 0, cb, opaque);
|
||||
}
|
||||
|
||||
static void blk_aio_pdiscard_entry(void *opaque)
|
||||
{
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
|
||||
rwco->ret = blk_co_pdiscard(rwco->blk, rwco->offset, acb->bytes);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk,
|
||||
int64_t offset, int bytes,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_pdiscard_entry, 0,
|
||||
cb, opaque);
|
||||
}
|
||||
|
||||
void blk_aio_cancel(BlockAIOCB *acb)
|
||||
{
|
||||
bdrv_aio_cancel(acb);
|
||||
@@ -1522,9 +1530,7 @@ void blk_aio_cancel_async(BlockAIOCB *acb)
|
||||
bdrv_aio_cancel_async(acb);
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
static int coroutine_fn
|
||||
blk_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
|
||||
int blk_co_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
|
||||
{
|
||||
blk_wait_while_drained(blk);
|
||||
|
||||
@@ -1540,7 +1546,8 @@ 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);
|
||||
rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset,
|
||||
qiov->iov[0].iov_base);
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
@@ -1554,7 +1561,7 @@ static void blk_aio_ioctl_entry(void *opaque)
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
|
||||
rwco->ret = blk_do_ioctl(rwco->blk, rwco->offset, rwco->iobuf);
|
||||
rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset, rwco->iobuf);
|
||||
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
@@ -1565,9 +1572,7 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
|
||||
return blk_aio_prwv(blk, req, 0, buf, blk_aio_ioctl_entry, 0, cb, opaque);
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
static int coroutine_fn
|
||||
blk_do_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
|
||||
int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -1581,50 +1586,7 @@ blk_do_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
|
||||
return bdrv_co_pdiscard(blk->root, offset, bytes);
|
||||
}
|
||||
|
||||
static void blk_aio_pdiscard_entry(void *opaque)
|
||||
{
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
|
||||
rwco->ret = blk_do_pdiscard(rwco->blk, rwco->offset, acb->bytes);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk,
|
||||
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, int bytes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
ret = blk_do_pdiscard(blk, offset, bytes);
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
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() */
|
||||
static int coroutine_fn blk_do_flush(BlockBackend *blk)
|
||||
int blk_co_flush(BlockBackend *blk)
|
||||
{
|
||||
blk_wait_while_drained(blk);
|
||||
|
||||
@@ -1635,36 +1597,10 @@ static int coroutine_fn blk_do_flush(BlockBackend *blk)
|
||||
return bdrv_co_flush(blk_bs(blk));
|
||||
}
|
||||
|
||||
static void blk_aio_flush_entry(void *opaque)
|
||||
{
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
|
||||
rwco->ret = blk_do_flush(rwco->blk);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_flush(BlockBackend *blk,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return blk_aio_prwv(blk, 0, 0, NULL, blk_aio_flush_entry, 0, cb, opaque);
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_flush(BlockBackend *blk)
|
||||
{
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(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);
|
||||
rwco->ret = blk_co_flush(rwco->blk);
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
@@ -2147,6 +2083,20 @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
|
||||
return bdrv_truncate(blk->root, offset, exact, prealloc, errp);
|
||||
}
|
||||
|
||||
static void blk_pdiscard_entry(void *opaque)
|
||||
{
|
||||
BlkRwCo *rwco = opaque;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
rwco->ret = blk_co_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);
|
||||
}
|
||||
|
||||
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
|
||||
int64_t pos, int size)
|
||||
{
|
||||
|
||||
+89
-308
@@ -24,136 +24,37 @@
|
||||
#define BLOCK_COPY_MAX_BUFFER (1 * MiB)
|
||||
#define BLOCK_COPY_MAX_MEM (128 * MiB)
|
||||
|
||||
typedef struct BlockCopyInFlightReq {
|
||||
int64_t offset;
|
||||
int64_t bytes;
|
||||
QLIST_ENTRY(BlockCopyInFlightReq) list;
|
||||
CoQueue wait_queue; /* coroutines blocked on this request */
|
||||
} BlockCopyInFlightReq;
|
||||
|
||||
typedef struct BlockCopyState {
|
||||
/*
|
||||
* BdrvChild objects are not owned or managed by block-copy. They are
|
||||
* provided by block-copy user and user is responsible for appropriate
|
||||
* permissions on these children.
|
||||
*/
|
||||
BdrvChild *source;
|
||||
BdrvChild *target;
|
||||
BdrvDirtyBitmap *copy_bitmap;
|
||||
int64_t in_flight_bytes;
|
||||
int64_t cluster_size;
|
||||
bool use_copy_range;
|
||||
int64_t copy_size;
|
||||
uint64_t len;
|
||||
QLIST_HEAD(, BlockCopyInFlightReq) inflight_reqs;
|
||||
|
||||
BdrvRequestFlags write_flags;
|
||||
|
||||
/*
|
||||
* skip_unallocated:
|
||||
*
|
||||
* Used by sync=top jobs, which first scan the source node for unallocated
|
||||
* areas and clear them in the copy_bitmap. During this process, the bitmap
|
||||
* is thus not fully initialized: It may still have bits set for areas that
|
||||
* are unallocated and should actually not be copied.
|
||||
*
|
||||
* This is indicated by skip_unallocated.
|
||||
*
|
||||
* In this case, block_copy() will query the source’s allocation status,
|
||||
* skip unallocated regions, clear them in the copy_bitmap, and invoke
|
||||
* block_copy_reset_unallocated() every time it does.
|
||||
*/
|
||||
bool skip_unallocated;
|
||||
|
||||
ProgressMeter *progress;
|
||||
/* progress_bytes_callback: called when some copying progress is done. */
|
||||
ProgressBytesCallbackFunc progress_bytes_callback;
|
||||
void *progress_opaque;
|
||||
|
||||
SharedResource *mem;
|
||||
} BlockCopyState;
|
||||
|
||||
static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
|
||||
int64_t offset,
|
||||
int64_t bytes)
|
||||
static void coroutine_fn block_copy_wait_inflight_reqs(BlockCopyState *s,
|
||||
int64_t start,
|
||||
int64_t end)
|
||||
{
|
||||
BlockCopyInFlightReq *req;
|
||||
bool waited;
|
||||
|
||||
QLIST_FOREACH(req, &s->inflight_reqs, list) {
|
||||
if (offset + bytes > req->offset && offset < req->offset + req->bytes) {
|
||||
return req;
|
||||
do {
|
||||
waited = false;
|
||||
QLIST_FOREACH(req, &s->inflight_reqs, list) {
|
||||
if (end > req->start_byte && start < req->end_byte) {
|
||||
qemu_co_queue_wait(&req->wait_queue, NULL);
|
||||
waited = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
} while (waited);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are no intersecting requests return false. Otherwise, wait for the
|
||||
* first found intersecting request to finish and return true.
|
||||
*/
|
||||
static bool coroutine_fn block_copy_wait_one(BlockCopyState *s, int64_t offset,
|
||||
int64_t bytes)
|
||||
{
|
||||
BlockCopyInFlightReq *req = find_conflicting_inflight_req(s, offset, bytes);
|
||||
|
||||
if (!req) {
|
||||
return false;
|
||||
}
|
||||
|
||||
qemu_co_queue_wait(&req->wait_queue, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Called only on full-dirty region */
|
||||
static void block_copy_inflight_req_begin(BlockCopyState *s,
|
||||
BlockCopyInFlightReq *req,
|
||||
int64_t offset, int64_t bytes)
|
||||
int64_t start, int64_t end)
|
||||
{
|
||||
assert(!find_conflicting_inflight_req(s, offset, bytes));
|
||||
|
||||
bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes);
|
||||
s->in_flight_bytes += bytes;
|
||||
|
||||
req->offset = offset;
|
||||
req->bytes = bytes;
|
||||
req->start_byte = start;
|
||||
req->end_byte = end;
|
||||
qemu_co_queue_init(&req->wait_queue);
|
||||
QLIST_INSERT_HEAD(&s->inflight_reqs, req, list);
|
||||
}
|
||||
|
||||
/*
|
||||
* block_copy_inflight_req_shrink
|
||||
*
|
||||
* Drop the tail of the request to be handled later. Set dirty bits back and
|
||||
* wake up all requests waiting for us (may be some of them are not intersecting
|
||||
* with shrunk request)
|
||||
*/
|
||||
static void coroutine_fn block_copy_inflight_req_shrink(BlockCopyState *s,
|
||||
BlockCopyInFlightReq *req, int64_t new_bytes)
|
||||
static void coroutine_fn block_copy_inflight_req_end(BlockCopyInFlightReq *req)
|
||||
{
|
||||
if (new_bytes == req->bytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(new_bytes > 0 && new_bytes < req->bytes);
|
||||
|
||||
s->in_flight_bytes -= req->bytes - new_bytes;
|
||||
bdrv_set_dirty_bitmap(s->copy_bitmap,
|
||||
req->offset + new_bytes, req->bytes - new_bytes);
|
||||
|
||||
req->bytes = new_bytes;
|
||||
qemu_co_queue_restart_all(&req->wait_queue);
|
||||
}
|
||||
|
||||
static void coroutine_fn block_copy_inflight_req_end(BlockCopyState *s,
|
||||
BlockCopyInFlightReq *req,
|
||||
int ret)
|
||||
{
|
||||
s->in_flight_bytes -= req->bytes;
|
||||
if (ret < 0) {
|
||||
bdrv_set_dirty_bitmap(s->copy_bitmap, req->offset, req->bytes);
|
||||
}
|
||||
QLIST_REMOVE(req, list);
|
||||
qemu_co_queue_restart_all(&req->wait_queue);
|
||||
}
|
||||
@@ -169,19 +70,16 @@ void block_copy_state_free(BlockCopyState *s)
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
static uint32_t block_copy_max_transfer(BdrvChild *source, BdrvChild *target)
|
||||
{
|
||||
return MIN_NON_ZERO(INT_MAX,
|
||||
MIN_NON_ZERO(source->bs->bl.max_transfer,
|
||||
target->bs->bl.max_transfer));
|
||||
}
|
||||
|
||||
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
|
||||
int64_t cluster_size,
|
||||
BdrvRequestFlags write_flags, Error **errp)
|
||||
{
|
||||
BlockCopyState *s;
|
||||
BdrvDirtyBitmap *copy_bitmap;
|
||||
uint32_t max_transfer =
|
||||
MIN_NON_ZERO(INT_MAX,
|
||||
MIN_NON_ZERO(source->bs->bl.max_transfer,
|
||||
target->bs->bl.max_transfer));
|
||||
|
||||
copy_bitmap = bdrv_create_dirty_bitmap(source->bs, cluster_size, NULL,
|
||||
errp);
|
||||
@@ -201,7 +99,7 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
|
||||
.mem = shres_create(BLOCK_COPY_MAX_MEM),
|
||||
};
|
||||
|
||||
if (block_copy_max_transfer(source, target) < cluster_size) {
|
||||
if (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
|
||||
@@ -216,11 +114,12 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
|
||||
s->copy_size = cluster_size;
|
||||
} else {
|
||||
/*
|
||||
* We enable copy-range, but keep small copy_size, until first
|
||||
* successful copy_range (look at block_copy_do_copy).
|
||||
* copy_range does not respect max_transfer (it's a TODO), so we factor
|
||||
* that in here.
|
||||
*/
|
||||
s->use_copy_range = true;
|
||||
s->copy_size = MAX(s->cluster_size, BLOCK_COPY_MAX_BUFFER);
|
||||
s->copy_size = MIN(MAX(cluster_size, BLOCK_COPY_MAX_COPY_RANGE),
|
||||
QEMU_ALIGN_DOWN(max_transfer, cluster_size));
|
||||
}
|
||||
|
||||
QLIST_INIT(&s->inflight_reqs);
|
||||
@@ -245,66 +144,34 @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm)
|
||||
/*
|
||||
* block_copy_do_copy
|
||||
*
|
||||
* Do copy of cluster-aligned chunk. Requested region is allowed to exceed
|
||||
* s->len only to cover last cluster when s->len is not aligned to clusters.
|
||||
* Do copy of cluser-aligned chunk. @end is allowed to exceed s->len only to
|
||||
* cover last cluster when s->len is not aligned to clusters.
|
||||
*
|
||||
* No sync here: nor bitmap neighter intersecting requests handling, only copy.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
|
||||
int64_t offset, int64_t bytes,
|
||||
bool zeroes, bool *error_is_read)
|
||||
int64_t start, int64_t end,
|
||||
bool *error_is_read)
|
||||
{
|
||||
int ret;
|
||||
int64_t nbytes = MIN(offset + bytes, s->len) - offset;
|
||||
int nbytes = MIN(end, s->len) - start;
|
||||
void *bounce_buffer = NULL;
|
||||
|
||||
assert(offset >= 0 && bytes > 0 && INT64_MAX - offset >= bytes);
|
||||
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
|
||||
assert(QEMU_IS_ALIGNED(bytes, s->cluster_size));
|
||||
assert(offset < s->len);
|
||||
assert(offset + bytes <= s->len ||
|
||||
offset + bytes == QEMU_ALIGN_UP(s->len, s->cluster_size));
|
||||
assert(nbytes < INT_MAX);
|
||||
|
||||
if (zeroes) {
|
||||
ret = bdrv_co_pwrite_zeroes(s->target, offset, nbytes, s->write_flags &
|
||||
~BDRV_REQ_WRITE_COMPRESSED);
|
||||
if (ret < 0) {
|
||||
trace_block_copy_write_zeroes_fail(s, offset, ret);
|
||||
if (error_is_read) {
|
||||
*error_is_read = false;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
assert(QEMU_IS_ALIGNED(start, s->cluster_size));
|
||||
assert(QEMU_IS_ALIGNED(end, s->cluster_size));
|
||||
assert(end < s->len || end == QEMU_ALIGN_UP(s->len, s->cluster_size));
|
||||
|
||||
if (s->use_copy_range) {
|
||||
ret = bdrv_co_copy_range(s->source, offset, s->target, offset, nbytes,
|
||||
ret = bdrv_co_copy_range(s->source, start, s->target, start, nbytes,
|
||||
0, s->write_flags);
|
||||
if (ret < 0) {
|
||||
trace_block_copy_copy_range_fail(s, offset, ret);
|
||||
trace_block_copy_copy_range_fail(s, start, ret);
|
||||
s->use_copy_range = false;
|
||||
s->copy_size = MAX(s->cluster_size, BLOCK_COPY_MAX_BUFFER);
|
||||
/* Fallback to read+write with allocated buffer */
|
||||
} else {
|
||||
if (s->use_copy_range) {
|
||||
/*
|
||||
* Successful copy-range. Now increase copy_size. copy_range
|
||||
* does not respect max_transfer (it's a TODO), so we factor
|
||||
* that in here.
|
||||
*
|
||||
* Note: we double-check s->use_copy_range for the case when
|
||||
* parallel block-copy request unsets it during previous
|
||||
* bdrv_co_copy_range call.
|
||||
*/
|
||||
s->copy_size =
|
||||
MIN(MAX(s->cluster_size, BLOCK_COPY_MAX_COPY_RANGE),
|
||||
QEMU_ALIGN_DOWN(block_copy_max_transfer(s->source,
|
||||
s->target),
|
||||
s->cluster_size));
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -312,27 +179,24 @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
|
||||
/*
|
||||
* In case of failed copy_range request above, we may proceed with buffered
|
||||
* request larger than BLOCK_COPY_MAX_BUFFER. Still, further requests will
|
||||
* be properly limited, so don't care too much. Moreover the most likely
|
||||
* case (copy_range is unsupported for the configuration, so the very first
|
||||
* copy_range request fails) is handled by setting large copy_size only
|
||||
* after first successful copy_range.
|
||||
* be properly limited, so don't care too much.
|
||||
*/
|
||||
|
||||
bounce_buffer = qemu_blockalign(s->source->bs, nbytes);
|
||||
|
||||
ret = bdrv_co_pread(s->source, offset, nbytes, bounce_buffer, 0);
|
||||
ret = bdrv_co_pread(s->source, start, nbytes, bounce_buffer, 0);
|
||||
if (ret < 0) {
|
||||
trace_block_copy_read_fail(s, offset, ret);
|
||||
trace_block_copy_read_fail(s, start, ret);
|
||||
if (error_is_read) {
|
||||
*error_is_read = true;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = bdrv_co_pwrite(s->target, offset, nbytes, bounce_buffer,
|
||||
ret = bdrv_co_pwrite(s->target, start, nbytes, bounce_buffer,
|
||||
s->write_flags);
|
||||
if (ret < 0) {
|
||||
trace_block_copy_write_fail(s, offset, ret);
|
||||
trace_block_copy_write_fail(s, start, ret);
|
||||
if (error_is_read) {
|
||||
*error_is_read = false;
|
||||
}
|
||||
@@ -345,38 +209,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int block_copy_block_status(BlockCopyState *s, int64_t offset,
|
||||
int64_t bytes, int64_t *pnum)
|
||||
{
|
||||
int64_t num;
|
||||
BlockDriverState *base;
|
||||
int ret;
|
||||
|
||||
if (s->skip_unallocated && s->source->bs->backing) {
|
||||
base = s->source->bs->backing->bs;
|
||||
} else {
|
||||
base = NULL;
|
||||
}
|
||||
|
||||
ret = bdrv_block_status_above(s->source->bs, base, offset, bytes, &num,
|
||||
NULL, NULL);
|
||||
if (ret < 0 || num < s->cluster_size) {
|
||||
/*
|
||||
* On error or if failed to obtain large enough chunk just fallback to
|
||||
* copy one cluster.
|
||||
*/
|
||||
num = s->cluster_size;
|
||||
ret = BDRV_BLOCK_ALLOCATED | BDRV_BLOCK_DATA;
|
||||
} else if (offset + num == s->len) {
|
||||
num = QEMU_ALIGN_UP(num, s->cluster_size);
|
||||
} else {
|
||||
num = QEMU_ALIGN_DOWN(num, s->cluster_size);
|
||||
}
|
||||
|
||||
*pnum = num;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the cluster starting at offset is allocated or not.
|
||||
* return via pnum the number of contiguous clusters sharing this allocation.
|
||||
@@ -449,19 +281,14 @@ int64_t block_copy_reset_unallocated(BlockCopyState *s,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* block_copy_dirty_clusters
|
||||
*
|
||||
* Copy dirty clusters in @offset/@bytes range.
|
||||
* Returns 1 if dirty clusters found and successfully copied, 0 if no dirty
|
||||
* clusters found and -errno on failure.
|
||||
*/
|
||||
static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s,
|
||||
int64_t offset, int64_t bytes,
|
||||
bool *error_is_read)
|
||||
int coroutine_fn block_copy(BlockCopyState *s,
|
||||
int64_t start, uint64_t bytes,
|
||||
bool *error_is_read)
|
||||
{
|
||||
int ret = 0;
|
||||
bool found_dirty = false;
|
||||
int64_t end = bytes + start; /* bytes */
|
||||
int64_t status_bytes;
|
||||
BlockCopyInFlightReq req;
|
||||
|
||||
/*
|
||||
* block_copy() user is responsible for keeping source and target in same
|
||||
@@ -470,109 +297,63 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s,
|
||||
assert(bdrv_get_aio_context(s->source->bs) ==
|
||||
bdrv_get_aio_context(s->target->bs));
|
||||
|
||||
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
|
||||
assert(QEMU_IS_ALIGNED(bytes, s->cluster_size));
|
||||
assert(QEMU_IS_ALIGNED(start, s->cluster_size));
|
||||
assert(QEMU_IS_ALIGNED(end, s->cluster_size));
|
||||
|
||||
while (bytes) {
|
||||
BlockCopyInFlightReq req;
|
||||
int64_t next_zero, cur_bytes, status_bytes;
|
||||
block_copy_wait_inflight_reqs(s, start, bytes);
|
||||
block_copy_inflight_req_begin(s, &req, start, end);
|
||||
|
||||
if (!bdrv_dirty_bitmap_get(s->copy_bitmap, offset)) {
|
||||
trace_block_copy_skip(s, offset);
|
||||
offset += s->cluster_size;
|
||||
bytes -= s->cluster_size;
|
||||
while (start < end) {
|
||||
int64_t next_zero, chunk_end;
|
||||
|
||||
if (!bdrv_dirty_bitmap_get(s->copy_bitmap, start)) {
|
||||
trace_block_copy_skip(s, start);
|
||||
start += s->cluster_size;
|
||||
continue; /* already copied */
|
||||
}
|
||||
|
||||
found_dirty = true;
|
||||
chunk_end = MIN(end, start + s->copy_size);
|
||||
|
||||
cur_bytes = MIN(bytes, s->copy_size);
|
||||
|
||||
next_zero = bdrv_dirty_bitmap_next_zero(s->copy_bitmap, offset,
|
||||
cur_bytes);
|
||||
next_zero = bdrv_dirty_bitmap_next_zero(s->copy_bitmap, start,
|
||||
chunk_end - start);
|
||||
if (next_zero >= 0) {
|
||||
assert(next_zero > offset); /* offset is dirty */
|
||||
assert(next_zero < offset + cur_bytes); /* no need to do MIN() */
|
||||
cur_bytes = next_zero - offset;
|
||||
}
|
||||
block_copy_inflight_req_begin(s, &req, offset, cur_bytes);
|
||||
|
||||
ret = block_copy_block_status(s, offset, cur_bytes, &status_bytes);
|
||||
assert(ret >= 0); /* never fail */
|
||||
cur_bytes = MIN(cur_bytes, status_bytes);
|
||||
block_copy_inflight_req_shrink(s, &req, cur_bytes);
|
||||
if (s->skip_unallocated && !(ret & BDRV_BLOCK_ALLOCATED)) {
|
||||
block_copy_inflight_req_end(s, &req, 0);
|
||||
progress_set_remaining(s->progress,
|
||||
bdrv_get_dirty_count(s->copy_bitmap) +
|
||||
s->in_flight_bytes);
|
||||
trace_block_copy_skip_range(s, offset, status_bytes);
|
||||
offset += status_bytes;
|
||||
bytes -= status_bytes;
|
||||
continue;
|
||||
assert(next_zero > start); /* start is dirty */
|
||||
assert(next_zero < chunk_end); /* no need to do MIN() */
|
||||
chunk_end = next_zero;
|
||||
}
|
||||
|
||||
trace_block_copy_process(s, offset);
|
||||
if (s->skip_unallocated) {
|
||||
ret = block_copy_reset_unallocated(s, start, &status_bytes);
|
||||
if (ret == 0) {
|
||||
trace_block_copy_skip_range(s, start, status_bytes);
|
||||
start += status_bytes;
|
||||
continue;
|
||||
}
|
||||
/* Clamp to known allocated region */
|
||||
chunk_end = MIN(chunk_end, start + status_bytes);
|
||||
}
|
||||
|
||||
co_get_from_shres(s->mem, cur_bytes);
|
||||
ret = block_copy_do_copy(s, offset, cur_bytes, ret & BDRV_BLOCK_ZERO,
|
||||
error_is_read);
|
||||
co_put_to_shres(s->mem, cur_bytes);
|
||||
block_copy_inflight_req_end(s, &req, ret);
|
||||
trace_block_copy_process(s, start);
|
||||
|
||||
bdrv_reset_dirty_bitmap(s->copy_bitmap, start, chunk_end - start);
|
||||
s->in_flight_bytes += chunk_end - start;
|
||||
|
||||
co_get_from_shres(s->mem, chunk_end - start);
|
||||
ret = block_copy_do_copy(s, start, chunk_end, error_is_read);
|
||||
co_put_to_shres(s->mem, chunk_end - start);
|
||||
s->in_flight_bytes -= chunk_end - start;
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
bdrv_set_dirty_bitmap(s->copy_bitmap, start, chunk_end - start);
|
||||
break;
|
||||
}
|
||||
|
||||
progress_work_done(s->progress, cur_bytes);
|
||||
s->progress_bytes_callback(cur_bytes, s->progress_opaque);
|
||||
offset += cur_bytes;
|
||||
bytes -= cur_bytes;
|
||||
progress_work_done(s->progress, chunk_end - start);
|
||||
s->progress_bytes_callback(chunk_end - start, s->progress_opaque);
|
||||
start = chunk_end;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return found_dirty;
|
||||
}
|
||||
|
||||
/*
|
||||
* block_copy
|
||||
*
|
||||
* Copy requested region, accordingly to dirty bitmap.
|
||||
* Collaborate with parallel block_copy requests: if they succeed it will help
|
||||
* us. If they fail, we will retry not-copied regions. So, if we return error,
|
||||
* it means that some I/O operation failed in context of _this_ block_copy call,
|
||||
* not some parallel operation.
|
||||
*/
|
||||
int coroutine_fn block_copy(BlockCopyState *s, int64_t offset, int64_t bytes,
|
||||
bool *error_is_read)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = block_copy_dirty_clusters(s, offset, bytes, error_is_read);
|
||||
|
||||
if (ret == 0) {
|
||||
ret = block_copy_wait_one(s, offset, bytes);
|
||||
}
|
||||
|
||||
/*
|
||||
* We retry in two cases:
|
||||
* 1. Some progress done
|
||||
* Something was copied, which means that there were yield points
|
||||
* and some new dirty bits may have appeared (due to failed parallel
|
||||
* block-copy requests).
|
||||
* 2. We have waited for some intersecting block-copy request
|
||||
* It may have failed and produced new dirty bits.
|
||||
*/
|
||||
} while (ret > 0);
|
||||
block_copy_inflight_req_end(&req);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BdrvDirtyBitmap *block_copy_dirty_bitmap(BlockCopyState *s)
|
||||
{
|
||||
return s->copy_bitmap;
|
||||
}
|
||||
|
||||
void block_copy_set_skip_unallocated(BlockCopyState *s, bool skip)
|
||||
{
|
||||
s->skip_unallocated = skip;
|
||||
}
|
||||
+25
-12
@@ -43,6 +43,27 @@ typedef struct CommitBlockJob {
|
||||
char *backing_file_str;
|
||||
} CommitBlockJob;
|
||||
|
||||
static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base,
|
||||
int64_t offset, uint64_t bytes,
|
||||
void *buf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
assert(bytes < SIZE_MAX);
|
||||
|
||||
ret = blk_co_pread(bs, offset, bytes, buf, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = blk_co_pwrite(base, offset, bytes, buf, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int commit_prepare(Job *job)
|
||||
{
|
||||
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
|
||||
@@ -119,6 +140,7 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
|
||||
int ret = 0;
|
||||
int64_t n = 0; /* bytes */
|
||||
void *buf = NULL;
|
||||
int bytes_written = 0;
|
||||
int64_t len, base_len;
|
||||
|
||||
ret = len = blk_getlength(s->top);
|
||||
@@ -143,7 +165,6 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
|
||||
|
||||
for (offset = 0; offset < len; offset += n) {
|
||||
bool copy;
|
||||
bool error_in_source = true;
|
||||
|
||||
/* Note that even when no rate limit is applied we need to yield
|
||||
* with no pending I/O here so that bdrv_drain_all() returns.
|
||||
@@ -158,20 +179,12 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
|
||||
copy = (ret == 1);
|
||||
trace_commit_one_iteration(s, offset, n, ret);
|
||||
if (copy) {
|
||||
assert(n < SIZE_MAX);
|
||||
|
||||
ret = blk_co_pread(s->top, offset, n, buf, 0);
|
||||
if (ret >= 0) {
|
||||
ret = blk_co_pwrite(s->base, offset, n, buf, 0);
|
||||
if (ret < 0) {
|
||||
error_in_source = false;
|
||||
}
|
||||
}
|
||||
ret = commit_populate(s->top, s->base, offset, n, buf);
|
||||
bytes_written += n;
|
||||
}
|
||||
if (ret < 0) {
|
||||
BlockErrorAction action =
|
||||
block_job_error_action(&s->common, s->on_error,
|
||||
error_in_source, -ret);
|
||||
block_job_error_action(&s->common, false, s->on_error, -ret);
|
||||
if (action == BLOCK_ERROR_ACTION_REPORT) {
|
||||
goto out;
|
||||
} else {
|
||||
|
||||
@@ -118,6 +118,13 @@ static void cor_lock_medium(BlockDriverState *bs, bool locked)
|
||||
}
|
||||
|
||||
|
||||
static bool cor_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate)
|
||||
{
|
||||
return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
|
||||
}
|
||||
|
||||
|
||||
static BlockDriver bdrv_copy_on_read = {
|
||||
.format_name = "copy-on-read",
|
||||
|
||||
@@ -136,6 +143,8 @@ static BlockDriver bdrv_copy_on_read = {
|
||||
|
||||
.bdrv_co_block_status = bdrv_co_block_status_from_file,
|
||||
|
||||
.bdrv_recurse_is_first_non_filter = cor_recurse_is_first_non_filter,
|
||||
|
||||
.has_variable_length = true,
|
||||
.is_filter = true,
|
||||
};
|
||||
|
||||
+1
-82
@@ -30,7 +30,6 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "crypto.h"
|
||||
|
||||
typedef struct BlockCrypto BlockCrypto;
|
||||
@@ -485,67 +484,6 @@ static int64_t block_crypto_getlength(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
|
||||
static BlockMeasureInfo *block_crypto_measure(QemuOpts *opts,
|
||||
BlockDriverState *in_bs,
|
||||
Error **errp)
|
||||
{
|
||||
g_autoptr(QCryptoBlockCreateOptions) create_opts = NULL;
|
||||
Error *local_err = NULL;
|
||||
BlockMeasureInfo *info;
|
||||
uint64_t size;
|
||||
size_t luks_payload_size;
|
||||
QDict *cryptoopts;
|
||||
|
||||
/*
|
||||
* Preallocation mode doesn't affect size requirements but we must consume
|
||||
* the option.
|
||||
*/
|
||||
g_free(qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC));
|
||||
|
||||
size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
|
||||
|
||||
if (in_bs) {
|
||||
int64_t ssize = bdrv_getlength(in_bs);
|
||||
|
||||
if (ssize < 0) {
|
||||
error_setg_errno(&local_err, -ssize,
|
||||
"Unable to get image virtual_size");
|
||||
goto err;
|
||||
}
|
||||
|
||||
size = ssize;
|
||||
}
|
||||
|
||||
cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL,
|
||||
&block_crypto_create_opts_luks, true);
|
||||
qdict_put_str(cryptoopts, "format", "luks");
|
||||
create_opts = block_crypto_create_opts_init(cryptoopts, &local_err);
|
||||
qobject_unref(cryptoopts);
|
||||
if (!create_opts) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!qcrypto_block_calculate_payload_offset(create_opts, NULL,
|
||||
&luks_payload_size,
|
||||
&local_err)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unallocated blocks are still encrypted so allocation status makes no
|
||||
* difference to the file size.
|
||||
*/
|
||||
info = g_new(BlockMeasureInfo, 1);
|
||||
info->fully_allocated = luks_payload_size + size;
|
||||
info->required = luks_payload_size + size;
|
||||
return info;
|
||||
|
||||
err:
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int block_crypto_probe_luks(const uint8_t *buf,
|
||||
int buf_size,
|
||||
const char *filename) {
|
||||
@@ -601,8 +539,7 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn block_crypto_co_create_opts_luks(BlockDriver *drv,
|
||||
const char *filename,
|
||||
static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
|
||||
QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -659,23 +596,6 @@ static int coroutine_fn block_crypto_co_create_opts_luks(BlockDriver *drv,
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
/*
|
||||
* If an error occurred, delete 'filename'. Even if the file existed
|
||||
* beforehand, it has been truncated and corrupted in the process.
|
||||
*/
|
||||
if (ret && bs) {
|
||||
Error *local_delete_err = NULL;
|
||||
int r_del = bdrv_co_delete_file(bs, &local_delete_err);
|
||||
/*
|
||||
* ENOTSUP will happen if the block driver doesn't support
|
||||
* the 'bdrv_co_delete_file' interface. This is a predictable
|
||||
* scenario and shouldn't be reported back to the user.
|
||||
*/
|
||||
if ((r_del < 0) && (r_del != -ENOTSUP)) {
|
||||
error_report_err(local_delete_err);
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_unref(bs);
|
||||
qapi_free_QCryptoBlockCreateOptions(create_opts);
|
||||
qobject_unref(cryptoopts);
|
||||
@@ -750,7 +670,6 @@ static BlockDriver bdrv_crypto_luks = {
|
||||
.bdrv_co_preadv = block_crypto_co_preadv,
|
||||
.bdrv_co_pwritev = block_crypto_co_pwritev,
|
||||
.bdrv_getlength = block_crypto_getlength,
|
||||
.bdrv_measure = block_crypto_measure,
|
||||
.bdrv_get_info = block_crypto_get_info_luks,
|
||||
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
|
||||
|
||||
|
||||
+4
-28
@@ -214,35 +214,11 @@ static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
||||
{
|
||||
BDRVCURLState *s = opaque;
|
||||
size_t realsize = size * nmemb;
|
||||
const char *header = (char *)ptr;
|
||||
const char *end = header + realsize;
|
||||
const char *accept_ranges = "accept-ranges:";
|
||||
const char *bytes = "bytes";
|
||||
const char *accept_line = "Accept-Ranges: bytes";
|
||||
|
||||
if (realsize >= strlen(accept_ranges)
|
||||
&& g_ascii_strncasecmp(header, accept_ranges,
|
||||
strlen(accept_ranges)) == 0) {
|
||||
|
||||
char *p = strchr(header, ':') + 1;
|
||||
|
||||
/* Skip whitespace between the header name and value. */
|
||||
while (p < end && *p && g_ascii_isspace(*p)) {
|
||||
p++;
|
||||
}
|
||||
|
||||
if (end - p >= strlen(bytes)
|
||||
&& strncmp(p, bytes, strlen(bytes)) == 0) {
|
||||
|
||||
/* Check that there is nothing but whitespace after the value. */
|
||||
p += strlen(bytes);
|
||||
while (p < end && *p && g_ascii_isspace(*p)) {
|
||||
p++;
|
||||
}
|
||||
|
||||
if (p == end || !*p) {
|
||||
s->accept_range = true;
|
||||
}
|
||||
}
|
||||
if (realsize >= strlen(accept_line)
|
||||
&& strncmp((char *)ptr, accept_line, strlen(accept_line)) == 0) {
|
||||
s->accept_range = true;
|
||||
}
|
||||
|
||||
return realsize;
|
||||
|
||||
+4
-12
@@ -860,24 +860,16 @@ char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp)
|
||||
return hbitmap_sha256(bitmap->bitmap, errp);
|
||||
}
|
||||
|
||||
int64_t bdrv_dirty_bitmap_next_dirty(BdrvDirtyBitmap *bitmap, int64_t offset,
|
||||
int64_t bytes)
|
||||
{
|
||||
return hbitmap_next_dirty(bitmap->bitmap, offset, bytes);
|
||||
}
|
||||
|
||||
int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, int64_t offset,
|
||||
int64_t bytes)
|
||||
int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset,
|
||||
uint64_t bytes)
|
||||
{
|
||||
return hbitmap_next_zero(bitmap->bitmap, offset, bytes);
|
||||
}
|
||||
|
||||
bool bdrv_dirty_bitmap_next_dirty_area(BdrvDirtyBitmap *bitmap,
|
||||
int64_t start, int64_t end, int64_t max_dirty_count,
|
||||
int64_t *dirty_start, int64_t *dirty_count)
|
||||
uint64_t *offset, uint64_t *bytes)
|
||||
{
|
||||
return hbitmap_next_dirty_area(bitmap->bitmap, start, end, max_dirty_count,
|
||||
dirty_start, dirty_count);
|
||||
return hbitmap_next_dirty_area(bitmap->bitmap, offset, bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+90
-111
@@ -156,7 +156,6 @@ typedef struct BDRVRawState {
|
||||
bool has_write_zeroes:1;
|
||||
bool discard_zeroes:1;
|
||||
bool use_linux_aio:1;
|
||||
bool use_linux_io_uring:1;
|
||||
bool page_cache_inconsistent:1;
|
||||
bool has_fallocate;
|
||||
bool needs_alignment;
|
||||
@@ -445,7 +444,7 @@ static QemuOptsList raw_runtime_opts = {
|
||||
{
|
||||
.name = "aio",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "host AIO implementation (threads, native, io_uring)",
|
||||
.help = "host AIO implementation (threads, native)",
|
||||
},
|
||||
{
|
||||
.name = "locking",
|
||||
@@ -504,16 +503,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (bdrv_flags & BDRV_O_NATIVE_AIO) {
|
||||
aio_default = BLOCKDEV_AIO_OPTIONS_NATIVE;
|
||||
#ifdef CONFIG_LINUX_IO_URING
|
||||
} else if (bdrv_flags & BDRV_O_IO_URING) {
|
||||
aio_default = BLOCKDEV_AIO_OPTIONS_IO_URING;
|
||||
#endif
|
||||
} else {
|
||||
aio_default = BLOCKDEV_AIO_OPTIONS_THREADS;
|
||||
}
|
||||
|
||||
aio_default = (bdrv_flags & BDRV_O_NATIVE_AIO)
|
||||
? BLOCKDEV_AIO_OPTIONS_NATIVE
|
||||
: BLOCKDEV_AIO_OPTIONS_THREADS;
|
||||
aio = qapi_enum_parse(&BlockdevAioOptions_lookup,
|
||||
qemu_opt_get(opts, "aio"),
|
||||
aio_default, &local_err);
|
||||
@@ -522,11 +514,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->use_linux_aio = (aio == BLOCKDEV_AIO_OPTIONS_NATIVE);
|
||||
#ifdef CONFIG_LINUX_IO_URING
|
||||
s->use_linux_io_uring = (aio == BLOCKDEV_AIO_OPTIONS_IO_URING);
|
||||
#endif
|
||||
|
||||
locking = qapi_enum_parse(&OnOffAuto_lookup,
|
||||
qemu_opt_get(opts, "locking"),
|
||||
@@ -612,22 +600,6 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
}
|
||||
#endif /* !defined(CONFIG_LINUX_AIO) */
|
||||
|
||||
#ifdef CONFIG_LINUX_IO_URING
|
||||
if (s->use_linux_io_uring) {
|
||||
if (!aio_setup_linux_io_uring(bdrv_get_aio_context(bs), errp)) {
|
||||
error_prepend(errp, "Unable to use io_uring: ");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (s->use_linux_io_uring) {
|
||||
error_setg(errp, "aio=io_uring was specified, but is not supported "
|
||||
"in this build.");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
#endif /* !defined(CONFIG_LINUX_IO_URING) */
|
||||
|
||||
s->has_discard = true;
|
||||
s->has_write_zeroes = true;
|
||||
if ((bs->open_flags & BDRV_O_NOCACHE) != 0) {
|
||||
@@ -888,6 +860,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs,
|
||||
"Is another process using the image [%s]?\n",
|
||||
bs->filename);
|
||||
}
|
||||
op = RAW_PL_ABORT;
|
||||
/* fall through to unlock bytes. */
|
||||
case RAW_PL_ABORT:
|
||||
raw_apply_lock_bytes(s, s->fd, s->perm, ~s->shared_perm,
|
||||
@@ -1904,25 +1877,21 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* When using O_DIRECT, the request must be aligned to be able to use
|
||||
* either libaio or io_uring interface. If not fail back to regular thread
|
||||
* pool read/write code which emulates this for us if we
|
||||
* set QEMU_AIO_MISALIGNED.
|
||||
* Check if the underlying device requires requests to be aligned,
|
||||
* and if the request we are trying to submit is aligned or not.
|
||||
* If this is the case tell the low-level driver that it needs
|
||||
* to copy the buffer.
|
||||
*/
|
||||
if (s->needs_alignment && !bdrv_qiov_is_aligned(bs, qiov)) {
|
||||
type |= QEMU_AIO_MISALIGNED;
|
||||
#ifdef CONFIG_LINUX_IO_URING
|
||||
} else if (s->use_linux_io_uring) {
|
||||
LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs));
|
||||
assert(qiov->size == bytes);
|
||||
return luring_co_submit(bs, aio, s->fd, offset, qiov, type);
|
||||
#endif
|
||||
if (s->needs_alignment) {
|
||||
if (!bdrv_qiov_is_aligned(bs, qiov)) {
|
||||
type |= QEMU_AIO_MISALIGNED;
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
} 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);
|
||||
} 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);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
acb = (RawPosixAIOData) {
|
||||
@@ -1958,36 +1927,24 @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
|
||||
static void raw_aio_plug(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState __attribute__((unused)) *s = bs->opaque;
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
BDRVRawState *s = bs->opaque;
|
||||
if (s->use_linux_aio) {
|
||||
LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
|
||||
laio_io_plug(bs, aio);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_LINUX_IO_URING
|
||||
if (s->use_linux_io_uring) {
|
||||
LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs));
|
||||
luring_io_plug(bs, aio);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void raw_aio_unplug(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState __attribute__((unused)) *s = bs->opaque;
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
BDRVRawState *s = bs->opaque;
|
||||
if (s->use_linux_aio) {
|
||||
LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
|
||||
laio_io_unplug(bs, aio);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_LINUX_IO_URING
|
||||
if (s->use_linux_io_uring) {
|
||||
LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs));
|
||||
luring_io_unplug(bs, aio);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int raw_co_flush_to_disk(BlockDriverState *bs)
|
||||
@@ -2007,20 +1964,14 @@ static int raw_co_flush_to_disk(BlockDriverState *bs)
|
||||
.aio_type = QEMU_AIO_FLUSH,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_LINUX_IO_URING
|
||||
if (s->use_linux_io_uring) {
|
||||
LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs));
|
||||
return luring_co_submit(bs, aio, s->fd, 0, NULL, QEMU_AIO_FLUSH);
|
||||
}
|
||||
#endif
|
||||
return raw_thread_pool_submit(bs, handle_aiocb_flush, &acb);
|
||||
}
|
||||
|
||||
static void raw_aio_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
BDRVRawState __attribute__((unused)) *s = bs->opaque;
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
BDRVRawState *s = bs->opaque;
|
||||
if (s->use_linux_aio) {
|
||||
Error *local_err = NULL;
|
||||
if (!aio_setup_linux_aio(new_context, &local_err)) {
|
||||
@@ -2030,16 +1981,6 @@ static void raw_aio_attach_aio_context(BlockDriverState *bs,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_LINUX_IO_URING
|
||||
if (s->use_linux_io_uring) {
|
||||
Error *local_err;
|
||||
if (!aio_setup_linux_io_uring(new_context, &local_err)) {
|
||||
error_reportf_err(local_err, "Unable to use linux io_uring, "
|
||||
"falling back to thread pool: ");
|
||||
s->use_linux_io_uring = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void raw_close(BlockDriverState *bs)
|
||||
@@ -2405,9 +2346,7 @@ out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
|
||||
const char *filename,
|
||||
QemuOpts *opts,
|
||||
static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
BlockdevCreateOptions options;
|
||||
@@ -2447,28 +2386,6 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
|
||||
return raw_co_create(&options, errp);
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_delete_file(BlockDriverState *bs,
|
||||
Error **errp)
|
||||
{
|
||||
struct stat st;
|
||||
int ret;
|
||||
|
||||
if (!(stat(bs->filename, &st) == 0) || !S_ISREG(st.st_mode)) {
|
||||
error_setg_errno(errp, ENOENT, "%s is not a regular file",
|
||||
bs->filename);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = unlink(bs->filename);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
error_setg_errno(errp, -ret, "Error when deleting file %s",
|
||||
bs->filename);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find allocation range in @bs around offset @start.
|
||||
* May change underlying file descriptor's file offset.
|
||||
@@ -2836,6 +2753,7 @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
|
||||
req->overlap_bytes = req->bytes;
|
||||
|
||||
bdrv_mark_request_serialising(req, bs->bl.request_alignment);
|
||||
bdrv_wait_serialising_requests(req);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3099,7 +3017,6 @@ BlockDriver bdrv_file = {
|
||||
.bdrv_co_block_status = raw_co_block_status,
|
||||
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
|
||||
.bdrv_co_pwrite_zeroes = raw_co_pwrite_zeroes,
|
||||
.bdrv_co_delete_file = raw_co_delete_file,
|
||||
|
||||
.bdrv_co_preadv = raw_co_preadv,
|
||||
.bdrv_co_pwritev = raw_co_pwritev,
|
||||
@@ -3501,6 +3418,67 @@ static coroutine_fn int hdev_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
return raw_do_pwrite_zeroes(bs, offset, bytes, flags, true);
|
||||
}
|
||||
|
||||
static int coroutine_fn hdev_co_create_opts(const char *filename, QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
int fd;
|
||||
int ret = 0;
|
||||
struct stat stat_buf;
|
||||
int64_t total_size = 0;
|
||||
bool has_prefix;
|
||||
|
||||
/* This function is used by both protocol block drivers and therefore either
|
||||
* of these prefixes may be given.
|
||||
* The return value has to be stored somewhere, otherwise this is an error
|
||||
* due to -Werror=unused-value. */
|
||||
has_prefix =
|
||||
strstart(filename, "host_device:", &filename) ||
|
||||
strstart(filename, "host_cdrom:" , &filename);
|
||||
|
||||
(void)has_prefix;
|
||||
|
||||
ret = raw_normalize_devicepath(&filename, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read out options */
|
||||
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||
BDRV_SECTOR_SIZE);
|
||||
|
||||
fd = qemu_open(filename, O_WRONLY | O_BINARY);
|
||||
if (fd < 0) {
|
||||
ret = -errno;
|
||||
error_setg_errno(errp, -ret, "Could not open device");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (fstat(fd, &stat_buf) < 0) {
|
||||
ret = -errno;
|
||||
error_setg_errno(errp, -ret, "Could not stat device");
|
||||
} else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode)) {
|
||||
error_setg(errp,
|
||||
"The given file is neither a block nor a character device");
|
||||
ret = -ENODEV;
|
||||
} else if (lseek(fd, 0, SEEK_END) < total_size) {
|
||||
error_setg(errp, "Device is too small");
|
||||
ret = -ENOSPC;
|
||||
}
|
||||
|
||||
if (!ret && total_size) {
|
||||
uint8_t buf[BDRV_SECTOR_SIZE] = { 0 };
|
||||
int64_t zero_size = MIN(BDRV_SECTOR_SIZE, total_size);
|
||||
if (lseek(fd, 0, SEEK_SET) == -1) {
|
||||
ret = -errno;
|
||||
} else {
|
||||
ret = qemu_write_full(fd, buf, zero_size);
|
||||
ret = ret == zero_size ? 0 : -errno;
|
||||
}
|
||||
}
|
||||
qemu_close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_host_device = {
|
||||
.format_name = "host_device",
|
||||
.protocol_name = "host_device",
|
||||
@@ -3513,8 +3491,8 @@ static BlockDriver bdrv_host_device = {
|
||||
.bdrv_reopen_prepare = raw_reopen_prepare,
|
||||
.bdrv_reopen_commit = raw_reopen_commit,
|
||||
.bdrv_reopen_abort = raw_reopen_abort,
|
||||
.bdrv_co_create_opts = bdrv_co_create_opts_simple,
|
||||
.create_opts = &bdrv_create_opts_simple,
|
||||
.bdrv_co_create_opts = hdev_co_create_opts,
|
||||
.create_opts = &raw_create_opts,
|
||||
.mutable_opts = mutable_opts,
|
||||
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
|
||||
.bdrv_co_pwrite_zeroes = hdev_co_pwrite_zeroes,
|
||||
@@ -3641,11 +3619,12 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
.bdrv_reopen_prepare = raw_reopen_prepare,
|
||||
.bdrv_reopen_commit = raw_reopen_commit,
|
||||
.bdrv_reopen_abort = raw_reopen_abort,
|
||||
.bdrv_co_create_opts = bdrv_co_create_opts_simple,
|
||||
.create_opts = &bdrv_create_opts_simple,
|
||||
.bdrv_co_create_opts = hdev_co_create_opts,
|
||||
.create_opts = &raw_create_opts,
|
||||
.mutable_opts = mutable_opts,
|
||||
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
|
||||
|
||||
|
||||
.bdrv_co_preadv = raw_co_preadv,
|
||||
.bdrv_co_pwritev = raw_co_pwritev,
|
||||
.bdrv_co_flush_to_disk = raw_co_flush_to_disk,
|
||||
@@ -3774,8 +3753,8 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
.bdrv_reopen_prepare = raw_reopen_prepare,
|
||||
.bdrv_reopen_commit = raw_reopen_commit,
|
||||
.bdrv_reopen_abort = raw_reopen_abort,
|
||||
.bdrv_co_create_opts = bdrv_co_create_opts_simple,
|
||||
.create_opts = &bdrv_create_opts_simple,
|
||||
.bdrv_co_create_opts = hdev_co_create_opts,
|
||||
.create_opts = &raw_create_opts,
|
||||
.mutable_opts = mutable_opts,
|
||||
|
||||
.bdrv_co_preadv = raw_co_preadv,
|
||||
|
||||
+1
-3
@@ -588,9 +588,7 @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
|
||||
const char *filename,
|
||||
QemuOpts *opts,
|
||||
static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
BlockdevCreateOptions options;
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Compress filter block driver
|
||||
*
|
||||
* Copyright (c) 2019 Virtuozzo International GmbH
|
||||
*
|
||||
* Author:
|
||||
* Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
|
||||
* (based on block/copy-on-read.c by Max Reitz)
|
||||
*
|
||||
* 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 or
|
||||
* (at your option) any later version of the License.
|
||||
*
|
||||
* 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 "block/block_int.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
|
||||
static int compress_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
|
||||
errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) {
|
||||
error_setg(errp,
|
||||
"Compression is not supported for underlying format: %s",
|
||||
bdrv_get_format_name(bs->file->bs) ?: "(no format)");
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int64_t compress_getlength(BlockDriverState *bs)
|
||||
{
|
||||
return bdrv_getlength(bs->file->bs);
|
||||
}
|
||||
|
||||
|
||||
static int coroutine_fn compress_co_preadv_part(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 compress_co_pwritev_part(BlockDriverState *bs,
|
||||
uint64_t offset,
|
||||
uint64_t bytes,
|
||||
QEMUIOVector *qiov,
|
||||
size_t qiov_offset, int flags)
|
||||
{
|
||||
return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
|
||||
flags | BDRV_REQ_WRITE_COMPRESSED);
|
||||
}
|
||||
|
||||
|
||||
static int coroutine_fn compress_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int bytes,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
|
||||
}
|
||||
|
||||
|
||||
static int coroutine_fn compress_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
return bdrv_co_pdiscard(bs->file, offset, bytes);
|
||||
}
|
||||
|
||||
|
||||
static void compress_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
BlockDriverInfo bdi;
|
||||
int ret;
|
||||
|
||||
if (!bs->file) {
|
||||
return;
|
||||
}
|
||||
|
||||
ret = bdrv_get_info(bs->file->bs, &bdi);
|
||||
if (ret < 0 || bdi.cluster_size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
bs->bl.request_alignment = bdi.cluster_size;
|
||||
}
|
||||
|
||||
|
||||
static void compress_eject(BlockDriverState *bs, bool eject_flag)
|
||||
{
|
||||
bdrv_eject(bs->file->bs, eject_flag);
|
||||
}
|
||||
|
||||
|
||||
static void compress_lock_medium(BlockDriverState *bs, bool locked)
|
||||
{
|
||||
bdrv_lock_medium(bs->file->bs, locked);
|
||||
}
|
||||
|
||||
|
||||
static BlockDriver bdrv_compress = {
|
||||
.format_name = "compress",
|
||||
|
||||
.bdrv_open = compress_open,
|
||||
.bdrv_child_perm = bdrv_filter_default_perms,
|
||||
|
||||
.bdrv_getlength = compress_getlength,
|
||||
|
||||
.bdrv_co_preadv_part = compress_co_preadv_part,
|
||||
.bdrv_co_pwritev_part = compress_co_pwritev_part,
|
||||
.bdrv_co_pwrite_zeroes = compress_co_pwrite_zeroes,
|
||||
.bdrv_co_pdiscard = compress_co_pdiscard,
|
||||
.bdrv_refresh_limits = compress_refresh_limits,
|
||||
|
||||
.bdrv_eject = compress_eject,
|
||||
.bdrv_lock_medium = compress_lock_medium,
|
||||
|
||||
.bdrv_co_block_status = bdrv_co_block_status_from_file,
|
||||
|
||||
.has_variable_length = true,
|
||||
.is_filter = true,
|
||||
};
|
||||
|
||||
static void bdrv_compress_init(void)
|
||||
{
|
||||
bdrv_register(&bdrv_compress);
|
||||
}
|
||||
|
||||
block_init(bdrv_compress_init);
|
||||
+1
-2
@@ -1130,8 +1130,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn qemu_gluster_co_create_opts(BlockDriver *drv,
|
||||
const char *filename,
|
||||
static int coroutine_fn qemu_gluster_co_create_opts(const char *filename,
|
||||
QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
|
||||
+86
-86
@@ -715,69 +715,12 @@ static void tracked_request_begin(BdrvTrackedRequest *req,
|
||||
qemu_co_mutex_unlock(&bs->reqs_lock);
|
||||
}
|
||||
|
||||
static bool tracked_request_overlaps(BdrvTrackedRequest *req,
|
||||
int64_t offset, uint64_t bytes)
|
||||
void bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
|
||||
{
|
||||
/* aaaa bbbb */
|
||||
if (offset >= req->overlap_offset + req->overlap_bytes) {
|
||||
return false;
|
||||
}
|
||||
/* bbbb aaaa */
|
||||
if (req->overlap_offset >= offset + bytes) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool coroutine_fn
|
||||
bdrv_wait_serialising_requests_locked(BlockDriverState *bs,
|
||||
BdrvTrackedRequest *self)
|
||||
{
|
||||
BdrvTrackedRequest *req;
|
||||
bool retry;
|
||||
bool waited = false;
|
||||
|
||||
do {
|
||||
retry = false;
|
||||
QLIST_FOREACH(req, &bs->tracked_requests, list) {
|
||||
if (req == self || (!req->serialising && !self->serialising)) {
|
||||
continue;
|
||||
}
|
||||
if (tracked_request_overlaps(req, self->overlap_offset,
|
||||
self->overlap_bytes))
|
||||
{
|
||||
/* Hitting this means there was a reentrant request, for
|
||||
* example, a block driver issuing nested requests. This must
|
||||
* never happen since it means deadlock.
|
||||
*/
|
||||
assert(qemu_coroutine_self() != req->co);
|
||||
|
||||
/* If the request 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 (!req->waiting_for) {
|
||||
self->waiting_for = req;
|
||||
qemu_co_queue_wait(&req->wait_queue, &bs->reqs_lock);
|
||||
self->waiting_for = NULL;
|
||||
retry = true;
|
||||
waited = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (retry);
|
||||
return waited;
|
||||
}
|
||||
|
||||
bool bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
|
||||
{
|
||||
BlockDriverState *bs = req->bs;
|
||||
int64_t overlap_offset = req->offset & ~(align - 1);
|
||||
uint64_t overlap_bytes = ROUND_UP(req->offset + req->bytes, align)
|
||||
- overlap_offset;
|
||||
bool waited;
|
||||
|
||||
qemu_co_mutex_lock(&bs->reqs_lock);
|
||||
if (!req->serialising) {
|
||||
atomic_inc(&req->bs->serialising_in_flight);
|
||||
req->serialising = true;
|
||||
@@ -785,9 +728,18 @@ bool bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
|
||||
|
||||
req->overlap_offset = MIN(req->overlap_offset, overlap_offset);
|
||||
req->overlap_bytes = MAX(req->overlap_bytes, overlap_bytes);
|
||||
waited = bdrv_wait_serialising_requests_locked(bs, req);
|
||||
qemu_co_mutex_unlock(&bs->reqs_lock);
|
||||
return waited;
|
||||
}
|
||||
|
||||
static bool is_request_serialising_and_aligned(BdrvTrackedRequest *req)
|
||||
{
|
||||
/*
|
||||
* If the request is serialising, overlap_offset and overlap_bytes are set,
|
||||
* so we can check if the request is aligned. Otherwise, don't care and
|
||||
* return false.
|
||||
*/
|
||||
|
||||
return req->serialising && (req->offset == req->overlap_offset) &&
|
||||
(req->bytes == req->overlap_bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -841,6 +793,20 @@ static int bdrv_get_cluster_size(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
static bool tracked_request_overlaps(BdrvTrackedRequest *req,
|
||||
int64_t offset, uint64_t bytes)
|
||||
{
|
||||
/* aaaa bbbb */
|
||||
if (offset >= req->overlap_offset + req->overlap_bytes) {
|
||||
return false;
|
||||
}
|
||||
/* bbbb aaaa */
|
||||
if (req->overlap_offset >= offset + bytes) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void bdrv_inc_in_flight(BlockDriverState *bs)
|
||||
{
|
||||
atomic_inc(&bs->in_flight);
|
||||
@@ -857,18 +823,48 @@ void bdrv_dec_in_flight(BlockDriverState *bs)
|
||||
bdrv_wakeup(bs);
|
||||
}
|
||||
|
||||
static bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self)
|
||||
bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self)
|
||||
{
|
||||
BlockDriverState *bs = self->bs;
|
||||
BdrvTrackedRequest *req;
|
||||
bool retry;
|
||||
bool waited = false;
|
||||
|
||||
if (!atomic_read(&bs->serialising_in_flight)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
qemu_co_mutex_lock(&bs->reqs_lock);
|
||||
waited = bdrv_wait_serialising_requests_locked(bs, self);
|
||||
qemu_co_mutex_unlock(&bs->reqs_lock);
|
||||
do {
|
||||
retry = false;
|
||||
qemu_co_mutex_lock(&bs->reqs_lock);
|
||||
QLIST_FOREACH(req, &bs->tracked_requests, list) {
|
||||
if (req == self || (!req->serialising && !self->serialising)) {
|
||||
continue;
|
||||
}
|
||||
if (tracked_request_overlaps(req, self->overlap_offset,
|
||||
self->overlap_bytes))
|
||||
{
|
||||
/* Hitting this means there was a reentrant request, for
|
||||
* example, a block driver issuing nested requests. This must
|
||||
* never happen since it means deadlock.
|
||||
*/
|
||||
assert(qemu_coroutine_self() != req->co);
|
||||
|
||||
/* If the request 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 (!req->waiting_for) {
|
||||
self->waiting_for = req;
|
||||
qemu_co_queue_wait(&req->wait_queue, &bs->reqs_lock);
|
||||
self->waiting_for = NULL;
|
||||
retry = true;
|
||||
waited = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
qemu_co_mutex_unlock(&bs->reqs_lock);
|
||||
} while (retry);
|
||||
|
||||
return waited;
|
||||
}
|
||||
@@ -1449,7 +1445,8 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
|
||||
* potential fallback support, if we ever implement any read flags
|
||||
* to pass through to drivers. For now, there aren't any
|
||||
* passthrough flags. */
|
||||
assert(!(flags & ~(BDRV_REQ_COPY_ON_READ | BDRV_REQ_PREFETCH)));
|
||||
assert(!(flags & ~(BDRV_REQ_NO_SERIALISING | BDRV_REQ_COPY_ON_READ |
|
||||
BDRV_REQ_PREFETCH)));
|
||||
|
||||
/* Handle Copy on Read and associated serialisation */
|
||||
if (flags & BDRV_REQ_COPY_ON_READ) {
|
||||
@@ -1459,7 +1456,12 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
|
||||
* it ensures that the CoR read and write operations are atomic and
|
||||
* guest writes cannot interleave between them. */
|
||||
bdrv_mark_request_serialising(req, bdrv_get_cluster_size(bs));
|
||||
} else {
|
||||
}
|
||||
|
||||
/* BDRV_REQ_SERIALISING is only for write operation */
|
||||
assert(!(flags & BDRV_REQ_SERIALISING));
|
||||
|
||||
if (!(flags & BDRV_REQ_NO_SERIALISING)) {
|
||||
bdrv_wait_serialising_requests(req);
|
||||
}
|
||||
|
||||
@@ -1501,13 +1503,12 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
|
||||
assert(num);
|
||||
|
||||
ret = bdrv_driver_preadv(bs, offset + bytes - bytes_remaining,
|
||||
num, qiov,
|
||||
qiov_offset + bytes - bytes_remaining, 0);
|
||||
num, qiov, bytes - bytes_remaining, 0);
|
||||
max_bytes -= num;
|
||||
} else {
|
||||
num = bytes_remaining;
|
||||
ret = qemu_iovec_memset(qiov, qiov_offset + bytes - bytes_remaining,
|
||||
0, bytes_remaining);
|
||||
ret = qemu_iovec_memset(qiov, bytes - bytes_remaining, 0,
|
||||
bytes_remaining);
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
@@ -1724,7 +1725,7 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
|
||||
bdrv_inc_in_flight(bs);
|
||||
|
||||
/* Don't do copy-on-read if we read data before write operation */
|
||||
if (atomic_read(&bs->copy_on_read)) {
|
||||
if (atomic_read(&bs->copy_on_read) && !(flags & BDRV_REQ_NO_SERIALISING)) {
|
||||
flags |= BDRV_REQ_COPY_ON_READ;
|
||||
}
|
||||
|
||||
@@ -1865,24 +1866,20 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes,
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* BDRV_REQ_NO_SERIALISING is only for read operation */
|
||||
assert(!(flags & BDRV_REQ_NO_SERIALISING));
|
||||
assert(!(bs->open_flags & BDRV_O_INACTIVE));
|
||||
assert((bs->open_flags & BDRV_O_NO_IO) == 0);
|
||||
assert(!(flags & ~BDRV_REQ_MASK));
|
||||
|
||||
if (flags & BDRV_REQ_SERIALISING) {
|
||||
waited = bdrv_mark_request_serialising(req, bdrv_get_cluster_size(bs));
|
||||
/*
|
||||
* For a misaligned request we should have already waited earlier,
|
||||
* because we come after bdrv_padding_rmw_read which must be called
|
||||
* with the request already marked as serialising.
|
||||
*/
|
||||
assert(!waited ||
|
||||
(req->offset == req->overlap_offset &&
|
||||
req->bytes == req->overlap_bytes));
|
||||
} else {
|
||||
bdrv_wait_serialising_requests(req);
|
||||
bdrv_mark_request_serialising(req, bdrv_get_cluster_size(bs));
|
||||
}
|
||||
|
||||
waited = bdrv_wait_serialising_requests(req);
|
||||
|
||||
assert(!waited || !req->serialising ||
|
||||
is_request_serialising_and_aligned(req));
|
||||
assert(req->overlap_offset <= offset);
|
||||
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
|
||||
assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
|
||||
@@ -2010,8 +2007,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
|
||||
}
|
||||
|
||||
ret = bdrv_driver_pwritev(bs, offset + bytes - bytes_remaining,
|
||||
num, qiov,
|
||||
qiov_offset + bytes - bytes_remaining,
|
||||
num, qiov, bytes - bytes_remaining,
|
||||
local_flags);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
@@ -2045,6 +2041,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
|
||||
padding = bdrv_init_padding(bs, offset, bytes, &pad);
|
||||
if (padding) {
|
||||
bdrv_mark_request_serialising(req, align);
|
||||
bdrv_wait_serialising_requests(req);
|
||||
|
||||
bdrv_padding_rmw_read(child, req, &pad, true);
|
||||
|
||||
@@ -2159,6 +2156,7 @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
|
||||
|
||||
if (bdrv_pad_request(bs, &qiov, &qiov_offset, &offset, &bytes, &pad)) {
|
||||
bdrv_mark_request_serialising(&req, align);
|
||||
bdrv_wait_serialising_requests(&req);
|
||||
bdrv_padding_rmw_read(child, &req, &pad, false);
|
||||
}
|
||||
|
||||
@@ -3250,7 +3248,9 @@ static int coroutine_fn bdrv_co_copy_range_internal(
|
||||
|
||||
/* BDRV_REQ_SERIALISING is only for write operation */
|
||||
assert(!(read_flags & BDRV_REQ_SERIALISING));
|
||||
bdrv_wait_serialising_requests(&req);
|
||||
if (!(read_flags & BDRV_REQ_NO_SERIALISING)) {
|
||||
bdrv_wait_serialising_requests(&req);
|
||||
}
|
||||
|
||||
ret = src->bs->drv->bdrv_co_copy_range_from(src->bs,
|
||||
src, src_offset,
|
||||
|
||||
@@ -1,433 +0,0 @@
|
||||
/*
|
||||
* Linux io_uring support.
|
||||
*
|
||||
* Copyright (C) 2009 IBM, Corp.
|
||||
* Copyright (C) 2009 Red Hat, Inc.
|
||||
* Copyright (C) 2019 Aarushi Mehta
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include <liburing.h>
|
||||
#include "qemu-common.h"
|
||||
#include "block/aio.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "block/block.h"
|
||||
#include "block/raw-aio.h"
|
||||
#include "qemu/coroutine.h"
|
||||
#include "qapi/error.h"
|
||||
#include "trace.h"
|
||||
|
||||
/* io_uring ring size */
|
||||
#define MAX_ENTRIES 128
|
||||
|
||||
typedef struct LuringAIOCB {
|
||||
Coroutine *co;
|
||||
struct io_uring_sqe sqeq;
|
||||
ssize_t ret;
|
||||
QEMUIOVector *qiov;
|
||||
bool is_read;
|
||||
QSIMPLEQ_ENTRY(LuringAIOCB) next;
|
||||
|
||||
/*
|
||||
* Buffered reads may require resubmission, see
|
||||
* luring_resubmit_short_read().
|
||||
*/
|
||||
int total_read;
|
||||
QEMUIOVector resubmit_qiov;
|
||||
} LuringAIOCB;
|
||||
|
||||
typedef struct LuringQueue {
|
||||
int plugged;
|
||||
unsigned int in_queue;
|
||||
unsigned int in_flight;
|
||||
bool blocked;
|
||||
QSIMPLEQ_HEAD(, LuringAIOCB) submit_queue;
|
||||
} LuringQueue;
|
||||
|
||||
typedef struct LuringState {
|
||||
AioContext *aio_context;
|
||||
|
||||
struct io_uring ring;
|
||||
|
||||
/* io queue for submit at batch. Protected by AioContext lock. */
|
||||
LuringQueue io_q;
|
||||
|
||||
/* I/O completion processing. Only runs in I/O thread. */
|
||||
QEMUBH *completion_bh;
|
||||
} LuringState;
|
||||
|
||||
/**
|
||||
* luring_resubmit:
|
||||
*
|
||||
* Resubmit a request by appending it to submit_queue. The caller must ensure
|
||||
* that ioq_submit() is called later so that submit_queue requests are started.
|
||||
*/
|
||||
static void luring_resubmit(LuringState *s, LuringAIOCB *luringcb)
|
||||
{
|
||||
QSIMPLEQ_INSERT_TAIL(&s->io_q.submit_queue, luringcb, next);
|
||||
s->io_q.in_queue++;
|
||||
}
|
||||
|
||||
/**
|
||||
* luring_resubmit_short_read:
|
||||
*
|
||||
* Before Linux commit 9d93a3f5a0c ("io_uring: punt short reads to async
|
||||
* context") a buffered I/O request with the start of the file range in the
|
||||
* page cache could result in a short read. Applications need to resubmit the
|
||||
* remaining read request.
|
||||
*
|
||||
* This is a slow path but recent kernels never take it.
|
||||
*/
|
||||
static void luring_resubmit_short_read(LuringState *s, LuringAIOCB *luringcb,
|
||||
int nread)
|
||||
{
|
||||
QEMUIOVector *resubmit_qiov;
|
||||
size_t remaining;
|
||||
|
||||
trace_luring_resubmit_short_read(s, luringcb, nread);
|
||||
|
||||
/* Update read position */
|
||||
luringcb->total_read = nread;
|
||||
remaining = luringcb->qiov->size - luringcb->total_read;
|
||||
|
||||
/* Shorten qiov */
|
||||
resubmit_qiov = &luringcb->resubmit_qiov;
|
||||
if (resubmit_qiov->iov == NULL) {
|
||||
qemu_iovec_init(resubmit_qiov, luringcb->qiov->niov);
|
||||
} else {
|
||||
qemu_iovec_reset(resubmit_qiov);
|
||||
}
|
||||
qemu_iovec_concat(resubmit_qiov, luringcb->qiov, luringcb->total_read,
|
||||
remaining);
|
||||
|
||||
/* Update sqe */
|
||||
luringcb->sqeq.off = nread;
|
||||
luringcb->sqeq.addr = (__u64)(uintptr_t)luringcb->resubmit_qiov.iov;
|
||||
luringcb->sqeq.len = luringcb->resubmit_qiov.niov;
|
||||
|
||||
luring_resubmit(s, luringcb);
|
||||
}
|
||||
|
||||
/**
|
||||
* luring_process_completions:
|
||||
* @s: AIO state
|
||||
*
|
||||
* Fetches completed I/O requests, consumes cqes and invokes their callbacks
|
||||
* The function is somewhat tricky because it supports nested event loops, for
|
||||
* example when a request callback invokes aio_poll().
|
||||
*
|
||||
* Function schedules BH completion so it can be called again in a nested
|
||||
* event loop. When there are no events left to complete the BH is being
|
||||
* canceled.
|
||||
*
|
||||
*/
|
||||
static void luring_process_completions(LuringState *s)
|
||||
{
|
||||
struct io_uring_cqe *cqes;
|
||||
int total_bytes;
|
||||
/*
|
||||
* Request completion callbacks can run the nested event loop.
|
||||
* Schedule ourselves so the nested event loop will "see" remaining
|
||||
* completed requests and process them. Without this, completion
|
||||
* callbacks that wait for other requests using a nested event loop
|
||||
* would hang forever.
|
||||
*
|
||||
* This workaround is needed because io_uring uses poll_wait, which
|
||||
* is woken up when new events are added to the uring, thus polling on
|
||||
* the same uring fd will block unless more events are received.
|
||||
*
|
||||
* Other leaf block drivers (drivers that access the data themselves)
|
||||
* are networking based, so they poll sockets for data and run the
|
||||
* correct coroutine.
|
||||
*/
|
||||
qemu_bh_schedule(s->completion_bh);
|
||||
|
||||
while (io_uring_peek_cqe(&s->ring, &cqes) == 0) {
|
||||
LuringAIOCB *luringcb;
|
||||
int ret;
|
||||
|
||||
if (!cqes) {
|
||||
break;
|
||||
}
|
||||
|
||||
luringcb = io_uring_cqe_get_data(cqes);
|
||||
ret = cqes->res;
|
||||
io_uring_cqe_seen(&s->ring, cqes);
|
||||
cqes = NULL;
|
||||
|
||||
/* Change counters one-by-one because we can be nested. */
|
||||
s->io_q.in_flight--;
|
||||
trace_luring_process_completion(s, luringcb, ret);
|
||||
|
||||
/* total_read is non-zero only for resubmitted read requests */
|
||||
total_bytes = ret + luringcb->total_read;
|
||||
|
||||
if (ret < 0) {
|
||||
if (ret == -EINTR) {
|
||||
luring_resubmit(s, luringcb);
|
||||
continue;
|
||||
}
|
||||
} else if (!luringcb->qiov) {
|
||||
goto end;
|
||||
} else if (total_bytes == luringcb->qiov->size) {
|
||||
ret = 0;
|
||||
/* Only read/write */
|
||||
} else {
|
||||
/* Short Read/Write */
|
||||
if (luringcb->is_read) {
|
||||
if (ret > 0) {
|
||||
luring_resubmit_short_read(s, luringcb, ret);
|
||||
continue;
|
||||
} else {
|
||||
/* Pad with zeroes */
|
||||
qemu_iovec_memset(luringcb->qiov, total_bytes, 0,
|
||||
luringcb->qiov->size - total_bytes);
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
ret = -ENOSPC;
|
||||
}
|
||||
}
|
||||
end:
|
||||
luringcb->ret = ret;
|
||||
qemu_iovec_destroy(&luringcb->resubmit_qiov);
|
||||
|
||||
/*
|
||||
* If the coroutine is already entered it must be in ioq_submit()
|
||||
* and will notice luringcb->ret has been filled in when it
|
||||
* eventually runs later. Coroutines cannot be entered recursively
|
||||
* so avoid doing that!
|
||||
*/
|
||||
if (!qemu_coroutine_entered(luringcb->co)) {
|
||||
aio_co_wake(luringcb->co);
|
||||
}
|
||||
}
|
||||
qemu_bh_cancel(s->completion_bh);
|
||||
}
|
||||
|
||||
static int ioq_submit(LuringState *s)
|
||||
{
|
||||
int ret = 0;
|
||||
LuringAIOCB *luringcb, *luringcb_next;
|
||||
|
||||
while (s->io_q.in_queue > 0) {
|
||||
/*
|
||||
* Try to fetch sqes from the ring for requests waiting in
|
||||
* the overflow queue
|
||||
*/
|
||||
QSIMPLEQ_FOREACH_SAFE(luringcb, &s->io_q.submit_queue, next,
|
||||
luringcb_next) {
|
||||
struct io_uring_sqe *sqes = io_uring_get_sqe(&s->ring);
|
||||
if (!sqes) {
|
||||
break;
|
||||
}
|
||||
/* Prep sqe for submission */
|
||||
*sqes = luringcb->sqeq;
|
||||
QSIMPLEQ_REMOVE_HEAD(&s->io_q.submit_queue, next);
|
||||
}
|
||||
ret = io_uring_submit(&s->ring);
|
||||
trace_luring_io_uring_submit(s, ret);
|
||||
/* Prevent infinite loop if submission is refused */
|
||||
if (ret <= 0) {
|
||||
if (ret == -EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
s->io_q.in_flight += ret;
|
||||
s->io_q.in_queue -= ret;
|
||||
}
|
||||
s->io_q.blocked = (s->io_q.in_queue > 0);
|
||||
|
||||
if (s->io_q.in_flight) {
|
||||
/*
|
||||
* We can try to complete something just right away if there are
|
||||
* still requests in-flight.
|
||||
*/
|
||||
luring_process_completions(s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void luring_process_completions_and_submit(LuringState *s)
|
||||
{
|
||||
aio_context_acquire(s->aio_context);
|
||||
luring_process_completions(s);
|
||||
|
||||
if (!s->io_q.plugged && s->io_q.in_queue > 0) {
|
||||
ioq_submit(s);
|
||||
}
|
||||
aio_context_release(s->aio_context);
|
||||
}
|
||||
|
||||
static void qemu_luring_completion_bh(void *opaque)
|
||||
{
|
||||
LuringState *s = opaque;
|
||||
luring_process_completions_and_submit(s);
|
||||
}
|
||||
|
||||
static void qemu_luring_completion_cb(void *opaque)
|
||||
{
|
||||
LuringState *s = opaque;
|
||||
luring_process_completions_and_submit(s);
|
||||
}
|
||||
|
||||
static bool qemu_luring_poll_cb(void *opaque)
|
||||
{
|
||||
LuringState *s = opaque;
|
||||
struct io_uring_cqe *cqes;
|
||||
|
||||
if (io_uring_peek_cqe(&s->ring, &cqes) == 0) {
|
||||
if (cqes) {
|
||||
luring_process_completions_and_submit(s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ioq_init(LuringQueue *io_q)
|
||||
{
|
||||
QSIMPLEQ_INIT(&io_q->submit_queue);
|
||||
io_q->plugged = 0;
|
||||
io_q->in_queue = 0;
|
||||
io_q->in_flight = 0;
|
||||
io_q->blocked = false;
|
||||
}
|
||||
|
||||
void luring_io_plug(BlockDriverState *bs, LuringState *s)
|
||||
{
|
||||
trace_luring_io_plug(s);
|
||||
s->io_q.plugged++;
|
||||
}
|
||||
|
||||
void luring_io_unplug(BlockDriverState *bs, LuringState *s)
|
||||
{
|
||||
assert(s->io_q.plugged);
|
||||
trace_luring_io_unplug(s, s->io_q.blocked, s->io_q.plugged,
|
||||
s->io_q.in_queue, s->io_q.in_flight);
|
||||
if (--s->io_q.plugged == 0 &&
|
||||
!s->io_q.blocked && s->io_q.in_queue > 0) {
|
||||
ioq_submit(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* luring_do_submit:
|
||||
* @fd: file descriptor for I/O
|
||||
* @luringcb: AIO control block
|
||||
* @s: AIO state
|
||||
* @offset: offset for request
|
||||
* @type: type of request
|
||||
*
|
||||
* Fetches sqes from ring, adds to pending queue and preps them
|
||||
*
|
||||
*/
|
||||
static int luring_do_submit(int fd, LuringAIOCB *luringcb, LuringState *s,
|
||||
uint64_t offset, int type)
|
||||
{
|
||||
int ret;
|
||||
struct io_uring_sqe *sqes = &luringcb->sqeq;
|
||||
|
||||
switch (type) {
|
||||
case QEMU_AIO_WRITE:
|
||||
io_uring_prep_writev(sqes, fd, luringcb->qiov->iov,
|
||||
luringcb->qiov->niov, offset);
|
||||
break;
|
||||
case QEMU_AIO_READ:
|
||||
io_uring_prep_readv(sqes, fd, luringcb->qiov->iov,
|
||||
luringcb->qiov->niov, offset);
|
||||
break;
|
||||
case QEMU_AIO_FLUSH:
|
||||
io_uring_prep_fsync(sqes, fd, IORING_FSYNC_DATASYNC);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: invalid AIO request type, aborting 0x%x.\n",
|
||||
__func__, type);
|
||||
abort();
|
||||
}
|
||||
io_uring_sqe_set_data(sqes, luringcb);
|
||||
|
||||
QSIMPLEQ_INSERT_TAIL(&s->io_q.submit_queue, luringcb, next);
|
||||
s->io_q.in_queue++;
|
||||
trace_luring_do_submit(s, s->io_q.blocked, s->io_q.plugged,
|
||||
s->io_q.in_queue, s->io_q.in_flight);
|
||||
if (!s->io_q.blocked &&
|
||||
(!s->io_q.plugged ||
|
||||
s->io_q.in_flight + s->io_q.in_queue >= MAX_ENTRIES)) {
|
||||
ret = ioq_submit(s);
|
||||
trace_luring_do_submit_done(s, ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int coroutine_fn luring_co_submit(BlockDriverState *bs, LuringState *s, int fd,
|
||||
uint64_t offset, QEMUIOVector *qiov, int type)
|
||||
{
|
||||
int ret;
|
||||
LuringAIOCB luringcb = {
|
||||
.co = qemu_coroutine_self(),
|
||||
.ret = -EINPROGRESS,
|
||||
.qiov = qiov,
|
||||
.is_read = (type == QEMU_AIO_READ),
|
||||
};
|
||||
trace_luring_co_submit(bs, s, &luringcb, fd, offset, qiov ? qiov->size : 0,
|
||||
type);
|
||||
ret = luring_do_submit(fd, &luringcb, s, offset, type);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (luringcb.ret == -EINPROGRESS) {
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
return luringcb.ret;
|
||||
}
|
||||
|
||||
void luring_detach_aio_context(LuringState *s, AioContext *old_context)
|
||||
{
|
||||
aio_set_fd_handler(old_context, s->ring.ring_fd, false, NULL, NULL, NULL,
|
||||
s);
|
||||
qemu_bh_delete(s->completion_bh);
|
||||
s->aio_context = NULL;
|
||||
}
|
||||
|
||||
void luring_attach_aio_context(LuringState *s, AioContext *new_context)
|
||||
{
|
||||
s->aio_context = new_context;
|
||||
s->completion_bh = aio_bh_new(new_context, qemu_luring_completion_bh, s);
|
||||
aio_set_fd_handler(s->aio_context, s->ring.ring_fd, false,
|
||||
qemu_luring_completion_cb, NULL, qemu_luring_poll_cb, s);
|
||||
}
|
||||
|
||||
LuringState *luring_init(Error **errp)
|
||||
{
|
||||
int rc;
|
||||
LuringState *s = g_new0(LuringState, 1);
|
||||
struct io_uring *ring = &s->ring;
|
||||
|
||||
trace_luring_init_state(s, sizeof(*s));
|
||||
|
||||
rc = io_uring_queue_init(MAX_ENTRIES, ring, 0);
|
||||
if (rc < 0) {
|
||||
error_setg_errno(errp, errno, "failed to init linux io_uring ring");
|
||||
g_free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ioq_init(&s->io_q);
|
||||
return s;
|
||||
|
||||
}
|
||||
|
||||
void luring_cleanup(LuringState *s)
|
||||
{
|
||||
io_uring_queue_exit(&s->ring);
|
||||
g_free(s);
|
||||
trace_luring_cleanup_state(s);
|
||||
}
|
||||
+72
-7
@@ -753,7 +753,7 @@ retry:
|
||||
}
|
||||
|
||||
lbas = scsi_datain_unmarshall(iTask.task);
|
||||
if (lbas == NULL || lbas->num_descriptors == 0) {
|
||||
if (lbas == NULL) {
|
||||
ret = -EIO;
|
||||
goto out_unlock;
|
||||
}
|
||||
@@ -991,7 +991,8 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
|
||||
acb->ioh->driver_status |= SG_ERR_DRIVER_SENSE;
|
||||
|
||||
acb->ioh->sb_len_wr = acb->task->datain.size - 2;
|
||||
ss = MIN(acb->ioh->mx_sb_len, acb->ioh->sb_len_wr);
|
||||
ss = (acb->ioh->mx_sb_len >= acb->ioh->sb_len_wr) ?
|
||||
acb->ioh->mx_sb_len : acb->ioh->sb_len_wr;
|
||||
memcpy(acb->ioh->sbp, &acb->task->datain.data[2], ss);
|
||||
}
|
||||
|
||||
@@ -2001,7 +2002,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
iscsilun->cluster_size = iscsilun->bl.opt_unmap_gran *
|
||||
iscsilun->block_size;
|
||||
if (iscsilun->lbprz) {
|
||||
ret = iscsi_allocmap_init(iscsilun, flags);
|
||||
ret = iscsi_allocmap_init(iscsilun, bs->open_flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2163,6 +2164,58 @@ static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coroutine_fn iscsi_co_create_opts(const char *filename, QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
int64_t total_size = 0;
|
||||
BlockDriverState *bs;
|
||||
IscsiLun *iscsilun = NULL;
|
||||
QDict *bs_options;
|
||||
Error *local_err = NULL;
|
||||
|
||||
bs = bdrv_new();
|
||||
|
||||
/* Read out options */
|
||||
total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||
BDRV_SECTOR_SIZE);
|
||||
bs->opaque = g_new0(struct IscsiLun, 1);
|
||||
iscsilun = bs->opaque;
|
||||
|
||||
bs_options = qdict_new();
|
||||
iscsi_parse_filename(filename, bs_options, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
ret = iscsi_open(bs, bs_options, 0, NULL);
|
||||
}
|
||||
qobject_unref(bs_options);
|
||||
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
iscsi_detach_aio_context(bs);
|
||||
if (iscsilun->type != TYPE_DISK) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
if (bs->total_sectors < total_size) {
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
if (iscsilun->iscsi != NULL) {
|
||||
iscsi_destroy_context(iscsilun->iscsi);
|
||||
}
|
||||
g_free(bs->opaque);
|
||||
bs->opaque = NULL;
|
||||
bdrv_unref(bs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
@@ -2398,6 +2451,18 @@ out_unlock:
|
||||
return r;
|
||||
}
|
||||
|
||||
static QemuOptsList iscsi_create_opts = {
|
||||
.name = "iscsi-create-opts",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(iscsi_create_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = BLOCK_OPT_SIZE,
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "Virtual disk size"
|
||||
},
|
||||
{ /* end of list */ }
|
||||
}
|
||||
};
|
||||
|
||||
static const char *const iscsi_strong_runtime_opts[] = {
|
||||
"transport",
|
||||
@@ -2421,8 +2486,8 @@ static BlockDriver bdrv_iscsi = {
|
||||
.bdrv_parse_filename = iscsi_parse_filename,
|
||||
.bdrv_file_open = iscsi_open,
|
||||
.bdrv_close = iscsi_close,
|
||||
.bdrv_co_create_opts = bdrv_co_create_opts_simple,
|
||||
.create_opts = &bdrv_create_opts_simple,
|
||||
.bdrv_co_create_opts = iscsi_co_create_opts,
|
||||
.create_opts = &iscsi_create_opts,
|
||||
.bdrv_reopen_prepare = iscsi_reopen_prepare,
|
||||
.bdrv_reopen_commit = iscsi_reopen_commit,
|
||||
.bdrv_co_invalidate_cache = iscsi_co_invalidate_cache,
|
||||
@@ -2460,8 +2525,8 @@ static BlockDriver bdrv_iser = {
|
||||
.bdrv_parse_filename = iscsi_parse_filename,
|
||||
.bdrv_file_open = iscsi_open,
|
||||
.bdrv_close = iscsi_close,
|
||||
.bdrv_co_create_opts = bdrv_co_create_opts_simple,
|
||||
.create_opts = &bdrv_create_opts_simple,
|
||||
.bdrv_co_create_opts = iscsi_co_create_opts,
|
||||
.create_opts = &iscsi_create_opts,
|
||||
.bdrv_reopen_prepare = iscsi_reopen_prepare,
|
||||
.bdrv_reopen_commit = iscsi_reopen_commit,
|
||||
.bdrv_co_invalidate_cache = iscsi_co_invalidate_cache,
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@
|
||||
* than this we will get EAGAIN from io_submit which is communicated to
|
||||
* the guest as an I/O error.
|
||||
*/
|
||||
#define MAX_EVENTS 1024
|
||||
#define MAX_EVENTS 128
|
||||
|
||||
struct qemu_laiocb {
|
||||
Coroutine *co;
|
||||
@@ -121,7 +121,7 @@ struct aio_ring {
|
||||
unsigned incompat_features;
|
||||
unsigned header_length; /* size of aio_ring */
|
||||
|
||||
struct io_event io_events[];
|
||||
struct io_event io_events[0];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+2
-24
@@ -102,9 +102,7 @@ struct MirrorOp {
|
||||
|
||||
bool is_pseudo_op;
|
||||
bool is_active_write;
|
||||
bool is_in_flight;
|
||||
CoQueue waiting_requests;
|
||||
Coroutine *co;
|
||||
|
||||
QTAILQ_ENTRY(MirrorOp) next;
|
||||
};
|
||||
@@ -294,9 +292,7 @@ mirror_wait_for_any_operation(MirrorBlockJob *s, bool active)
|
||||
* caller of this function. Since there is only one pseudo op
|
||||
* at any given time, we will always find some real operation
|
||||
* to wait on. */
|
||||
if (!op->is_pseudo_op && op->is_in_flight &&
|
||||
op->is_active_write == active)
|
||||
{
|
||||
if (!op->is_pseudo_op && op->is_active_write == active) {
|
||||
qemu_co_queue_wait(&op->waiting_requests, NULL);
|
||||
return;
|
||||
}
|
||||
@@ -370,7 +366,6 @@ static void coroutine_fn mirror_co_read(void *opaque)
|
||||
/* Copy the dirty cluster. */
|
||||
s->in_flight++;
|
||||
s->bytes_in_flight += op->bytes;
|
||||
op->is_in_flight = true;
|
||||
trace_mirror_one_iteration(s, op->offset, op->bytes);
|
||||
|
||||
ret = bdrv_co_preadv(s->mirror_top_bs->backing, op->offset, op->bytes,
|
||||
@@ -386,7 +381,6 @@ static void coroutine_fn mirror_co_zero(void *opaque)
|
||||
op->s->in_flight++;
|
||||
op->s->bytes_in_flight += op->bytes;
|
||||
*op->bytes_handled = op->bytes;
|
||||
op->is_in_flight = true;
|
||||
|
||||
ret = blk_co_pwrite_zeroes(op->s->target, op->offset, op->bytes,
|
||||
op->s->unmap ? BDRV_REQ_MAY_UNMAP : 0);
|
||||
@@ -401,7 +395,6 @@ static void coroutine_fn mirror_co_discard(void *opaque)
|
||||
op->s->in_flight++;
|
||||
op->s->bytes_in_flight += op->bytes;
|
||||
*op->bytes_handled = op->bytes;
|
||||
op->is_in_flight = true;
|
||||
|
||||
ret = blk_co_pdiscard(op->s->target, op->offset, op->bytes);
|
||||
mirror_write_complete(op, ret);
|
||||
@@ -436,7 +429,6 @@ static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset,
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
op->co = co;
|
||||
|
||||
QTAILQ_INSERT_TAIL(&s->ops_in_flight, op, next);
|
||||
qemu_coroutine_enter(co);
|
||||
@@ -681,7 +673,6 @@ static int mirror_exit_common(Job *job)
|
||||
bdrv_set_backing_hd(target_bs, backing, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
local_err = NULL;
|
||||
ret = -EPERM;
|
||||
}
|
||||
}
|
||||
@@ -704,19 +695,7 @@ static int mirror_exit_common(Job *job)
|
||||
* drain potential other users of the BDS before changing the graph. */
|
||||
assert(s->in_drain);
|
||||
bdrv_drained_begin(target_bs);
|
||||
/*
|
||||
* Cannot use check_to_replace_node() here, because that would
|
||||
* check for an op blocker on @to_replace, and we have our own
|
||||
* there.
|
||||
*/
|
||||
if (bdrv_recurse_can_replace(src, to_replace)) {
|
||||
bdrv_replace_node(to_replace, target_bs, &local_err);
|
||||
} else {
|
||||
error_setg(&local_err, "Can no longer replace '%s' by '%s', "
|
||||
"because it can no longer be guaranteed that doing so "
|
||||
"would not lead to an abrupt change of visible data",
|
||||
to_replace->node_name, target_bs->node_name);
|
||||
}
|
||||
bdrv_replace_node(to_replace, target_bs, &local_err);
|
||||
bdrv_drained_end(target_bs);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
@@ -1325,7 +1304,6 @@ static MirrorOp *coroutine_fn active_write_prepare(MirrorBlockJob *s,
|
||||
.offset = offset,
|
||||
.bytes = bytes,
|
||||
.is_active_write = true,
|
||||
.is_in_flight = true,
|
||||
};
|
||||
qemu_co_queue_init(&op->waiting_requests);
|
||||
QTAILQ_INSERT_TAIL(&s->ops_in_flight, op, next);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
common-obj-y += block-hmp-cmds.o
|
||||
File diff suppressed because it is too large.
Load diff
+4
-25
@@ -70,7 +70,6 @@ typedef struct BDRVNBDState {
|
||||
CoMutex send_mutex;
|
||||
CoQueue free_sema;
|
||||
Coroutine *connection_co;
|
||||
Coroutine *teardown_co;
|
||||
QemuCoSleepState *connection_co_sleep_ns_state;
|
||||
bool drained;
|
||||
bool wait_drained_end;
|
||||
@@ -217,15 +216,7 @@ static void nbd_teardown_connection(BlockDriverState *bs)
|
||||
qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
|
||||
}
|
||||
}
|
||||
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);
|
||||
BDRV_POLL_WHILE(bs, s->connection_co);
|
||||
}
|
||||
|
||||
static bool nbd_client_connecting(BDRVNBDState *s)
|
||||
@@ -417,9 +408,6 @@ static coroutine_fn void nbd_connection_entry(void *opaque)
|
||||
s->ioc = NULL;
|
||||
}
|
||||
|
||||
if (s->teardown_co) {
|
||||
aio_co_wake(s->teardown_co);
|
||||
}
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
@@ -891,7 +879,6 @@ typedef struct NBDReplyChunkIter {
|
||||
static void nbd_iter_channel_error(NBDReplyChunkIter *iter,
|
||||
int ret, Error **local_err)
|
||||
{
|
||||
assert(local_err && *local_err);
|
||||
assert(ret < 0);
|
||||
|
||||
if (!iter->ret) {
|
||||
@@ -1541,10 +1528,8 @@ static int nbd_parse_uri(const char *filename, QDict *options)
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = uri->path ? uri->path : "";
|
||||
if (p[0] == '/') {
|
||||
p++;
|
||||
}
|
||||
p = uri->path ? uri->path : "/";
|
||||
p += strspn(p, "/");
|
||||
if (p[0]) {
|
||||
qdict_put_str(options, "export", p);
|
||||
}
|
||||
@@ -2011,7 +1996,7 @@ static void nbd_refresh_filename(BlockDriverState *bs)
|
||||
len = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
"nbd://%s:%s", host, port);
|
||||
}
|
||||
if (len >= sizeof(bs->exact_filename)) {
|
||||
if (len > sizeof(bs->exact_filename)) {
|
||||
/* Name is too long to represent exactly, so leave it empty. */
|
||||
bs->exact_filename[0] = '\0';
|
||||
}
|
||||
@@ -2043,8 +2028,6 @@ static BlockDriver bdrv_nbd = {
|
||||
.protocol_name = "nbd",
|
||||
.instance_size = sizeof(BDRVNBDState),
|
||||
.bdrv_parse_filename = nbd_parse_filename,
|
||||
.bdrv_co_create_opts = bdrv_co_create_opts_simple,
|
||||
.create_opts = &bdrv_create_opts_simple,
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_reopen_prepare = nbd_client_reopen_prepare,
|
||||
.bdrv_co_preadv = nbd_client_co_preadv,
|
||||
@@ -2070,8 +2053,6 @@ static BlockDriver bdrv_nbd_tcp = {
|
||||
.protocol_name = "nbd+tcp",
|
||||
.instance_size = sizeof(BDRVNBDState),
|
||||
.bdrv_parse_filename = nbd_parse_filename,
|
||||
.bdrv_co_create_opts = bdrv_co_create_opts_simple,
|
||||
.create_opts = &bdrv_create_opts_simple,
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_reopen_prepare = nbd_client_reopen_prepare,
|
||||
.bdrv_co_preadv = nbd_client_co_preadv,
|
||||
@@ -2097,8 +2078,6 @@ static BlockDriver bdrv_nbd_unix = {
|
||||
.protocol_name = "nbd+unix",
|
||||
.instance_size = sizeof(BDRVNBDState),
|
||||
.bdrv_parse_filename = nbd_parse_filename,
|
||||
.bdrv_co_create_opts = bdrv_co_create_opts_simple,
|
||||
.create_opts = &bdrv_create_opts_simple,
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_reopen_prepare = nbd_client_reopen_prepare,
|
||||
.bdrv_co_preadv = nbd_client_co_preadv,
|
||||
|
||||
+1
-3
@@ -662,9 +662,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn nfs_file_co_create_opts(BlockDriver *drv,
|
||||
const char *url,
|
||||
QemuOpts *opts,
|
||||
static int coroutine_fn nfs_file_co_create_opts(const char *url, QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
BlockdevCreateOptions *create_options;
|
||||
|
||||
@@ -1333,9 +1333,6 @@ static BlockDriver bdrv_nvme = {
|
||||
.protocol_name = "nvme",
|
||||
.instance_size = sizeof(BDRVNVMeState),
|
||||
|
||||
.bdrv_co_create_opts = bdrv_co_create_opts_simple,
|
||||
.create_opts = &bdrv_create_opts_simple,
|
||||
|
||||
.bdrv_parse_filename = nvme_parse_filename,
|
||||
.bdrv_file_open = nvme_file_open,
|
||||
.bdrv_close = nvme_close,
|
||||
|
||||
+1
-2
@@ -609,8 +609,7 @@ exit:
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int coroutine_fn parallels_co_create_opts(BlockDriver *drv,
|
||||
const char *filename,
|
||||
static int coroutine_fn parallels_co_create_opts(const char *filename,
|
||||
QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
|
||||
@@ -1,590 +0,0 @@
|
||||
/*
|
||||
* QMP command handlers specific to the system emulators
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-block.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
|
||||
static BlockBackend *qmp_get_blk(const char *blk_name, const char *qdev_id,
|
||||
Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
|
||||
if (!blk_name == !qdev_id) {
|
||||
error_setg(errp, "Need exactly one of 'device' and 'id'");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (qdev_id) {
|
||||
blk = blk_by_qdev_id(qdev_id, errp);
|
||||
} else {
|
||||
blk = blk_by_name(blk_name);
|
||||
if (blk == NULL) {
|
||||
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
||||
"Device '%s' not found", blk_name);
|
||||
}
|
||||
}
|
||||
|
||||
return blk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to open the tray of @device.
|
||||
* If @force, ignore its tray lock.
|
||||
* Else, if the tray is locked, don't open it, but ask the guest to open it.
|
||||
* On error, store an error through @errp and return -errno.
|
||||
* If @device does not exist, return -ENODEV.
|
||||
* If it has no removable media, return -ENOTSUP.
|
||||
* If it has no tray, return -ENOSYS.
|
||||
* If the guest was asked to open the tray, return -EINPROGRESS.
|
||||
* Else, return 0.
|
||||
*/
|
||||
static int do_open_tray(const char *blk_name, const char *qdev_id,
|
||||
bool force, Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
const char *device = qdev_id ?: blk_name;
|
||||
bool locked;
|
||||
|
||||
blk = qmp_get_blk(blk_name, qdev_id, errp);
|
||||
if (!blk) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!blk_dev_has_removable_media(blk)) {
|
||||
error_setg(errp, "Device '%s' is not removable", device);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
error_setg(errp, "Device '%s' does not have a tray", device);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
if (blk_dev_is_tray_open(blk)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
locked = blk_dev_is_medium_locked(blk);
|
||||
if (locked) {
|
||||
blk_dev_eject_request(blk, force);
|
||||
}
|
||||
|
||||
if (!locked || force) {
|
||||
blk_dev_change_media_cb(blk, false, &error_abort);
|
||||
}
|
||||
|
||||
if (locked && !force) {
|
||||
error_setg(errp, "Device '%s' is locked and force was not specified, "
|
||||
"wait for tray to open and try again", device);
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qmp_blockdev_open_tray(bool has_device, const char *device,
|
||||
bool has_id, const char *id,
|
||||
bool has_force, bool force,
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int rc;
|
||||
|
||||
if (!has_force) {
|
||||
force = false;
|
||||
}
|
||||
rc = do_open_tray(has_device ? device : NULL,
|
||||
has_id ? id : NULL,
|
||||
force, &local_err);
|
||||
if (rc && rc != -ENOSYS && rc != -EINPROGRESS) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
error_free(local_err);
|
||||
}
|
||||
|
||||
void qmp_blockdev_close_tray(bool has_device, const char *device,
|
||||
bool has_id, const char *id,
|
||||
Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
Error *local_err = NULL;
|
||||
|
||||
device = has_device ? device : NULL;
|
||||
id = has_id ? id : NULL;
|
||||
|
||||
blk = qmp_get_blk(device, id, errp);
|
||||
if (!blk) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blk_dev_has_removable_media(blk)) {
|
||||
error_setg(errp, "Device '%s' is not removable", device ?: id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
/* Ignore this command on tray-less devices */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blk_dev_is_tray_open(blk)) {
|
||||
return;
|
||||
}
|
||||
|
||||
blk_dev_change_media_cb(blk, true, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void blockdev_remove_medium(bool has_device, const char *device,
|
||||
bool has_id, const char *id, Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
bool has_attached_device;
|
||||
|
||||
device = has_device ? device : NULL;
|
||||
id = has_id ? id : NULL;
|
||||
|
||||
blk = qmp_get_blk(device, id, errp);
|
||||
if (!blk) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* For BBs without a device, we can exchange the BDS tree at will */
|
||||
has_attached_device = blk_get_attached_dev(blk);
|
||||
|
||||
if (has_attached_device && !blk_dev_has_removable_media(blk)) {
|
||||
error_setg(errp, "Device '%s' is not removable", device ?: id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_attached_device && blk_dev_has_tray(blk) &&
|
||||
!blk_dev_is_tray_open(blk))
|
||||
{
|
||||
error_setg(errp, "Tray of device '%s' is not open", device ?: id);
|
||||
return;
|
||||
}
|
||||
|
||||
bs = blk_bs(blk);
|
||||
if (!bs) {
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
blk_remove_bs(blk);
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
/* For tray-less devices, blockdev-open-tray is a no-op (or may not be
|
||||
* called at all); therefore, the medium needs to be ejected here.
|
||||
* Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load
|
||||
* value passed here (i.e. false). */
|
||||
blk_dev_change_media_cb(blk, false, &error_abort);
|
||||
}
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
void qmp_blockdev_remove_medium(const char *id, Error **errp)
|
||||
{
|
||||
blockdev_remove_medium(false, NULL, true, id, errp);
|
||||
}
|
||||
|
||||
static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
|
||||
BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
bool has_device;
|
||||
int ret;
|
||||
|
||||
/* For BBs without a device, we can exchange the BDS tree at will */
|
||||
has_device = blk_get_attached_dev(blk);
|
||||
|
||||
if (has_device && !blk_dev_has_removable_media(blk)) {
|
||||
error_setg(errp, "Device is not removable");
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
|
||||
error_setg(errp, "Tray of the device is not open");
|
||||
return;
|
||||
}
|
||||
|
||||
if (blk_bs(blk)) {
|
||||
error_setg(errp, "There already is a medium in the device");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = blk_insert_bs(blk, bs, errp);
|
||||
if (ret < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
/* For tray-less devices, blockdev-close-tray is a no-op (or may not be
|
||||
* called at all); therefore, the medium needs to be pushed into the
|
||||
* slot here.
|
||||
* Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load
|
||||
* value passed here (i.e. true). */
|
||||
blk_dev_change_media_cb(blk, true, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
blk_remove_bs(blk);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blockdev_insert_medium(bool has_device, const char *device,
|
||||
bool has_id, const char *id,
|
||||
const char *node_name, Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
|
||||
blk = qmp_get_blk(has_device ? device : NULL,
|
||||
has_id ? id : NULL,
|
||||
errp);
|
||||
if (!blk) {
|
||||
return;
|
||||
}
|
||||
|
||||
bs = bdrv_find_node(node_name);
|
||||
if (!bs) {
|
||||
error_setg(errp, "Node '%s' not found", node_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_has_blk(bs)) {
|
||||
error_setg(errp, "Node '%s' is already in use", node_name);
|
||||
return;
|
||||
}
|
||||
|
||||
qmp_blockdev_insert_anon_medium(blk, bs, errp);
|
||||
}
|
||||
|
||||
void qmp_blockdev_insert_medium(const char *id, const char *node_name,
|
||||
Error **errp)
|
||||
{
|
||||
blockdev_insert_medium(false, NULL, true, id, node_name, errp);
|
||||
}
|
||||
|
||||
void qmp_blockdev_change_medium(bool has_device, const char *device,
|
||||
bool has_id, const char *id,
|
||||
const char *filename,
|
||||
bool has_format, const char *format,
|
||||
bool has_read_only,
|
||||
BlockdevChangeReadOnlyMode read_only,
|
||||
Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *medium_bs = NULL;
|
||||
int bdrv_flags;
|
||||
bool detect_zeroes;
|
||||
int rc;
|
||||
QDict *options = NULL;
|
||||
Error *err = NULL;
|
||||
|
||||
blk = qmp_get_blk(has_device ? device : NULL,
|
||||
has_id ? id : NULL,
|
||||
errp);
|
||||
if (!blk) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (blk_bs(blk)) {
|
||||
blk_update_root_state(blk);
|
||||
}
|
||||
|
||||
bdrv_flags = blk_get_open_flags_from_root_state(blk);
|
||||
bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
|
||||
BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
|
||||
|
||||
if (!has_read_only) {
|
||||
read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
|
||||
}
|
||||
|
||||
switch (read_only) {
|
||||
case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
|
||||
break;
|
||||
|
||||
case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
|
||||
bdrv_flags &= ~BDRV_O_RDWR;
|
||||
break;
|
||||
|
||||
case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
|
||||
bdrv_flags |= BDRV_O_RDWR;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
options = qdict_new();
|
||||
detect_zeroes = blk_get_detect_zeroes_from_root_state(blk);
|
||||
qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off");
|
||||
|
||||
if (has_format) {
|
||||
qdict_put_str(options, "driver", format);
|
||||
}
|
||||
|
||||
medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
|
||||
if (!medium_bs) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = do_open_tray(has_device ? device : NULL,
|
||||
has_id ? id : NULL,
|
||||
false, &err);
|
||||
if (rc && rc != -ENOSYS) {
|
||||
error_propagate(errp, err);
|
||||
goto fail;
|
||||
}
|
||||
error_free(err);
|
||||
err = NULL;
|
||||
|
||||
blockdev_remove_medium(has_device, device, has_id, id, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
qmp_blockdev_close_tray(has_device, device, has_id, id, errp);
|
||||
|
||||
fail:
|
||||
/* If the medium has been inserted, the device has its own reference, so
|
||||
* ours must be relinquished; and if it has not been inserted successfully,
|
||||
* the reference must be relinquished anyway */
|
||||
bdrv_unref(medium_bs);
|
||||
}
|
||||
|
||||
void qmp_eject(bool has_device, const char *device,
|
||||
bool has_id, const char *id,
|
||||
bool has_force, bool force, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int rc;
|
||||
|
||||
if (!has_force) {
|
||||
force = false;
|
||||
}
|
||||
|
||||
rc = do_open_tray(has_device ? device : NULL,
|
||||
has_id ? id : NULL,
|
||||
force, &local_err);
|
||||
if (rc && rc != -ENOSYS) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
error_free(local_err);
|
||||
|
||||
blockdev_remove_medium(has_device, device, has_id, id, errp);
|
||||
}
|
||||
|
||||
/* throttling disk I/O limits */
|
||||
void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
|
||||
{
|
||||
ThrottleConfig cfg;
|
||||
BlockDriverState *bs;
|
||||
BlockBackend *blk;
|
||||
AioContext *aio_context;
|
||||
|
||||
blk = qmp_get_blk(arg->has_device ? arg->device : NULL,
|
||||
arg->has_id ? arg->id : NULL,
|
||||
errp);
|
||||
if (!blk) {
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = blk_get_aio_context(blk);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
bs = blk_bs(blk);
|
||||
if (!bs) {
|
||||
error_setg(errp, "Device has no medium");
|
||||
goto out;
|
||||
}
|
||||
|
||||
throttle_config_init(&cfg);
|
||||
cfg.buckets[THROTTLE_BPS_TOTAL].avg = arg->bps;
|
||||
cfg.buckets[THROTTLE_BPS_READ].avg = arg->bps_rd;
|
||||
cfg.buckets[THROTTLE_BPS_WRITE].avg = arg->bps_wr;
|
||||
|
||||
cfg.buckets[THROTTLE_OPS_TOTAL].avg = arg->iops;
|
||||
cfg.buckets[THROTTLE_OPS_READ].avg = arg->iops_rd;
|
||||
cfg.buckets[THROTTLE_OPS_WRITE].avg = arg->iops_wr;
|
||||
|
||||
if (arg->has_bps_max) {
|
||||
cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max;
|
||||
}
|
||||
if (arg->has_bps_rd_max) {
|
||||
cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max;
|
||||
}
|
||||
if (arg->has_bps_wr_max) {
|
||||
cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max;
|
||||
}
|
||||
if (arg->has_iops_max) {
|
||||
cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max;
|
||||
}
|
||||
if (arg->has_iops_rd_max) {
|
||||
cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max;
|
||||
}
|
||||
if (arg->has_iops_wr_max) {
|
||||
cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max;
|
||||
}
|
||||
|
||||
if (arg->has_bps_max_length) {
|
||||
cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length;
|
||||
}
|
||||
if (arg->has_bps_rd_max_length) {
|
||||
cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length;
|
||||
}
|
||||
if (arg->has_bps_wr_max_length) {
|
||||
cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length;
|
||||
}
|
||||
if (arg->has_iops_max_length) {
|
||||
cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length;
|
||||
}
|
||||
if (arg->has_iops_rd_max_length) {
|
||||
cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length;
|
||||
}
|
||||
if (arg->has_iops_wr_max_length) {
|
||||
cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length;
|
||||
}
|
||||
|
||||
if (arg->has_iops_size) {
|
||||
cfg.op_size = arg->iops_size;
|
||||
}
|
||||
|
||||
if (!throttle_is_valid(&cfg, errp)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (throttle_enabled(&cfg)) {
|
||||
/* Enable I/O limits if they're not enabled yet, otherwise
|
||||
* just update the throttling group. */
|
||||
if (!blk_get_public(blk)->throttle_group_member.throttle_state) {
|
||||
blk_io_limits_enable(blk,
|
||||
arg->has_group ? arg->group :
|
||||
arg->has_device ? arg->device :
|
||||
arg->id);
|
||||
} else if (arg->has_group) {
|
||||
blk_io_limits_update_group(blk, arg->group);
|
||||
}
|
||||
/* Set the new throttling configuration */
|
||||
blk_set_io_limits(blk, &cfg);
|
||||
} else if (blk_get_public(blk)->throttle_group_member.throttle_state) {
|
||||
/* If all throttling settings are set to 0, disable I/O limits */
|
||||
blk_io_limits_disable(blk);
|
||||
}
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
void qmp_block_latency_histogram_set(
|
||||
const char *id,
|
||||
bool has_boundaries, uint64List *boundaries,
|
||||
bool has_boundaries_read, uint64List *boundaries_read,
|
||||
bool has_boundaries_write, uint64List *boundaries_write,
|
||||
bool has_boundaries_flush, uint64List *boundaries_flush,
|
||||
Error **errp)
|
||||
{
|
||||
BlockBackend *blk = qmp_get_blk(NULL, id, errp);
|
||||
BlockAcctStats *stats;
|
||||
int ret;
|
||||
|
||||
if (!blk) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats = blk_get_stats(blk);
|
||||
|
||||
if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
|
||||
!has_boundaries_flush)
|
||||
{
|
||||
block_latency_histograms_clear(stats);
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_boundaries || has_boundaries_read) {
|
||||
ret = block_latency_histogram_set(
|
||||
stats, BLOCK_ACCT_READ,
|
||||
has_boundaries_read ? boundaries_read : boundaries);
|
||||
if (ret) {
|
||||
error_setg(errp, "Device '%s' set read boundaries fail", id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_boundaries || has_boundaries_write) {
|
||||
ret = block_latency_histogram_set(
|
||||
stats, BLOCK_ACCT_WRITE,
|
||||
has_boundaries_write ? boundaries_write : boundaries);
|
||||
if (ret) {
|
||||
error_setg(errp, "Device '%s' set write boundaries fail", id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_boundaries || has_boundaries_flush) {
|
||||
ret = block_latency_histogram_set(
|
||||
stats, BLOCK_ACCT_FLUSH,
|
||||
has_boundaries_flush ? boundaries_flush : boundaries);
|
||||
if (ret) {
|
||||
error_setg(errp, "Device '%s' set flush boundaries fail", id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-9
@@ -42,9 +42,7 @@
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
|
||||
BlockDriverState *bs,
|
||||
bool flat,
|
||||
Error **errp)
|
||||
BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
ImageInfo **p_image_info;
|
||||
BlockDriverState *bs0;
|
||||
@@ -158,11 +156,6 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* stop gathering data for flat output */
|
||||
if (flat) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (bs0->drv && bs0->backing) {
|
||||
info->backing_file_depth++;
|
||||
bs0 = bs0->backing->bs;
|
||||
@@ -396,7 +389,7 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
|
||||
|
||||
if (bs && bs->drv) {
|
||||
info->has_inserted = true;
|
||||
info->inserted = bdrv_block_device_info(blk, bs, false, errp);
|
||||
info->inserted = bdrv_block_device_info(blk, bs, errp);
|
||||
if (info->inserted == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
+1
-2
@@ -934,8 +934,7 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn qcow_co_create_opts(BlockDriver *drv,
|
||||
const char *filename,
|
||||
static int coroutine_fn qcow_co_create_opts(const char *filename,
|
||||
QemuOpts *opts, Error **errp)
|
||||
{
|
||||
BlockdevCreateOptions *create_options = NULL;
|
||||
|
||||
+11
-5
@@ -647,6 +647,7 @@ static Qcow2BitmapList *bitmap_list_load(BlockDriverState *bs, uint64_t offset,
|
||||
return bm_list;
|
||||
|
||||
broken_dir:
|
||||
ret = -EINVAL;
|
||||
error_setg(errp, "Broken bitmap directory");
|
||||
|
||||
fail:
|
||||
@@ -1288,6 +1289,7 @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
|
||||
uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
|
||||
const char *bm_name = bdrv_dirty_bitmap_name(bitmap);
|
||||
uint8_t *buf = NULL;
|
||||
BdrvDirtyBitmapIter *dbi;
|
||||
uint64_t *tb;
|
||||
uint64_t tb_size =
|
||||
size_to_clusters(s,
|
||||
@@ -1306,14 +1308,12 @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbi = bdrv_dirty_iter_new(bitmap);
|
||||
buf = g_malloc(s->cluster_size);
|
||||
limit = bytes_covered_by_bitmap_cluster(s, bitmap);
|
||||
assert(DIV_ROUND_UP(bm_size, limit) == tb_size);
|
||||
|
||||
offset = 0;
|
||||
while ((offset = bdrv_dirty_bitmap_next_dirty(bitmap, offset, INT64_MAX))
|
||||
>= 0)
|
||||
{
|
||||
while ((offset = bdrv_dirty_iter_next(dbi)) >= 0) {
|
||||
uint64_t cluster = offset / limit;
|
||||
uint64_t end, write_size;
|
||||
int64_t off;
|
||||
@@ -1356,17 +1356,23 @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
offset = end;
|
||||
if (end >= bm_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
bdrv_set_dirty_iter(dbi, end);
|
||||
}
|
||||
|
||||
*bitmap_table_size = tb_size;
|
||||
g_free(buf);
|
||||
bdrv_dirty_iter_free(dbi);
|
||||
|
||||
return tb;
|
||||
|
||||
fail:
|
||||
clear_bitmap_table(bs, tb, tb_size);
|
||||
g_free(buf);
|
||||
bdrv_dirty_iter_free(dbi);
|
||||
g_free(tb);
|
||||
|
||||
return NULL;
|
||||
|
||||
+15
-29
@@ -124,11 +124,12 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
||||
#endif
|
||||
|
||||
new_l1_size2 = sizeof(uint64_t) * new_l1_size;
|
||||
new_l1_table = qemu_try_blockalign(bs->file->bs, new_l1_size2);
|
||||
new_l1_table = qemu_try_blockalign(bs->file->bs,
|
||||
ROUND_UP(new_l1_size2, 512));
|
||||
if (new_l1_table == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(new_l1_table, 0, new_l1_size2);
|
||||
memset(new_l1_table, 0, ROUND_UP(new_l1_size2, 512));
|
||||
|
||||
if (s->l1_size) {
|
||||
memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
|
||||
@@ -216,31 +217,26 @@ static int l2_load(BlockDriverState *bs, uint64_t offset,
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes an L1 entry to disk (note that depending on the alignment
|
||||
* requirements this function may write more that just one entry in
|
||||
* order to prevent bdrv_pwrite from performing a read-modify-write)
|
||||
* Writes one sector of the L1 table to the disk (can't update single entries
|
||||
* and we really don't want bdrv_pread to perform a read-modify-write)
|
||||
*/
|
||||
#define L1_ENTRIES_PER_SECTOR (512 / 8)
|
||||
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint64_t buf[L1_ENTRIES_PER_SECTOR] = { 0 };
|
||||
int l1_start_index;
|
||||
int i, ret;
|
||||
int bufsize = MAX(sizeof(uint64_t),
|
||||
MIN(bs->file->bs->bl.request_alignment, s->cluster_size));
|
||||
int nentries = bufsize / sizeof(uint64_t);
|
||||
g_autofree uint64_t *buf = g_try_new0(uint64_t, nentries);
|
||||
|
||||
if (buf == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
l1_start_index = QEMU_ALIGN_DOWN(l1_index, nentries);
|
||||
for (i = 0; i < MIN(nentries, s->l1_size - l1_start_index); i++) {
|
||||
l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
|
||||
for (i = 0; i < L1_ENTRIES_PER_SECTOR && l1_start_index + i < s->l1_size;
|
||||
i++)
|
||||
{
|
||||
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
|
||||
}
|
||||
|
||||
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1,
|
||||
s->l1_table_offset + 8 * l1_start_index, bufsize, false);
|
||||
s->l1_table_offset + 8 * l1_start_index, sizeof(buf), false);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -248,7 +244,7 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
|
||||
ret = bdrv_pwrite_sync(bs->file,
|
||||
s->l1_table_offset + 8 * l1_start_index,
|
||||
buf, bufsize);
|
||||
buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -781,10 +777,6 @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
(cluster_offset + compressed_size - 1) / QCOW2_COMPRESSED_SECTOR_SIZE -
|
||||
(cluster_offset / QCOW2_COMPRESSED_SECTOR_SIZE);
|
||||
|
||||
/* The offset and size must fit in their fields of the L2 table entry */
|
||||
assert((cluster_offset & s->cluster_offset_mask) == cluster_offset);
|
||||
assert((nb_csectors & s->csize_mask) == nb_csectors);
|
||||
|
||||
cluster_offset |= QCOW_OFLAG_COMPRESSED |
|
||||
((uint64_t)nb_csectors << s->csize_shift);
|
||||
|
||||
@@ -980,7 +972,6 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
|
||||
|
||||
assert(l2_index + m->nb_clusters <= s->l2_slice_size);
|
||||
for (i = 0; i < m->nb_clusters; i++) {
|
||||
uint64_t offset = cluster_offset + (i << s->cluster_bits);
|
||||
/* if two concurrent writes happen to the same unallocated cluster
|
||||
* each write allocates separate cluster and writes data concurrently.
|
||||
* The first one to complete updates l2 table with pointer to its
|
||||
@@ -991,10 +982,8 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
|
||||
old_cluster[j++] = l2_slice[l2_index + i];
|
||||
}
|
||||
|
||||
/* The offset must fit in the offset field of the L2 table entry */
|
||||
assert((offset & L2E_OFFSET_MASK) == offset);
|
||||
|
||||
l2_slice[l2_index + i] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
|
||||
l2_slice[l2_index + i] = cpu_to_be64((cluster_offset +
|
||||
(i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
|
||||
}
|
||||
|
||||
|
||||
@@ -1927,9 +1916,6 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* The offset must fit in the offset field */
|
||||
assert((offset & L2E_OFFSET_MASK) == offset);
|
||||
|
||||
if (l2_refcount > 1) {
|
||||
/* For shared L2 tables, set the refcount accordingly
|
||||
* (it is already 1 and needs to be l2_refcount) */
|
||||
|
||||
@@ -1263,7 +1263,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
* l1_table_offset when it is the current s->l1_table_offset! Be careful
|
||||
* when changing this! */
|
||||
if (l1_table_offset != s->l1_table_offset) {
|
||||
l1_table = g_try_malloc0(l1_size2);
|
||||
l1_table = g_try_malloc0(ROUND_UP(l1_size2, 512));
|
||||
if (l1_size2 && l1_table == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
|
||||
@@ -1024,7 +1024,8 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
|
||||
return ret;
|
||||
}
|
||||
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
|
||||
new_l1_table = qemu_try_blockalign(bs->file->bs, new_l1_bytes);
|
||||
new_l1_table = qemu_try_blockalign(bs->file->bs,
|
||||
ROUND_UP(new_l1_bytes, 512));
|
||||
if (new_l1_table == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -248,15 +248,12 @@ qcow2_co_encdec(BlockDriverState *bs, uint64_t host_offset,
|
||||
.len = len,
|
||||
.func = func,
|
||||
};
|
||||
uint64_t sector_size;
|
||||
|
||||
assert(QEMU_IS_ALIGNED(guest_offset, BDRV_SECTOR_SIZE));
|
||||
assert(QEMU_IS_ALIGNED(host_offset, BDRV_SECTOR_SIZE));
|
||||
assert(QEMU_IS_ALIGNED(len, BDRV_SECTOR_SIZE));
|
||||
assert(s->crypto);
|
||||
|
||||
sector_size = qcrypto_block_get_sector_size(s->crypto);
|
||||
assert(QEMU_IS_ALIGNED(guest_offset, sector_size));
|
||||
assert(QEMU_IS_ALIGNED(host_offset, sector_size));
|
||||
assert(QEMU_IS_ALIGNED(len, sector_size));
|
||||
|
||||
return len == 0 ? 0 : qcow2_co_process(bs, qcow2_encdec_pool_func, &arg);
|
||||
}
|
||||
|
||||
@@ -275,8 +272,7 @@ qcow2_co_encdec(BlockDriverState *bs, uint64_t host_offset,
|
||||
* will be written to the underlying storage device at
|
||||
* @host_offset
|
||||
*
|
||||
* @len - length of the buffer (must be a multiple of the encryption
|
||||
* sector size)
|
||||
* @len - length of the buffer (must be a BDRV_SECTOR_SIZE multiple)
|
||||
*
|
||||
* Depending on the encryption method, @host_offset and/or @guest_offset
|
||||
* may be used for generating the initialization vector for
|
||||
|
||||
+132
-166
@@ -135,16 +135,13 @@ static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen,
|
||||
s->crypto_header.length = headerlen;
|
||||
s->crypto_header.offset = ret;
|
||||
|
||||
/*
|
||||
* Zero fill all space in cluster so it has predictable
|
||||
* content, as we may not initialize some regions of the
|
||||
* header (eg only 1 out of 8 key slots will be initialized)
|
||||
*/
|
||||
/* Zero fill remaining space in cluster so it has predictable
|
||||
* content in case of future spec changes */
|
||||
clusterlen = size_to_clusters(s, headerlen) * s->cluster_size;
|
||||
assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen, false) == 0);
|
||||
ret = bdrv_pwrite_zeroes(bs->file,
|
||||
ret,
|
||||
clusterlen, 0);
|
||||
ret + headerlen,
|
||||
clusterlen - headerlen, 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not zero fill encryption header");
|
||||
return -1;
|
||||
@@ -177,7 +174,7 @@ static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* read qcow2 extension and fill bs
|
||||
* start reading from start_offset
|
||||
* finish reading upon magic of value 0 or when end_offset reached
|
||||
@@ -370,7 +367,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (offset_into_cluster(s, bitmaps_ext.bitmap_directory_offset)) {
|
||||
if (bitmaps_ext.bitmap_directory_offset & (s->cluster_size - 1)) {
|
||||
error_setg(errp, "bitmaps_ext: "
|
||||
"invalid bitmap directory offset");
|
||||
return -EINVAL;
|
||||
@@ -456,15 +453,16 @@ static void cleanup_unknown_header_ext(BlockDriverState *bs)
|
||||
static void report_unsupported_feature(Error **errp, Qcow2Feature *table,
|
||||
uint64_t mask)
|
||||
{
|
||||
g_autoptr(GString) features = g_string_sized_new(60);
|
||||
char *features = g_strdup("");
|
||||
char *old;
|
||||
|
||||
while (table && table->name[0] != '\0') {
|
||||
if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) {
|
||||
if (mask & (1ULL << table->bit)) {
|
||||
if (features->len > 0) {
|
||||
g_string_append(features, ", ");
|
||||
}
|
||||
g_string_append_printf(features, "%.46s", table->name);
|
||||
old = features;
|
||||
features = g_strdup_printf("%s%s%.46s", old, *old ? ", " : "",
|
||||
table->name);
|
||||
g_free(old);
|
||||
mask &= ~(1ULL << table->bit);
|
||||
}
|
||||
}
|
||||
@@ -472,14 +470,14 @@ static void report_unsupported_feature(Error **errp, Qcow2Feature *table,
|
||||
}
|
||||
|
||||
if (mask) {
|
||||
if (features->len > 0) {
|
||||
g_string_append(features, ", ");
|
||||
}
|
||||
g_string_append_printf(features,
|
||||
"Unknown incompatible feature: %" PRIx64, mask);
|
||||
old = features;
|
||||
features = g_strdup_printf("%s%sUnknown incompatible feature: %" PRIx64,
|
||||
old, *old ? ", " : "", mask);
|
||||
g_free(old);
|
||||
}
|
||||
|
||||
error_setg(errp, "Unsupported qcow2 feature(s): %s", features->str);
|
||||
error_setg(errp, "Unsupported qcow2 feature(s): %s", features);
|
||||
g_free(features);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1494,7 +1492,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
|
||||
|
||||
if (s->l1_size > 0) {
|
||||
s->l1_table = qemu_try_blockalign(bs->file->bs,
|
||||
s->l1_size * sizeof(uint64_t));
|
||||
ROUND_UP(s->l1_size * sizeof(uint64_t), 512));
|
||||
if (s->l1_table == NULL) {
|
||||
error_setg(errp, "Could not allocate L1 table");
|
||||
ret = -ENOMEM;
|
||||
@@ -1707,14 +1705,14 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
|
||||
if (!(bdrv_get_flags(bs) & BDRV_O_INACTIVE)) {
|
||||
/* It's case 1, 2 or 3.2. Or 3.1 which is BUG in management layer. */
|
||||
bool header_updated = qcow2_load_dirty_bitmaps(bs, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
update_header = update_header && !header_updated;
|
||||
}
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (update_header) {
|
||||
ret = qcow2_update_header(bs);
|
||||
@@ -1724,8 +1722,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
|
||||
}
|
||||
}
|
||||
|
||||
bs->supported_zero_flags = header.version >= 3 ?
|
||||
BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0;
|
||||
bs->supported_zero_flags = header.version >= 3 ? BDRV_REQ_MAY_UNMAP : 0;
|
||||
|
||||
/* Repair image if dirty */
|
||||
if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
|
||||
@@ -1758,7 +1755,6 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
|
||||
g_free(s->image_data_file);
|
||||
if (has_data_file(bs)) {
|
||||
bdrv_unref_child(bs, s->data_file);
|
||||
s->data_file = NULL;
|
||||
}
|
||||
g_free(s->unknown_header_fields);
|
||||
cleanup_unknown_header_ext(bs);
|
||||
@@ -1885,11 +1881,6 @@ fail:
|
||||
static void qcow2_reopen_commit(BDRVReopenState *state)
|
||||
{
|
||||
qcow2_update_options_commit(state->bs, state->opaque);
|
||||
g_free(state->opaque);
|
||||
}
|
||||
|
||||
static void qcow2_reopen_commit_post(BDRVReopenState *state)
|
||||
{
|
||||
if (state->flags & BDRV_O_RDWR) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
@@ -1904,6 +1895,7 @@ static void qcow2_reopen_commit_post(BDRVReopenState *state)
|
||||
bdrv_get_node_name(state->bs));
|
||||
}
|
||||
}
|
||||
g_free(state->opaque);
|
||||
}
|
||||
|
||||
static void qcow2_reopen_abort(BDRVReopenState *state)
|
||||
@@ -1966,8 +1958,9 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint64_t cluster_offset;
|
||||
int index_in_cluster, ret;
|
||||
unsigned int bytes;
|
||||
int ret, status = 0;
|
||||
int status = 0;
|
||||
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
|
||||
@@ -1988,7 +1981,8 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
|
||||
|
||||
if ((ret == QCOW2_CLUSTER_NORMAL || ret == QCOW2_CLUSTER_ZERO_ALLOC) &&
|
||||
!s->crypto) {
|
||||
*map = cluster_offset | offset_into_cluster(s, offset);
|
||||
index_in_cluster = offset & (s->cluster_size - 1);
|
||||
*map = cluster_offset | index_in_cluster;
|
||||
*file = s->data_file->bs;
|
||||
status |= BDRV_BLOCK_OFFSET_VALID;
|
||||
}
|
||||
@@ -2076,6 +2070,8 @@ qcow2_co_preadv_encrypted(BlockDriverState *bs,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
|
||||
assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE));
|
||||
if (qcow2_co_decrypt(bs,
|
||||
file_cluster_offset + offset_into_cluster(s, offset),
|
||||
offset, buf, bytes) < 0)
|
||||
@@ -2173,7 +2169,10 @@ static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
|
||||
offset, bytes, qiov, qiov_offset);
|
||||
|
||||
case QCOW2_CLUSTER_NORMAL:
|
||||
assert(offset_into_cluster(s, file_cluster_offset) == 0);
|
||||
if ((file_cluster_offset & 511) != 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (bs->encrypted) {
|
||||
return qcow2_co_preadv_encrypted(bs, file_cluster_offset,
|
||||
offset, bytes, qiov, qiov_offset);
|
||||
@@ -2509,7 +2508,7 @@ static coroutine_fn int qcow2_co_pwritev_part(
|
||||
goto out_locked;
|
||||
}
|
||||
|
||||
assert(offset_into_cluster(s, cluster_offset) == 0);
|
||||
assert((cluster_offset & 511) == 0);
|
||||
|
||||
ret = qcow2_pre_write_overlap_check(bs, 0,
|
||||
cluster_offset + offset_in_cluster,
|
||||
@@ -2611,7 +2610,6 @@ static void qcow2_close(BlockDriverState *bs)
|
||||
|
||||
qcrypto_block_free(s->crypto);
|
||||
s->crypto = NULL;
|
||||
qapi_free_QCryptoBlockOpenOptions(s->crypto_opts);
|
||||
|
||||
g_free(s->unknown_header_fields);
|
||||
cleanup_unknown_header_ext(bs);
|
||||
@@ -2622,7 +2620,6 @@ static void qcow2_close(BlockDriverState *bs)
|
||||
|
||||
if (has_data_file(bs)) {
|
||||
bdrv_unref_child(bs, s->data_file);
|
||||
s->data_file = NULL;
|
||||
}
|
||||
|
||||
qcow2_refcount_close(bs);
|
||||
@@ -2823,15 +2820,8 @@ int qcow2_update_header(BlockDriverState *bs)
|
||||
buflen -= ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Feature table. A mere 8 feature names occupies 392 bytes, and
|
||||
* when coupled with the v3 minimum header of 104 bytes plus the
|
||||
* 8-byte end-of-extension marker, that would leave only 8 bytes
|
||||
* for a backing file name in an image with 512-byte clusters.
|
||||
* Thus, we choose to omit this header for cluster sizes 4k and
|
||||
* smaller.
|
||||
*/
|
||||
if (s->qcow_version >= 3 && s->cluster_size > 4096) {
|
||||
/* Feature table */
|
||||
if (s->qcow_version >= 3) {
|
||||
static const Qcow2Feature features[] = {
|
||||
{
|
||||
.type = QCOW2_FEAT_TYPE_INCOMPATIBLE,
|
||||
@@ -3272,7 +3262,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
|
||||
* inconsistency later.
|
||||
*
|
||||
* We do need a refcount table because growing the refcount table means
|
||||
* allocating two new refcount blocks - the second of which would be at
|
||||
* allocating two new refcount blocks - the seconds of which would be at
|
||||
* 2 GB for 64k clusters, and we don't want to have a 2 GB initial file
|
||||
* size for any qcow2 image.
|
||||
*/
|
||||
@@ -3297,8 +3287,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
|
||||
|
||||
/* Validate options and set default values */
|
||||
if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) {
|
||||
error_setg(errp, "Image size must be a multiple of %u bytes",
|
||||
(unsigned) BDRV_SECTOR_SIZE);
|
||||
error_setg(errp, "Image size must be a multiple of 512 bytes");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -3517,7 +3506,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Want a backing file? There you go. */
|
||||
/* Want a backing file? There you go.*/
|
||||
if (qcow2_opts->has_backing_file) {
|
||||
const char *backing_format = NULL;
|
||||
|
||||
@@ -3575,9 +3564,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv,
|
||||
const char *filename,
|
||||
QemuOpts *opts,
|
||||
static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
BlockdevCreateOptions *create_options = NULL;
|
||||
@@ -3784,12 +3771,6 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
|
||||
int ret;
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
|
||||
/* If the image does not support QCOW_OFLAG_ZERO then discarding
|
||||
* clusters could expose stale data from the backing file. */
|
||||
if (s->qcow_version < 3 && bs->backing) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (!QEMU_IS_ALIGNED(offset | bytes, s->cluster_size)) {
|
||||
assert(bytes < s->cluster_size);
|
||||
/* Ignore partial clusters, except for the special case of the
|
||||
@@ -3862,6 +3843,10 @@ qcow2_co_copy_range_from(BlockDriverState *bs,
|
||||
case QCOW2_CLUSTER_NORMAL:
|
||||
child = s->data_file;
|
||||
copy_offset += offset_into_cluster(s, src_offset);
|
||||
if ((copy_offset & 511) != 0) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -3923,7 +3908,7 @@ qcow2_co_copy_range_to(BlockDriverState *bs,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
assert(offset_into_cluster(s, cluster_offset) == 0);
|
||||
assert((cluster_offset & 511) == 0);
|
||||
|
||||
ret = qcow2_pre_write_overlap_check(bs, 0,
|
||||
cluster_offset + offset_in_cluster, cur_bytes, true);
|
||||
@@ -3980,9 +3965,8 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) {
|
||||
error_setg(errp, "The new size must be a multiple of %u",
|
||||
(unsigned) BDRV_SECTOR_SIZE);
|
||||
if (offset & 511) {
|
||||
error_setg(errp, "The new size must be a multiple of 512");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -4248,8 +4232,10 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* XXX: put compressed sectors first, then all the cluster aligned
|
||||
tables to avoid losing bytes in alignment */
|
||||
static coroutine_fn int
|
||||
qcow2_co_pwritev_compressed_task(BlockDriverState *bs,
|
||||
qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset)
|
||||
{
|
||||
@@ -4259,11 +4245,32 @@ qcow2_co_pwritev_compressed_task(BlockDriverState *bs,
|
||||
uint8_t *buf, *out_buf;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
assert(bytes == s->cluster_size || (bytes < s->cluster_size &&
|
||||
(offset + bytes == bs->total_sectors << BDRV_SECTOR_BITS)));
|
||||
if (has_data_file(bs)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (bytes == 0) {
|
||||
/* align end of file to a sector boundary to ease reading with
|
||||
sector based I/Os */
|
||||
int64_t len = bdrv_getlength(bs->file->bs);
|
||||
if (len < 0) {
|
||||
return len;
|
||||
}
|
||||
return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
|
||||
}
|
||||
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buf = qemu_blockalign(bs, s->cluster_size);
|
||||
if (bytes < s->cluster_size) {
|
||||
if (bytes != s->cluster_size) {
|
||||
if (bytes > s->cluster_size ||
|
||||
offset + bytes != bs->total_sectors << BDRV_SECTOR_BITS)
|
||||
{
|
||||
qemu_vfree(buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Zero-pad last write if image size is not cluster aligned */
|
||||
memset(buf + bytes, 0, s->cluster_size - bytes);
|
||||
}
|
||||
@@ -4312,82 +4319,6 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static coroutine_fn int qcow2_co_pwritev_compressed_task_entry(AioTask *task)
|
||||
{
|
||||
Qcow2AioTask *t = container_of(task, Qcow2AioTask, task);
|
||||
|
||||
assert(!t->cluster_type && !t->l2meta);
|
||||
|
||||
return qcow2_co_pwritev_compressed_task(t->bs, t->offset, t->bytes, t->qiov,
|
||||
t->qiov_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: put compressed sectors first, then all the cluster aligned
|
||||
* tables to avoid losing bytes in alignment
|
||||
*/
|
||||
static coroutine_fn int
|
||||
qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
AioTaskPool *aio = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (has_data_file(bs)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (bytes == 0) {
|
||||
/*
|
||||
* align end of file to a sector boundary to ease reading with
|
||||
* sector based I/Os
|
||||
*/
|
||||
int64_t len = bdrv_getlength(bs->file->bs);
|
||||
if (len < 0) {
|
||||
return len;
|
||||
}
|
||||
return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
|
||||
}
|
||||
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (offset_into_cluster(s, bytes) &&
|
||||
(offset + bytes) != (bs->total_sectors << BDRV_SECTOR_BITS)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while (bytes && aio_task_pool_status(aio) == 0) {
|
||||
uint64_t chunk_size = MIN(bytes, s->cluster_size);
|
||||
|
||||
if (!aio && chunk_size != bytes) {
|
||||
aio = aio_task_pool_new(QCOW2_MAX_WORKERS);
|
||||
}
|
||||
|
||||
ret = qcow2_add_task(bs, aio, qcow2_co_pwritev_compressed_task_entry,
|
||||
0, 0, offset, chunk_size, qiov, qiov_offset, NULL);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
qiov_offset += chunk_size;
|
||||
offset += chunk_size;
|
||||
bytes -= chunk_size;
|
||||
}
|
||||
|
||||
if (aio) {
|
||||
aio_task_pool_wait_all(aio);
|
||||
if (ret == 0) {
|
||||
ret = aio_task_pool_status(aio);
|
||||
}
|
||||
g_free(aio);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
qcow2_co_preadv_compressed(BlockDriverState *bs,
|
||||
uint64_t file_cluster_offset,
|
||||
@@ -4641,6 +4572,60 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t qcow2_measure_crypto_hdr_init_func(QCryptoBlock *block,
|
||||
size_t headerlen, void *opaque, Error **errp)
|
||||
{
|
||||
size_t *headerlenp = opaque;
|
||||
|
||||
/* Stash away the payload size */
|
||||
*headerlenp = headerlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t qcow2_measure_crypto_hdr_write_func(QCryptoBlock *block,
|
||||
size_t offset, const uint8_t *buf, size_t buflen,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
/* Discard the bytes, we're not actually writing to an image */
|
||||
return buflen;
|
||||
}
|
||||
|
||||
/* Determine the number of bytes for the LUKS payload */
|
||||
static bool qcow2_measure_luks_headerlen(QemuOpts *opts, size_t *len,
|
||||
Error **errp)
|
||||
{
|
||||
QDict *opts_qdict;
|
||||
QDict *cryptoopts_qdict;
|
||||
QCryptoBlockCreateOptions *cryptoopts;
|
||||
QCryptoBlock *crypto;
|
||||
|
||||
/* Extract "encrypt." options into a qdict */
|
||||
opts_qdict = qemu_opts_to_qdict(opts, NULL);
|
||||
qdict_extract_subqdict(opts_qdict, &cryptoopts_qdict, "encrypt.");
|
||||
qobject_unref(opts_qdict);
|
||||
|
||||
/* Build QCryptoBlockCreateOptions object from qdict */
|
||||
qdict_put_str(cryptoopts_qdict, "format", "luks");
|
||||
cryptoopts = block_crypto_create_opts_init(cryptoopts_qdict, errp);
|
||||
qobject_unref(cryptoopts_qdict);
|
||||
if (!cryptoopts) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Fake LUKS creation in order to determine the payload size */
|
||||
crypto = qcrypto_block_create(cryptoopts, "encrypt.",
|
||||
qcow2_measure_crypto_hdr_init_func,
|
||||
qcow2_measure_crypto_hdr_write_func,
|
||||
len, errp);
|
||||
qapi_free_QCryptoBlockCreateOptions(cryptoopts);
|
||||
if (!crypto) {
|
||||
return false;
|
||||
}
|
||||
|
||||
qcrypto_block_free(crypto);
|
||||
return true;
|
||||
}
|
||||
|
||||
static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -4691,27 +4676,9 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
|
||||
g_free(optstr);
|
||||
|
||||
if (has_luks) {
|
||||
g_autoptr(QCryptoBlockCreateOptions) create_opts = NULL;
|
||||
QDict *opts_qdict;
|
||||
QDict *cryptoopts;
|
||||
size_t headerlen;
|
||||
|
||||
opts_qdict = qemu_opts_to_qdict(opts, NULL);
|
||||
qdict_extract_subqdict(opts_qdict, &cryptoopts, "encrypt.");
|
||||
qobject_unref(opts_qdict);
|
||||
|
||||
qdict_put_str(cryptoopts, "format", "luks");
|
||||
|
||||
create_opts = block_crypto_create_opts_init(cryptoopts, errp);
|
||||
qobject_unref(cryptoopts);
|
||||
if (!create_opts) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!qcrypto_block_calculate_payload_offset(create_opts,
|
||||
"encrypt.",
|
||||
&headerlen,
|
||||
&local_err)) {
|
||||
if (!qcow2_measure_luks_headerlen(opts, &headerlen, &local_err)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -5536,7 +5503,6 @@ BlockDriver bdrv_qcow2 = {
|
||||
.bdrv_close = qcow2_close,
|
||||
.bdrv_reopen_prepare = qcow2_reopen_prepare,
|
||||
.bdrv_reopen_commit = qcow2_reopen_commit,
|
||||
.bdrv_reopen_commit_post = qcow2_reopen_commit_post,
|
||||
.bdrv_reopen_abort = qcow2_reopen_abort,
|
||||
.bdrv_join_options = qcow2_join_options,
|
||||
.bdrv_child_perm = bdrv_format_default_perms,
|
||||
|
||||
@@ -301,6 +301,9 @@ typedef struct BDRVQcow2State {
|
||||
QEMUTimer *cache_clean_timer;
|
||||
unsigned cache_clean_interval;
|
||||
|
||||
uint8_t *cluster_cache;
|
||||
uint8_t *cluster_data;
|
||||
uint64_t cluster_cache_offset;
|
||||
QLIST_HEAD(, QCowL2Meta) cluster_allocs;
|
||||
|
||||
uint64_t *refcount_table;
|
||||
|
||||
+1
-2
@@ -720,8 +720,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn bdrv_qed_co_create_opts(BlockDriver *drv,
|
||||
const char *filename,
|
||||
static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
|
||||
QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
|
||||
+9
-61
@@ -796,53 +796,17 @@ static coroutine_fn int quorum_co_flush(BlockDriverState *bs)
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool quorum_recurse_can_replace(BlockDriverState *bs,
|
||||
BlockDriverState *to_replace)
|
||||
static bool quorum_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
/*
|
||||
* We have no idea whether our children show the same data as
|
||||
* this node (@bs). It is actually highly likely that
|
||||
* @to_replace does not, because replacing a broken child is
|
||||
* one of the main use cases here.
|
||||
*
|
||||
* We do know that the new BDS will match @bs, so replacing
|
||||
* any of our children by it will be safe. It cannot change
|
||||
* the data this quorum node presents to its parents.
|
||||
*
|
||||
* However, replacing @to_replace by @bs in any of our
|
||||
* children's chains may change visible data somewhere in
|
||||
* there. We therefore cannot recurse down those chains with
|
||||
* bdrv_recurse_can_replace().
|
||||
* (More formally, bdrv_recurse_can_replace() requires that
|
||||
* @to_replace will be replaced by something matching the @bs
|
||||
* passed to it. We cannot guarantee that.)
|
||||
*
|
||||
* Thus, we can only check whether any of our immediate
|
||||
* children matches @to_replace.
|
||||
*
|
||||
* (In the future, we might add a function to recurse down a
|
||||
* chain that checks that nothing there cares about a change
|
||||
* in data from the respective child in question. For
|
||||
* example, most filters do not care when their child's data
|
||||
* suddenly changes, as long as their parents do not care.)
|
||||
*/
|
||||
if (s->children[i]->bs == to_replace) {
|
||||
/*
|
||||
* We now have to ensure that there is no other parent
|
||||
* that cares about replacing this child by a node with
|
||||
* potentially different data.
|
||||
* We do so by checking whether there are any other parents
|
||||
* at all, which is stricter than necessary, but also very
|
||||
* simple. (We may decide to implement something more
|
||||
* complex and permissive when there is an actual need for
|
||||
* it.)
|
||||
*/
|
||||
return QLIST_FIRST(&to_replace->parents) == s->children[i] &&
|
||||
QLIST_NEXT(s->children[i], next_parent) == NULL;
|
||||
bool perm = bdrv_recurse_is_first_non_filter(s->children[i]->bs,
|
||||
candidate);
|
||||
if (perm) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1150,23 +1114,6 @@ static char *quorum_dirname(BlockDriverState *bs, Error **errp)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void quorum_child_perm(BlockDriverState *bs, BdrvChild *c,
|
||||
const BdrvChildRole *role,
|
||||
BlockReopenQueue *reopen_queue,
|
||||
uint64_t perm, uint64_t shared,
|
||||
uint64_t *nperm, uint64_t *nshared)
|
||||
{
|
||||
*nperm = perm & DEFAULT_PERM_PASSTHROUGH;
|
||||
|
||||
/*
|
||||
* We cannot share RESIZE or WRITE, as this would make the
|
||||
* children differ from each other.
|
||||
*/
|
||||
*nshared = (shared & (BLK_PERM_CONSISTENT_READ |
|
||||
BLK_PERM_WRITE_UNCHANGED))
|
||||
| DEFAULT_PERM_UNCHANGED;
|
||||
}
|
||||
|
||||
static const char *const quorum_strong_runtime_opts[] = {
|
||||
QUORUM_OPT_VOTE_THRESHOLD,
|
||||
QUORUM_OPT_BLKVERIFY,
|
||||
@@ -1196,9 +1143,10 @@ static BlockDriver bdrv_quorum = {
|
||||
.bdrv_add_child = quorum_add_child,
|
||||
.bdrv_del_child = quorum_del_child,
|
||||
|
||||
.bdrv_child_perm = quorum_child_perm,
|
||||
.bdrv_child_perm = bdrv_filter_default_perms,
|
||||
|
||||
.bdrv_recurse_can_replace = quorum_recurse_can_replace,
|
||||
.is_filter = true,
|
||||
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
|
||||
|
||||
.strong_runtime_opts = quorum_strong_runtime_opts,
|
||||
};
|
||||
|
||||
+1
-3
@@ -419,9 +419,7 @@ static int raw_has_zero_init_truncate(BlockDriverState *bs)
|
||||
return bdrv_has_zero_init_truncate(bs->file->bs);
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
|
||||
const char *filename,
|
||||
QemuOpts *opts,
|
||||
static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
return bdrv_create_file(filename, opts, errp);
|
||||
|
||||
+14
-33
@@ -104,7 +104,6 @@ typedef struct BDRVRBDState {
|
||||
rbd_image_t image;
|
||||
char *image_name;
|
||||
char *snap;
|
||||
char *namespace;
|
||||
uint64_t image_size;
|
||||
} BDRVRBDState;
|
||||
|
||||
@@ -153,7 +152,7 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
|
||||
const char *start;
|
||||
char *p, *buf;
|
||||
QList *keypairs = NULL;
|
||||
char *found_str, *image_name;
|
||||
char *found_str;
|
||||
|
||||
if (!strstart(filename, "rbd:", &start)) {
|
||||
error_setg(errp, "File name must start with 'rbd:'");
|
||||
@@ -172,24 +171,18 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
|
||||
qdict_put_str(options, "pool", found_str);
|
||||
|
||||
if (strchr(p, '@')) {
|
||||
image_name = qemu_rbd_next_tok(p, '@', &p);
|
||||
found_str = qemu_rbd_next_tok(p, '@', &p);
|
||||
qemu_rbd_unescape(found_str);
|
||||
qdict_put_str(options, "image", found_str);
|
||||
|
||||
found_str = qemu_rbd_next_tok(p, ':', &p);
|
||||
qemu_rbd_unescape(found_str);
|
||||
qdict_put_str(options, "snapshot", found_str);
|
||||
} else {
|
||||
image_name = qemu_rbd_next_tok(p, ':', &p);
|
||||
}
|
||||
/* Check for namespace in the image_name */
|
||||
if (strchr(image_name, '/')) {
|
||||
found_str = qemu_rbd_next_tok(image_name, '/', &image_name);
|
||||
found_str = qemu_rbd_next_tok(p, ':', &p);
|
||||
qemu_rbd_unescape(found_str);
|
||||
qdict_put_str(options, "namespace", found_str);
|
||||
} else {
|
||||
qdict_put_str(options, "namespace", "");
|
||||
qdict_put_str(options, "image", found_str);
|
||||
}
|
||||
qemu_rbd_unescape(image_name);
|
||||
qdict_put_str(options, "image", image_name);
|
||||
if (!p) {
|
||||
goto done;
|
||||
}
|
||||
@@ -350,11 +343,6 @@ static QemuOptsList runtime_opts = {
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Rados pool name",
|
||||
},
|
||||
{
|
||||
.name = "namespace",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Rados namespace name in the pool",
|
||||
},
|
||||
{
|
||||
.name = "image",
|
||||
.type = QEMU_OPT_STRING,
|
||||
@@ -437,8 +425,7 @@ static int qemu_rbd_co_create(BlockdevCreateOptions *options, Error **errp)
|
||||
return qemu_rbd_do_create(options, NULL, NULL, errp);
|
||||
}
|
||||
|
||||
static int coroutine_fn qemu_rbd_co_create_opts(BlockDriver *drv,
|
||||
const char *filename,
|
||||
static int coroutine_fn qemu_rbd_co_create_opts(const char *filename,
|
||||
QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -480,14 +467,13 @@ static int coroutine_fn qemu_rbd_co_create_opts(BlockDriver *drv,
|
||||
* schema, but when they come from -drive, they're all QString.
|
||||
*/
|
||||
loc = rbd_opts->location;
|
||||
loc->pool = g_strdup(qdict_get_try_str(options, "pool"));
|
||||
loc->conf = g_strdup(qdict_get_try_str(options, "conf"));
|
||||
loc->has_conf = !!loc->conf;
|
||||
loc->user = g_strdup(qdict_get_try_str(options, "user"));
|
||||
loc->has_user = !!loc->user;
|
||||
loc->q_namespace = g_strdup(qdict_get_try_str(options, "namespace"));
|
||||
loc->image = g_strdup(qdict_get_try_str(options, "image"));
|
||||
keypairs = qdict_get_try_str(options, "=keyvalue-pairs");
|
||||
loc->pool = g_strdup(qdict_get_try_str(options, "pool"));
|
||||
loc->conf = g_strdup(qdict_get_try_str(options, "conf"));
|
||||
loc->has_conf = !!loc->conf;
|
||||
loc->user = g_strdup(qdict_get_try_str(options, "user"));
|
||||
loc->has_user = !!loc->user;
|
||||
loc->image = g_strdup(qdict_get_try_str(options, "image"));
|
||||
keypairs = qdict_get_try_str(options, "=keyvalue-pairs");
|
||||
|
||||
ret = qemu_rbd_do_create(create_options, keypairs, password_secret, errp);
|
||||
if (ret < 0) {
|
||||
@@ -662,11 +648,6 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
|
||||
error_setg_errno(errp, -r, "error opening pool %s", opts->pool);
|
||||
goto failed_shutdown;
|
||||
}
|
||||
/*
|
||||
* Set the namespace after opening the io context on the pool,
|
||||
* if nspace == NULL or if nspace == "", it is just as we did nothing
|
||||
*/
|
||||
rados_ioctx_set_namespace(*io_ctx, opts->q_namespace);
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
+9
-38
@@ -144,15 +144,12 @@ fail:
|
||||
static void replication_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVReplicationState *s = bs->opaque;
|
||||
Job *commit_job;
|
||||
|
||||
if (s->stage == BLOCK_REPLICATION_RUNNING) {
|
||||
replication_stop(s->rs, false, NULL);
|
||||
}
|
||||
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);
|
||||
job_cancel_sync(&s->commit_job->job);
|
||||
}
|
||||
|
||||
if (s->mode == REPLICATION_MODE_SECONDARY) {
|
||||
@@ -309,6 +306,12 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool replication_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate)
|
||||
{
|
||||
return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
|
||||
}
|
||||
|
||||
static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
@@ -453,17 +456,6 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
||||
aio_context_acquire(aio_context);
|
||||
s = bs->opaque;
|
||||
|
||||
if (s->stage == BLOCK_REPLICATION_DONE ||
|
||||
s->stage == BLOCK_REPLICATION_FAILOVER) {
|
||||
/*
|
||||
* This case happens when a secondary is promoted to primary.
|
||||
* Ignore the request because the secondary side of replication
|
||||
* doesn't have to do anything anymore.
|
||||
*/
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->stage != BLOCK_REPLICATION_NONE) {
|
||||
error_setg(errp, "Block replication is running or done");
|
||||
aio_context_release(aio_context);
|
||||
@@ -588,17 +580,6 @@ static void replication_do_checkpoint(ReplicationState *rs, Error **errp)
|
||||
aio_context_acquire(aio_context);
|
||||
s = bs->opaque;
|
||||
|
||||
if (s->stage == BLOCK_REPLICATION_DONE ||
|
||||
s->stage == BLOCK_REPLICATION_FAILOVER) {
|
||||
/*
|
||||
* This case happens when a secondary was promoted to primary.
|
||||
* Ignore the request because the secondary side of replication
|
||||
* doesn't have to do anything anymore.
|
||||
*/
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->mode == REPLICATION_MODE_SECONDARY) {
|
||||
secondary_do_checkpoint(s, errp);
|
||||
}
|
||||
@@ -615,7 +596,7 @@ static void replication_get_error(ReplicationState *rs, Error **errp)
|
||||
aio_context_acquire(aio_context);
|
||||
s = bs->opaque;
|
||||
|
||||
if (s->stage == BLOCK_REPLICATION_NONE) {
|
||||
if (s->stage != BLOCK_REPLICATION_RUNNING) {
|
||||
error_setg(errp, "Block replication is not running");
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
@@ -657,17 +638,6 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
|
||||
aio_context_acquire(aio_context);
|
||||
s = bs->opaque;
|
||||
|
||||
if (s->stage == BLOCK_REPLICATION_DONE ||
|
||||
s->stage == BLOCK_REPLICATION_FAILOVER) {
|
||||
/*
|
||||
* This case happens when a secondary was promoted to primary.
|
||||
* Ignore the request because the secondary side of replication
|
||||
* doesn't have to do anything anymore.
|
||||
*/
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->stage != BLOCK_REPLICATION_RUNNING) {
|
||||
error_setg(errp, "Block replication is not running");
|
||||
aio_context_release(aio_context);
|
||||
@@ -729,6 +699,7 @@ static BlockDriver bdrv_replication = {
|
||||
.bdrv_co_writev = replication_co_writev,
|
||||
|
||||
.is_filter = true,
|
||||
.bdrv_recurse_is_first_non_filter = replication_recurse_is_first_non_filter,
|
||||
|
||||
.has_variable_length = true,
|
||||
.strong_runtime_opts = replication_strong_runtime_opts,
|
||||
|
||||
+1
-3
@@ -2157,9 +2157,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn sd_co_create_opts(BlockDriver *drv,
|
||||
const char *filename,
|
||||
QemuOpts *opts,
|
||||
static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
BlockdevCreateOptions *create_options = NULL;
|
||||
|
||||
Loaded 100 of 2542 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user