Compare commits
80 Commits
qemu-openb
...
v2.11.1
Author | SHA1 | Date | |
---|---|---|---|
|
7c1beb52ed | ||
|
00e9fba2be | ||
|
63112b16a6 | ||
|
30c3b4823c | ||
|
88ab85384d | ||
|
64653b7fbe | ||
|
9a26ca6b94 | ||
|
172f4e5a31 | ||
|
0c85a40e71 | ||
|
f9e53c77ea | ||
|
f9c8767828 | ||
|
5af9f2504f | ||
|
2e6571e671 | ||
|
126617e6f8 | ||
|
8a9c5c34ac | ||
|
616d64ac06 | ||
|
a7b2537f8a | ||
|
de1e7a91c8 | ||
|
0181686a98 | ||
|
a3fd64f2fe | ||
|
68d7e24475 | ||
|
2095c5a2e3 | ||
|
c8847f5565 | ||
|
b9eec804f4 | ||
|
b8aa511bc0 | ||
|
ab7b4f6734 | ||
|
ed8b4ecc68 | ||
|
eab4b5170f | ||
|
d7aa3d0a0a | ||
|
3dc12273b7 | ||
|
e9a8747cd2 | ||
|
49b1fa33a3 | ||
|
43a29f0025 | ||
|
d72e0a69ea | ||
|
4374cbca95 | ||
|
a1f33a5b93 | ||
|
6a47136799 | ||
|
e4f4fa00eb | ||
|
ff6f7e10c6 | ||
|
7c578cbc37 | ||
|
804e5ea9ed | ||
|
9070f408f4 | ||
|
78a38cd47e | ||
|
0fac4aa930 | ||
|
97d17551b5 | ||
|
7e25155a7b | ||
|
80277d7cd5 | ||
|
50c6998c20 | ||
|
dccdaacc3d | ||
|
5683983e99 | ||
|
4d79c0e434 | ||
|
098132386d | ||
|
61c8e67a66 | ||
|
e7857ad997 | ||
|
9327a8e2d6 | ||
|
8ebfafa796 | ||
|
61efbbf869 | ||
|
1ade973f52 | ||
|
803d42fa65 | ||
|
cb2637a5ae | ||
|
4b220d88ba | ||
|
1027f3419b | ||
|
ccf82aee58 | ||
|
1e14820884 | ||
|
a22b8096b6 | ||
|
3f44190cb6 | ||
|
88bf4a70df | ||
|
f793121539 | ||
|
0af294d774 | ||
|
62425350b5 | ||
|
d6f1448277 | ||
|
7f53a81073 | ||
|
2b0c34cf61 | ||
|
057364da77 | ||
|
b9da3c1de7 | ||
|
c184e17c75 | ||
|
5ba945f1cb | ||
|
ea311a9959 | ||
|
fd89d93e85 | ||
|
817a9fcba8 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -53,8 +53,8 @@
|
||||
/qemu-version.h.tmp
|
||||
/module_block.h
|
||||
/scsi/qemu-pr-helper
|
||||
/vscclient
|
||||
/vhost-user-scsi
|
||||
/vhost-user-blk
|
||||
/fsdev/virtfs-proxy-helper
|
||||
*.tmp
|
||||
*.[1-9]
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -40,6 +40,3 @@
|
||||
[submodule "capstone"]
|
||||
path = capstone
|
||||
url = git://git.qemu.org/capstone.git
|
||||
[submodule "roms/seabios-hppa"]
|
||||
path = roms/seabios-hppa
|
||||
url = git://github.com/hdeller/seabios-hppa.git
|
||||
|
4
.mailmap
4
.mailmap
@@ -18,7 +18,3 @@ malc <av1474@comtv.ru> malc <malc@c046a42c-6fe2-441c-8c8c-71466251a162>
|
||||
# There is also a:
|
||||
# (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162>
|
||||
# for the cvs2svn initialization commit e63c3dc74bf.
|
||||
#
|
||||
# Also list preferred name forms where people have changed their
|
||||
# git author config
|
||||
Daniel P. Berrangé <berrange@redhat.com>
|
||||
|
23
.travis.yml
23
.travis.yml
@@ -1,7 +1,7 @@
|
||||
sudo: false
|
||||
language: c
|
||||
python:
|
||||
- "2.6"
|
||||
- "2.4"
|
||||
compiler:
|
||||
- gcc
|
||||
cache: ccache
|
||||
@@ -13,13 +13,12 @@ addons:
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-ng-dev
|
||||
- libgcc-4.8-dev
|
||||
- libgnutls-dev
|
||||
- libgtk-3-dev
|
||||
- libiscsi-dev
|
||||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libncurses5-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng12-dev
|
||||
@@ -52,9 +51,9 @@ env:
|
||||
- CONFIG=""
|
||||
- CONFIG="--enable-debug --enable-debug-tcg --enable-trace-backends=log"
|
||||
- CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-uuid --disable-libusb"
|
||||
- CONFIG="--enable-modules --disable-linux-user"
|
||||
- CONFIG="--with-coroutine=ucontext --disable-linux-user"
|
||||
- CONFIG="--with-coroutine=sigaltstack --disable-linux-user"
|
||||
- CONFIG="--enable-modules"
|
||||
- CONFIG="--with-coroutine=ucontext"
|
||||
- CONFIG="--with-coroutine=sigaltstack"
|
||||
git:
|
||||
# we want to do this ourselves
|
||||
submodules: false
|
||||
@@ -116,17 +115,15 @@ matrix:
|
||||
- sudo apt-get build-dep -qq qemu
|
||||
- wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
|
||||
- git submodule update --init --recursive
|
||||
# Trusty System build with latest stable clang & python 3.0
|
||||
# Trusty System build with latest stable clang
|
||||
- sudo: required
|
||||
addons:
|
||||
dist: trusty
|
||||
language: generic
|
||||
compiler: none
|
||||
python:
|
||||
- "3.0"
|
||||
env:
|
||||
- COMPILER_NAME=clang CXX=clang++-3.9 CC=clang-3.9
|
||||
- CONFIG="--disable-linux-user --cc=clang-3.9 --cxx=clang++-3.9 --python=/usr/bin/python3"
|
||||
- CONFIG="--disable-linux-user --cc=clang-3.9 --cxx=clang++-3.9"
|
||||
before_install:
|
||||
- wget -nv -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
- sudo apt-add-repository -y 'deb http://llvm.org/apt/trusty llvm-toolchain-trusty-3.9 main'
|
||||
@@ -137,17 +134,15 @@ matrix:
|
||||
- git submodule update --init --recursive
|
||||
before_script:
|
||||
- ./configure ${CONFIG} || cat config.log
|
||||
# Trusty Linux User build with latest stable clang & python 3.6
|
||||
# Trusty Linux User build with latest stable clang
|
||||
- sudo: required
|
||||
addons:
|
||||
dist: trusty
|
||||
language: generic
|
||||
compiler: none
|
||||
python:
|
||||
- "3.6"
|
||||
env:
|
||||
- COMPILER_NAME=clang CXX=clang++-3.9 CC=clang-3.9
|
||||
- CONFIG="--disable-system --cc=clang-3.9 --cxx=clang++-3.9 --python=/usr/bin/python3"
|
||||
- CONFIG="--disable-system --cc=clang-3.9 --cxx=clang++-3.9"
|
||||
before_install:
|
||||
- wget -nv -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
- sudo apt-add-repository -y 'deb http://llvm.org/apt/trusty llvm-toolchain-trusty-3.9 main'
|
||||
|
97
MAINTAINERS
97
MAINTAINERS
@@ -76,29 +76,6 @@ K: ^Subject:.*(?i)trivial
|
||||
T: git git://git.corpit.ru/qemu.git trivial-patches
|
||||
T: git git://github.com/vivier/qemu.git trivial-patches
|
||||
|
||||
Architecture support
|
||||
--------------------
|
||||
S390
|
||||
M: Cornelia Huck <cohuck@redhat.com>
|
||||
S: Supported
|
||||
F: default-configs/s390x-softmmu.mak
|
||||
F: gdb-xml/s390*.xml
|
||||
F: hw/char/sclp*.[hc]
|
||||
F: hw/char/terminal3270.c
|
||||
F: hw/intc/s390_flic.c
|
||||
F: hw/intc/s390_flic_kvm.c
|
||||
F: hw/s390x/
|
||||
F: hw/vfio/ccw.c
|
||||
F: hw/watchdog/wdt_diag288.c
|
||||
F: include/hw/s390x/
|
||||
F: include/hw/watchdog/wdt_diag288.h
|
||||
F: pc-bios/s390-ccw/
|
||||
F: pc-bios/s390-ccw.img
|
||||
F: target/s390x/
|
||||
K: ^Subject:.*(?i)s390x?
|
||||
T: git git://github.com/cohuck/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
Guest CPU cores (TCG):
|
||||
----------------------
|
||||
Overall
|
||||
@@ -156,7 +133,6 @@ HPPA (PA-RISC)
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
S: Maintained
|
||||
F: target/hppa/
|
||||
F: hw/hppa/
|
||||
F: disas/hppa.c
|
||||
|
||||
LM32
|
||||
@@ -236,7 +212,6 @@ F: disas/ppc.c
|
||||
S390
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
S: Maintained
|
||||
F: target/s390x/
|
||||
F: hw/s390x/
|
||||
@@ -284,7 +259,6 @@ S: Maintained
|
||||
F: target/xtensa/
|
||||
F: hw/xtensa/
|
||||
F: tests/tcg/xtensa/
|
||||
F: disas/xtensa.c
|
||||
|
||||
TriCore
|
||||
M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
|
||||
@@ -569,7 +543,7 @@ F: include/hw/*/xlnx*.h
|
||||
|
||||
ARM ACPI Subsystem
|
||||
M: Shannon Zhao <zhaoshenglong@huawei.com>
|
||||
M: Shannon Zhao <shannon.zhaosl@gmail.com>
|
||||
M: Shannon Zhao <shannon.zhao@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/virt-acpi-build.c
|
||||
@@ -758,11 +732,7 @@ F: hw/ppc/prep.c
|
||||
F: hw/ppc/prep_systemio.c
|
||||
F: hw/ppc/rs6000_mc.c
|
||||
F: hw/pci-host/prep.[hc]
|
||||
F: hw/isa/i82378.c
|
||||
F: hw/isa/pc87312.[hc]
|
||||
F: hw/dma/i82374.c
|
||||
F: hw/timer/m48t59-isa.c
|
||||
F: include/hw/timer/m48t59.h
|
||||
F: pc-bios/ppc_rom.bin
|
||||
|
||||
sPAPR
|
||||
@@ -791,12 +761,6 @@ L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/ppc/virtex_ml507.c
|
||||
|
||||
sam460ex
|
||||
M: BALATON Zoltan <balaton@eik.bme.hu>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/ide/sii3112.c
|
||||
|
||||
SH4 Machines
|
||||
------------
|
||||
R2D
|
||||
@@ -856,22 +820,15 @@ F: hw/char/sclp*.[hc]
|
||||
F: hw/char/terminal3270.c
|
||||
F: hw/s390x/
|
||||
F: include/hw/s390x/
|
||||
F: pc-bios/s390-ccw/
|
||||
F: hw/watchdog/wdt_diag288.c
|
||||
F: include/hw/watchdog/wdt_diag288.h
|
||||
F: pc-bios/s390-ccw.img
|
||||
F: default-configs/s390x-softmmu.mak
|
||||
T: git git://github.com/cohuck/qemu.git s390-next
|
||||
T: git git://github.com/borntraeger/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
S390-ccw Bios
|
||||
M: Christian Borntraeger <borntraeger@de.ibm.com>
|
||||
M: Thomas Huth <thuth@redhat.com>
|
||||
S: Supported
|
||||
F: pc-bios/s390-ccw/
|
||||
F: pc-bios/s390-ccw.img
|
||||
T: git git://github.com/borntraeger/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
UniCore32 Machines
|
||||
-------------
|
||||
PKUnity-3 SoC initramfs-with-busybox
|
||||
@@ -884,7 +841,6 @@ X86 Machines
|
||||
------------
|
||||
PC
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
M: Marcel Apfelbaum <marcel@redhat.com>
|
||||
S: Supported
|
||||
F: include/hw/i386/
|
||||
F: hw/i386/
|
||||
@@ -905,13 +861,12 @@ F: hw/misc/sga.c
|
||||
PC Chipset
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
S: Supported
|
||||
S: Support
|
||||
F: hw/char/debugcon.c
|
||||
F: hw/char/parallel.c
|
||||
F: hw/char/serial*
|
||||
F: hw/dma/i8257*
|
||||
F: hw/i2c/pm_smbus.c
|
||||
F: hw/input/pckbd.c
|
||||
F: hw/intc/apic*
|
||||
F: hw/intc/ioapic*
|
||||
F: hw/intc/i8259*
|
||||
@@ -920,10 +875,7 @@ F: hw/misc/pc-testdev.c
|
||||
F: hw/timer/hpet*
|
||||
F: hw/timer/i8254*
|
||||
F: hw/timer/mc146818rtc*
|
||||
F: hw/watchdog/wdt_ib700.c
|
||||
F: include/hw/display/vga.h
|
||||
F: include/hw/i2c/pm_smbus.h
|
||||
F: include/hw/isa/i8257.h
|
||||
F: include/hw/timer/hpet.h
|
||||
F: include/hw/timer/i8254*
|
||||
F: include/hw/timer/mc146818rtc*
|
||||
@@ -972,15 +924,6 @@ F: tests/ahci-test.c
|
||||
F: tests/libqos/ahci*
|
||||
T: git git://github.com/jnsnow/qemu.git ide
|
||||
|
||||
IPMI
|
||||
M: Corey Minyard <minyard@acm.org>
|
||||
S: Maintained
|
||||
F: include/hw/ipmi/*
|
||||
F: hw/ipmi/*
|
||||
F: hw/smbios/smbios_type_38.c
|
||||
F: tests/ipmi*
|
||||
T: git git://github.com/cminyard/qemu.git master-ipmi-rebase
|
||||
|
||||
Floppy
|
||||
M: John Snow <jsnow@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
@@ -1033,9 +976,7 @@ M: Alexander Graf <agraf@suse.de>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/ppc/ppc4*.c
|
||||
F: hw/i2c/ppc4xx_i2c.c
|
||||
F: include/hw/ppc/ppc4xx.h
|
||||
F: include/hw/i2c/ppc4xx_i2c.h
|
||||
|
||||
ppce500
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
@@ -1054,13 +995,11 @@ Network devices
|
||||
M: Jason Wang <jasowang@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: hw/net/
|
||||
F: include/hw/net/
|
||||
F: tests/virtio-net-test.c
|
||||
T: git git://github.com/jasowang/qemu.git net
|
||||
|
||||
SCSI
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
R: Fam Zheng <famz@redhat.com>
|
||||
S: Supported
|
||||
F: include/hw/scsi/*
|
||||
F: hw/scsi/*
|
||||
@@ -1132,11 +1071,13 @@ F: include/hw/virtio/
|
||||
F: tests/virtio-balloon-test.c
|
||||
|
||||
virtio-9p
|
||||
M: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
||||
M: Greg Kurz <groug@kaod.org>
|
||||
S: Supported
|
||||
F: hw/9pfs/
|
||||
F: fsdev/
|
||||
F: tests/virtio-9p-test.c
|
||||
T: git git://github.com/kvaneesh/QEMU.git
|
||||
T: git git://github.com/gkurz/qemu.git 9p-next
|
||||
|
||||
virtio-blk
|
||||
@@ -1204,7 +1145,7 @@ F: hw/scsi/mfi.h
|
||||
F: tests/megasas-test.c
|
||||
|
||||
Network packet abstractions
|
||||
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
|
||||
M: Dmitry Fleytman <dmitry@daynix.com>
|
||||
S: Maintained
|
||||
F: include/net/eth.h
|
||||
F: net/eth.c
|
||||
@@ -1212,7 +1153,7 @@ F: hw/net/net_rx_pkt*
|
||||
F: hw/net/net_tx_pkt*
|
||||
|
||||
Vmware
|
||||
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
|
||||
M: Dmitry Fleytman <dmitry@daynix.com>
|
||||
S: Maintained
|
||||
F: hw/net/vmxnet*
|
||||
F: hw/scsi/vmw_pvscsi*
|
||||
@@ -1233,12 +1174,12 @@ F: hw/mem/nvdimm.c
|
||||
F: include/hw/mem/nvdimm.h
|
||||
|
||||
e1000x
|
||||
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
|
||||
M: Dmitry Fleytman <dmitry@daynix.com>
|
||||
S: Maintained
|
||||
F: hw/net/e1000x*
|
||||
|
||||
e1000e
|
||||
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
|
||||
M: Dmitry Fleytman <dmitry@daynix.com>
|
||||
S: Maintained
|
||||
F: hw/net/e1000e*
|
||||
|
||||
@@ -1319,7 +1260,6 @@ T: git git://github.com/stefanha/qemu.git block
|
||||
|
||||
Block SCSI subsystem
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
R: Fam Zheng <famz@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: include/scsi/*
|
||||
@@ -1598,7 +1538,6 @@ M: Alistair Francis <alistair.francis@xilinx.com>
|
||||
S: Maintained
|
||||
F: hw/core/register.c
|
||||
F: include/hw/register.h
|
||||
F: include/hw/registerfields.h
|
||||
|
||||
SLIRP
|
||||
M: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||||
@@ -1633,7 +1572,6 @@ F: include/hw/acpi/tpm.h
|
||||
F: include/sysemu/tpm*
|
||||
F: qapi/tpm.json
|
||||
F: backends/tpm.c
|
||||
T: git git://github.com/stefanberger/qemu-tpm.git tpm-next
|
||||
|
||||
Checkpatch
|
||||
S: Odd Fixes
|
||||
@@ -1761,7 +1699,6 @@ R: Laurent Vivier <laurent@vivier.eu>
|
||||
S: Maintained
|
||||
F: linux-user/
|
||||
F: default-configs/*-linux-user.mak
|
||||
F: scripts/qemu-binfmt-conf.sh
|
||||
|
||||
Tiny Code Generator (TCG)
|
||||
-------------------------
|
||||
@@ -1920,12 +1857,6 @@ L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/null.c
|
||||
|
||||
NVMe Block Driver
|
||||
M: Fam Zheng <famz@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/nvme*
|
||||
|
||||
Bootdevice
|
||||
M: Gonglei <arei.gonglei@huawei.com>
|
||||
S: Maintained
|
||||
@@ -2034,14 +1965,6 @@ F: block/replication.c
|
||||
F: tests/test-replication.c
|
||||
F: docs/block-replication.txt
|
||||
|
||||
PVRDMA
|
||||
M: Yuval Shaia <yuval.shaia@oracle.com>
|
||||
M: Marcel Apfelbaum <marcel@redhat.com>
|
||||
S: Maintained
|
||||
F: hw/rdma/*
|
||||
F: hw/rdma/vmw/*
|
||||
F: docs/pvrdma.txt
|
||||
|
||||
Build and test automation
|
||||
-------------------------
|
||||
Build and test automation
|
||||
|
61
Makefile
61
Makefile
@@ -6,13 +6,7 @@ BUILD_DIR=$(CURDIR)
|
||||
# Before including a proper config-host.mak, assume we are in the source tree
|
||||
SRC_PATH=.
|
||||
|
||||
UNCHECKED_GOALS := %clean TAGS cscope ctags dist \
|
||||
html info pdf txt \
|
||||
help check-help print-% \
|
||||
docker docker-% vm-test vm-build-%
|
||||
|
||||
print-%:
|
||||
@echo '$*=$($*)'
|
||||
UNCHECKED_GOALS := %clean TAGS cscope ctags docker docker-% help
|
||||
|
||||
# All following code might depend on configuration variables
|
||||
ifneq ($(wildcard config-host.mak),)
|
||||
@@ -20,8 +14,6 @@ ifneq ($(wildcard config-host.mak),)
|
||||
all:
|
||||
include config-host.mak
|
||||
|
||||
PYTHON_UTF8 = LC_ALL= LANG=C LC_CTYPE=en_US.UTF-8 $(PYTHON)
|
||||
|
||||
git-submodule-update:
|
||||
|
||||
.PHONY: git-submodule-update
|
||||
@@ -58,7 +50,7 @@ ifneq ($(realpath $(SRC_PATH)),$(realpath .))
|
||||
ifneq ($(wildcard $(SRC_PATH)/config-host.mak),)
|
||||
$(error This is an out of tree build but your source tree ($(SRC_PATH)) \
|
||||
seems to have been used for an in-tree build. You can fix this by running \
|
||||
"$(MAKE) distclean && rm -rf *-linux-user *-softmmu" in your source tree)
|
||||
"make distclean && rm -rf *-linux-user *-softmmu" in your source tree)
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -234,29 +226,17 @@ KEYCODEMAP_GEN = $(SRC_PATH)/ui/keycodemapdb/tools/keymap-gen
|
||||
KEYCODEMAP_CSV = $(SRC_PATH)/ui/keycodemapdb/data/keymaps.csv
|
||||
|
||||
KEYCODEMAP_FILES = \
|
||||
ui/input-keymap-atset1-to-qcode.c \
|
||||
ui/input-keymap-linux-to-qcode.c \
|
||||
ui/input-keymap-qcode-to-atset1.c \
|
||||
ui/input-keymap-qcode-to-atset2.c \
|
||||
ui/input-keymap-qcode-to-atset3.c \
|
||||
ui/input-keymap-qcode-to-linux.c \
|
||||
ui/input-keymap-qcode-to-qnum.c \
|
||||
ui/input-keymap-qcode-to-sun.c \
|
||||
ui/input-keymap-qnum-to-qcode.c \
|
||||
ui/input-keymap-usb-to-qcode.c \
|
||||
ui/input-keymap-win32-to-qcode.c \
|
||||
ui/input-keymap-x11-to-qcode.c \
|
||||
ui/input-keymap-xorgevdev-to-qcode.c \
|
||||
ui/input-keymap-xorgkbd-to-qcode.c \
|
||||
ui/input-keymap-xorgxquartz-to-qcode.c \
|
||||
ui/input-keymap-xorgxwin-to-qcode.c \
|
||||
$(NULL)
|
||||
|
||||
GENERATED_FILES += $(KEYCODEMAP_FILES)
|
||||
|
||||
ui/input-keymap-%.c: $(KEYCODEMAP_GEN) $(KEYCODEMAP_CSV) $(SRC_PATH)/ui/Makefile.objs
|
||||
$(call quiet-command,\
|
||||
stem=$* && src=$${stem%-to-*} dst=$${stem#*-to-} && \
|
||||
src=$$(echo $@ | sed -E -e "s,^ui/input-keymap-(.+)-to-(.+)\.c$$,\1,") && \
|
||||
dst=$$(echo $@ | sed -E -e "s,^ui/input-keymap-(.+)-to-(.+)\.c$$,\2,") && \
|
||||
test -e $(KEYCODEMAP_GEN) && \
|
||||
$(PYTHON) $(KEYCODEMAP_GEN) \
|
||||
--lang glib2 \
|
||||
@@ -293,7 +273,7 @@ else
|
||||
DOCS=
|
||||
endif
|
||||
|
||||
SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory --quiet) BUILD_DIR=$(BUILD_DIR)
|
||||
SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR)
|
||||
SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
|
||||
SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %-config-devices.mak.d, $(TARGET_DIRS))
|
||||
|
||||
@@ -323,7 +303,7 @@ endif
|
||||
else \
|
||||
echo "WARNING: $@ out of date.";\
|
||||
fi; \
|
||||
echo "Run \"$(MAKE) defconfig\" to regenerate."; \
|
||||
echo "Run \"make defconfig\" to regenerate."; \
|
||||
rm $@.tmp; \
|
||||
fi; \
|
||||
else \
|
||||
@@ -347,7 +327,6 @@ dummy := $(call unnest-vars,, \
|
||||
ivshmem-server-obj-y \
|
||||
libvhost-user-obj-y \
|
||||
vhost-user-scsi-obj-y \
|
||||
vhost-user-blk-obj-y \
|
||||
qga-vss-dll-obj-y \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
@@ -488,17 +467,17 @@ qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
|
||||
|
||||
qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
|
||||
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-types.py \
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
|
||||
$(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \
|
||||
"GEN","$@")
|
||||
qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
|
||||
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-visit.py \
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
|
||||
$(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \
|
||||
"GEN","$@")
|
||||
qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
|
||||
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-commands.py \
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
|
||||
$(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \
|
||||
"GEN","$@")
|
||||
|
||||
@@ -519,27 +498,27 @@ qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \
|
||||
|
||||
qapi-types.c qapi-types.h :\
|
||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-types.py \
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
|
||||
$(gen-out-type) -o "." -b $<, \
|
||||
"GEN","$@")
|
||||
qapi-visit.c qapi-visit.h :\
|
||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-visit.py \
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
|
||||
$(gen-out-type) -o "." -b $<, \
|
||||
"GEN","$@")
|
||||
qapi-event.c qapi-event.h :\
|
||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-event.py \
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
|
||||
$(gen-out-type) -o "." $<, \
|
||||
"GEN","$@")
|
||||
qmp-commands.h qmp-marshal.c :\
|
||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-commands.py \
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
|
||||
$(gen-out-type) -o "." $<, \
|
||||
"GEN","$@")
|
||||
qmp-introspect.h qmp-introspect.c :\
|
||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-introspect.py \
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \
|
||||
$(gen-out-type) -o "." $<, \
|
||||
"GEN","$@")
|
||||
|
||||
@@ -579,8 +558,6 @@ ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) $(COMMON_LDADDS)
|
||||
endif
|
||||
vhost-user-scsi$(EXESUF): $(vhost-user-scsi-obj-y) libvhost-user.a
|
||||
$(call LINK, $^)
|
||||
vhost-user-blk$(EXESUF): $(vhost-user-blk-obj-y) libvhost-user.a
|
||||
$(call LINK, $^)
|
||||
|
||||
module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak
|
||||
$(call quiet-command,$(PYTHON) $< $@ \
|
||||
@@ -662,8 +639,7 @@ s390-ccw.img s390-netboot.img \
|
||||
spapr-rtas.bin slof.bin skiboot.lid \
|
||||
palcode-clipper \
|
||||
u-boot.e500 \
|
||||
qemu_vga.ndrv \
|
||||
hppa-firmware.img
|
||||
qemu_vga.ndrv
|
||||
else
|
||||
BLOBS=
|
||||
endif
|
||||
@@ -812,10 +788,10 @@ qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
||||
docs/interop/qemu-qmp-qapi.texi docs/interop/qemu-ga-qapi.texi: $(SRC_PATH)/scripts/qapi2texi.py $(qapi-py)
|
||||
|
||||
docs/interop/qemu-qmp-qapi.texi: $(qapi-modules)
|
||||
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
|
||||
|
||||
docs/interop/qemu-ga-qapi.texi: $(SRC_PATH)/qga/qapi-schema.json
|
||||
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
|
||||
|
||||
qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
|
||||
qemu.1: qemu-option-trace.texi
|
||||
@@ -957,5 +933,4 @@ ifdef QEMU_GA_MSI_ENABLED
|
||||
endif
|
||||
@echo ''
|
||||
endif
|
||||
@echo ' $(MAKE) [targets] (quiet build, default)'
|
||||
@echo ' $(MAKE) V=1 [targets] (verbose build)'
|
||||
@echo ' make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build'
|
||||
|
@@ -115,7 +115,6 @@ libvhost-user-obj-y = contrib/libvhost-user/
|
||||
vhost-user-scsi.o-cflags := $(LIBISCSI_CFLAGS)
|
||||
vhost-user-scsi.o-libs := $(LIBISCSI_LIBS)
|
||||
vhost-user-scsi-obj-y = contrib/vhost-user-scsi/
|
||||
vhost-user-blk-obj-y = contrib/vhost-user-blk/
|
||||
|
||||
######################################################################
|
||||
trace-events-subdirs =
|
||||
@@ -130,12 +129,9 @@ trace-events-subdirs += hw/block/dataplane
|
||||
trace-events-subdirs += hw/char
|
||||
trace-events-subdirs += hw/intc
|
||||
trace-events-subdirs += hw/net
|
||||
trace-events-subdirs += hw/rdma
|
||||
trace-events-subdirs += hw/rdma/vmw
|
||||
trace-events-subdirs += hw/virtio
|
||||
trace-events-subdirs += hw/audio
|
||||
trace-events-subdirs += hw/misc
|
||||
trace-events-subdirs += hw/misc/macio
|
||||
trace-events-subdirs += hw/usb
|
||||
trace-events-subdirs += hw/scsi
|
||||
trace-events-subdirs += hw/nvram
|
||||
@@ -144,7 +140,6 @@ trace-events-subdirs += hw/input
|
||||
trace-events-subdirs += hw/timer
|
||||
trace-events-subdirs += hw/dma
|
||||
trace-events-subdirs += hw/sparc
|
||||
trace-events-subdirs += hw/sparc64
|
||||
trace-events-subdirs += hw/sd
|
||||
trace-events-subdirs += hw/isa
|
||||
trace-events-subdirs += hw/mem
|
||||
@@ -153,13 +148,11 @@ trace-events-subdirs += hw/i386/xen
|
||||
trace-events-subdirs += hw/9pfs
|
||||
trace-events-subdirs += hw/ppc
|
||||
trace-events-subdirs += hw/pci
|
||||
trace-events-subdirs += hw/pci-host
|
||||
trace-events-subdirs += hw/s390x
|
||||
trace-events-subdirs += hw/vfio
|
||||
trace-events-subdirs += hw/acpi
|
||||
trace-events-subdirs += hw/arm
|
||||
trace-events-subdirs += hw/alpha
|
||||
trace-events-subdirs += hw/hppa
|
||||
trace-events-subdirs += hw/xen
|
||||
trace-events-subdirs += hw/ide
|
||||
trace-events-subdirs += ui
|
||||
|
@@ -93,8 +93,8 @@ all: $(PROGS) stap
|
||||
# cpu emulator library
|
||||
obj-y += exec.o
|
||||
obj-y += accel/
|
||||
obj-$(CONFIG_TCG) += tcg/tcg.o tcg/tcg-op.o tcg/tcg-op-vec.o tcg/tcg-op-gvec.o
|
||||
obj-$(CONFIG_TCG) += tcg/tcg-common.o tcg/optimize.o
|
||||
obj-$(CONFIG_TCG) += tcg/tcg.o tcg/tcg-op.o tcg/optimize.o
|
||||
obj-$(CONFIG_TCG) += tcg/tcg-common.o
|
||||
obj-$(CONFIG_TCG_INTERPRETER) += tcg/tci.o
|
||||
obj-$(CONFIG_TCG_INTERPRETER) += disas/tci.o
|
||||
obj-y += fpu/softfloat.o
|
||||
|
4
README
4
README
@@ -68,10 +68,6 @@ the QEMU website
|
||||
https://qemu.org/Contribute/SubmitAPatch
|
||||
https://qemu.org/Contribute/TrivialPatches
|
||||
|
||||
The QEMU website is also maintained under source control.
|
||||
|
||||
git clone git://git.qemu.org/qemu-web.git
|
||||
https://www.qemu.org/2017/02/04/the-new-qemu-website-is-up/
|
||||
|
||||
Bug reporting
|
||||
=============
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "sysemu/accel.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qemu-common.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/kvm.h"
|
||||
@@ -33,7 +34,6 @@
|
||||
#include "hw/xen/xen.h"
|
||||
#include "qom/object.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/option.h"
|
||||
|
||||
static const TypeInfo accel_type = {
|
||||
.name = TYPE_ACCEL,
|
||||
|
@@ -235,7 +235,6 @@ static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
struct kvm_userspace_memory_region mem;
|
||||
int ret;
|
||||
|
||||
mem.slot = slot->slot | (kml->as_id << 16);
|
||||
mem.guest_phys_addr = slot->start_addr;
|
||||
@@ -249,10 +248,7 @@ static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot)
|
||||
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);
|
||||
trace_kvm_set_user_memory(mem.slot, mem.flags, mem.guest_phys_addr,
|
||||
mem.memory_size, mem.userspace_addr, ret);
|
||||
return ret;
|
||||
return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
||||
}
|
||||
|
||||
int kvm_destroy_vcpu(CPUState *cpu)
|
||||
|
@@ -12,5 +12,4 @@ kvm_irqchip_commit_routes(void) ""
|
||||
kvm_irqchip_add_msi_route(char *name, int vector, int virq) "dev %s vector %d virq %d"
|
||||
kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d"
|
||||
kvm_irqchip_release_virq(int virq) "virq %d"
|
||||
kvm_set_user_memory(uint32_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, int ret) "Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " ret=%d"
|
||||
|
||||
|
@@ -1,5 +1,3 @@
|
||||
obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o
|
||||
obj-$(call lnot,$(CONFIG_HVF)) += hvf-stub.o
|
||||
obj-$(call lnot,$(CONFIG_WHPX)) += whpx-stub.o
|
||||
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
|
||||
obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o
|
||||
obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o
|
||||
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
|
||||
obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o
|
||||
|
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* QEMU HVF support
|
||||
*
|
||||
* Copyright 2017 Red Hat, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2 or later, as published by the Free Software Foundation,
|
||||
* and may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "sysemu/hvf.h"
|
||||
|
||||
int hvf_init_vcpu(CPUState *cpu)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int hvf_vcpu_exec(CPUState *cpu)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
void hvf_vcpu_destroy(CPUState *cpu)
|
||||
{
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* QEMU Windows Hypervisor Platform accelerator (WHPX) stub
|
||||
*
|
||||
* Copyright Microsoft Corp. 2017
|
||||
*
|
||||
* 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-common.h"
|
||||
#include "cpu.h"
|
||||
#include "sysemu/whpx.h"
|
||||
|
||||
int whpx_init_vcpu(CPUState *cpu)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int whpx_vcpu_exec(CPUState *cpu)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void whpx_destroy_vcpu(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
void whpx_vcpu_kick(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
void whpx_cpu_synchronize_state(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
void whpx_cpu_synchronize_post_reset(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
void whpx_cpu_synchronize_post_init(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu)
|
||||
{
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
obj-$(CONFIG_SOFTMMU) += tcg-all.o
|
||||
obj-$(CONFIG_SOFTMMU) += cputlb.o
|
||||
obj-y += tcg-runtime.o tcg-runtime-gvec.o
|
||||
obj-y += tcg-runtime.o
|
||||
obj-y += cpu-exec.o cpu-exec-common.o translate-all.o
|
||||
obj-y += translator.o
|
||||
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include "cpu.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/memory-internal.h"
|
||||
|
||||
bool tcg_allowed;
|
||||
|
||||
|
@@ -146,10 +146,8 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
||||
uint8_t *tb_ptr = itb->tc.ptr;
|
||||
|
||||
qemu_log_mask_and_addr(CPU_LOG_EXEC, itb->pc,
|
||||
"Trace %d: %p ["
|
||||
TARGET_FMT_lx "/" TARGET_FMT_lx "/%#x] %s\n",
|
||||
cpu->cpu_index, itb->tc.ptr,
|
||||
itb->cs_base, itb->pc, itb->flags,
|
||||
"Trace %p [%d: " TARGET_FMT_lx "] %s\n",
|
||||
itb->tc.ptr, cpu->cpu_index, itb->pc,
|
||||
lookup_symbol(itb->pc));
|
||||
|
||||
#if defined(DEBUG_DISAS)
|
||||
@@ -527,13 +525,19 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||
TranslationBlock **last_tb)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
int32_t insns_left;
|
||||
|
||||
/* Clear the interrupt flag now since we're processing
|
||||
* cpu->interrupt_request and cpu->exit_request.
|
||||
* Ensure zeroing happens before reading cpu->exit_request or
|
||||
* cpu->interrupt_request (see also smp_wmb in cpu_exit())
|
||||
*/
|
||||
atomic_mb_set(&cpu->icount_decr.u16.high, 0);
|
||||
insns_left = atomic_read(&cpu->icount_decr.u32);
|
||||
atomic_set(&cpu->icount_decr.u16.high, 0);
|
||||
if (unlikely(insns_left < 0)) {
|
||||
/* Ensure the zeroing of icount_decr comes before the next read
|
||||
* of cpu->exit_request or cpu->interrupt_request.
|
||||
*/
|
||||
smp_mb();
|
||||
}
|
||||
|
||||
if (unlikely(atomic_read(&cpu->interrupt_request))) {
|
||||
int interrupt_request;
|
||||
|
@@ -880,7 +880,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
|
||||
if (unlikely(env->tlb_table[mmu_idx][index].addr_code !=
|
||||
(addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)))) {
|
||||
if (!VICTIM_TLB_HIT(addr_read, addr)) {
|
||||
tlb_fill(ENV_GET_CPU(env), addr, 0, MMU_INST_FETCH, mmu_idx, 0);
|
||||
tlb_fill(ENV_GET_CPU(env), addr, MMU_INST_FETCH, mmu_idx, 0);
|
||||
}
|
||||
}
|
||||
iotlbentry = &env->iotlb[mmu_idx][index];
|
||||
@@ -928,7 +928,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
|
||||
* Otherwise the function will return, and there will be a valid
|
||||
* entry in the TLB for this access.
|
||||
*/
|
||||
void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx,
|
||||
void probe_write(CPUArchState *env, target_ulong addr, int mmu_idx,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
@@ -938,8 +938,7 @@ void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx,
|
||||
!= (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
/* TLB entry is for a different page */
|
||||
if (!VICTIM_TLB_HIT(addr_write, addr)) {
|
||||
tlb_fill(ENV_GET_CPU(env), addr, size, MMU_DATA_STORE,
|
||||
mmu_idx, retaddr);
|
||||
tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -982,8 +981,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
|
||||
if ((addr & TARGET_PAGE_MASK)
|
||||
!= (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
if (!VICTIM_TLB_HIT(addr_write, addr)) {
|
||||
tlb_fill(ENV_GET_CPU(env), addr, 1 << s_bits, MMU_DATA_STORE,
|
||||
mmu_idx, retaddr);
|
||||
tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr);
|
||||
}
|
||||
tlb_addr = tlbe->addr_write & ~TLB_INVALID_MASK;
|
||||
}
|
||||
@@ -997,8 +995,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
|
||||
|
||||
/* Let the guest notice RMW on a write-only page. */
|
||||
if (unlikely(tlbe->addr_read != (tlb_addr & ~TLB_NOTDIRTY))) {
|
||||
tlb_fill(ENV_GET_CPU(env), addr, 1 << s_bits, MMU_DATA_LOAD,
|
||||
mmu_idx, retaddr);
|
||||
tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_LOAD, mmu_idx, retaddr);
|
||||
/* Since we don't support reads and writes to different addresses,
|
||||
and we do have the proper page loaded for write, this shouldn't
|
||||
ever return. But just in case, handle via stop-the-world. */
|
||||
|
@@ -124,7 +124,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr,
|
||||
if ((addr & TARGET_PAGE_MASK)
|
||||
!= (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
if (!VICTIM_TLB_HIT(ADDR_READ, addr)) {
|
||||
tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, READ_ACCESS_TYPE,
|
||||
tlb_fill(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE,
|
||||
mmu_idx, retaddr);
|
||||
}
|
||||
tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
|
||||
@@ -191,7 +191,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr,
|
||||
if ((addr & TARGET_PAGE_MASK)
|
||||
!= (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
if (!VICTIM_TLB_HIT(ADDR_READ, addr)) {
|
||||
tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, READ_ACCESS_TYPE,
|
||||
tlb_fill(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE,
|
||||
mmu_idx, retaddr);
|
||||
}
|
||||
tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
|
||||
@@ -283,8 +283,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
|
||||
if ((addr & TARGET_PAGE_MASK)
|
||||
!= (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
if (!VICTIM_TLB_HIT(addr_write, addr)) {
|
||||
tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, MMU_DATA_STORE,
|
||||
mmu_idx, retaddr);
|
||||
tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr);
|
||||
}
|
||||
tlb_addr = env->tlb_table[mmu_idx][index].addr_write & ~TLB_INVALID_MASK;
|
||||
}
|
||||
@@ -317,7 +316,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
|
||||
tlb_addr2 = env->tlb_table[mmu_idx][index2].addr_write;
|
||||
if (page2 != (tlb_addr2 & (TARGET_PAGE_MASK | TLB_INVALID_MASK))
|
||||
&& !VICTIM_TLB_HIT(addr_write, page2)) {
|
||||
tlb_fill(ENV_GET_CPU(env), page2, DATA_SIZE, MMU_DATA_STORE,
|
||||
tlb_fill(ENV_GET_CPU(env), page2, MMU_DATA_STORE,
|
||||
mmu_idx, retaddr);
|
||||
}
|
||||
|
||||
@@ -360,8 +359,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
|
||||
if ((addr & TARGET_PAGE_MASK)
|
||||
!= (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
if (!VICTIM_TLB_HIT(addr_write, addr)) {
|
||||
tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, MMU_DATA_STORE,
|
||||
mmu_idx, retaddr);
|
||||
tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr);
|
||||
}
|
||||
tlb_addr = env->tlb_table[mmu_idx][index].addr_write & ~TLB_INVALID_MASK;
|
||||
}
|
||||
@@ -394,7 +392,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
|
||||
tlb_addr2 = env->tlb_table[mmu_idx][index2].addr_write;
|
||||
if (page2 != (tlb_addr2 & (TARGET_PAGE_MASK | TLB_INVALID_MASK))
|
||||
&& !VICTIM_TLB_HIT(addr_write, page2)) {
|
||||
tlb_fill(ENV_GET_CPU(env), page2, DATA_SIZE, MMU_DATA_STORE,
|
||||
tlb_fill(ENV_GET_CPU(env), page2, MMU_DATA_STORE,
|
||||
mmu_idx, retaddr);
|
||||
}
|
||||
|
||||
|
@@ -1,997 +0,0 @@
|
||||
/*
|
||||
* Generic vectorized operation runtime
|
||||
*
|
||||
* Copyright (c) 2018 Linaro
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/helper-proto.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);
|
||||
intptr_t i;
|
||||
|
||||
if (unlikely(maxsz > oprsz)) {
|
||||
for (i = oprsz; i < maxsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) + *(vec8 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) + *(vec16 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) + *(vec32 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) + *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) + vecb;
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) + vecb;
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) + vecb;
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) + vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) - *(vec8 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) - *(vec16 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) - *(vec32 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) - *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) - vecb;
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) - vecb;
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) - vecb;
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) - vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) * *(vec8 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) * *(vec16 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) * *(vec32 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) * *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) * vecb;
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) * vecb;
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) * vecb;
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) * vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec8)) {
|
||||
*(vec8 *)(d + i) = -*(vec8 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec16)) {
|
||||
*(vec16 *)(d + i) = -*(vec16 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec32)) {
|
||||
*(vec32 *)(d + i) = -*(vec32 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec64)) {
|
||||
*(vec64 *)(d + i) = -*(vec64 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_mov)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
|
||||
memcpy(d, a, oprsz);
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_dup64)(void *d, uint32_t desc, uint64_t c)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
if (c == 0) {
|
||||
oprsz = 0;
|
||||
} else {
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = c;
|
||||
}
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_dup32)(void *d, uint32_t desc, uint32_t c)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
if (c == 0) {
|
||||
oprsz = 0;
|
||||
} else {
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = c;
|
||||
}
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_dup16)(void *d, uint32_t desc, uint32_t c)
|
||||
{
|
||||
HELPER(gvec_dup32)(d, desc, 0x00010001 * (c & 0xffff));
|
||||
}
|
||||
|
||||
void HELPER(gvec_dup8)(void *d, uint32_t desc, uint32_t c)
|
||||
{
|
||||
HELPER(gvec_dup32)(d, desc, 0x01010101 * (c & 0xff));
|
||||
}
|
||||
|
||||
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(vec64)) {
|
||||
*(vec64 *)(d + i) = ~*(vec64 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) & *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) | *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) ^ *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) &~ *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) |~ *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) & vecb;
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) ^ vecb;
|
||||
}
|
||||
clear_high(d, oprsz, 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(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) | vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_shl8i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) << shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_shl16i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) << shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_shl32i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) << shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_shl64i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) << shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_shr8i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_shr16i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_shr32i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_shr64i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_sar8i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(svec8 *)(d + i) = *(svec8 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_sar16i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(svec16 *)(d + i) = *(svec16 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_sar32i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(svec32 *)(d + i) = *(svec32 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_sar64i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(svec64 *)(d + i) = *(svec64 *)(a + i) >> shift;
|
||||
}
|
||||
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(vec64)) { \
|
||||
*(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, 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
|
||||
|
||||
void HELPER(gvec_ssadd8)(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(int8_t)) {
|
||||
int r = *(int8_t *)(a + i) + *(int8_t *)(b + i);
|
||||
if (r > INT8_MAX) {
|
||||
r = INT8_MAX;
|
||||
} else if (r < INT8_MIN) {
|
||||
r = INT8_MIN;
|
||||
}
|
||||
*(int8_t *)(d + i) = r;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_ssadd16)(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(int16_t)) {
|
||||
int r = *(int16_t *)(a + i) + *(int16_t *)(b + i);
|
||||
if (r > INT16_MAX) {
|
||||
r = INT16_MAX;
|
||||
} else if (r < INT16_MIN) {
|
||||
r = INT16_MIN;
|
||||
}
|
||||
*(int16_t *)(d + i) = r;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_ssadd32)(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(int32_t)) {
|
||||
int32_t ai = *(int32_t *)(a + i);
|
||||
int32_t bi = *(int32_t *)(b + i);
|
||||
int32_t di = ai + bi;
|
||||
if (((di ^ ai) &~ (ai ^ bi)) < 0) {
|
||||
/* Signed overflow. */
|
||||
di = (di < 0 ? INT32_MAX : INT32_MIN);
|
||||
}
|
||||
*(int32_t *)(d + i) = di;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_ssadd64)(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(int64_t)) {
|
||||
int64_t ai = *(int64_t *)(a + i);
|
||||
int64_t bi = *(int64_t *)(b + i);
|
||||
int64_t di = ai + bi;
|
||||
if (((di ^ ai) &~ (ai ^ bi)) < 0) {
|
||||
/* Signed overflow. */
|
||||
di = (di < 0 ? INT64_MAX : INT64_MIN);
|
||||
}
|
||||
*(int64_t *)(d + i) = di;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_sssub8)(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)) {
|
||||
int r = *(int8_t *)(a + i) - *(int8_t *)(b + i);
|
||||
if (r > INT8_MAX) {
|
||||
r = INT8_MAX;
|
||||
} else if (r < INT8_MIN) {
|
||||
r = INT8_MIN;
|
||||
}
|
||||
*(uint8_t *)(d + i) = r;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_sssub16)(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(int16_t)) {
|
||||
int r = *(int16_t *)(a + i) - *(int16_t *)(b + i);
|
||||
if (r > INT16_MAX) {
|
||||
r = INT16_MAX;
|
||||
} else if (r < INT16_MIN) {
|
||||
r = INT16_MIN;
|
||||
}
|
||||
*(int16_t *)(d + i) = r;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_sssub32)(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(int32_t)) {
|
||||
int32_t ai = *(int32_t *)(a + i);
|
||||
int32_t bi = *(int32_t *)(b + i);
|
||||
int32_t di = ai - bi;
|
||||
if (((di ^ ai) & (ai ^ bi)) < 0) {
|
||||
/* Signed overflow. */
|
||||
di = (di < 0 ? INT32_MAX : INT32_MIN);
|
||||
}
|
||||
*(int32_t *)(d + i) = di;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_sssub64)(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(int64_t)) {
|
||||
int64_t ai = *(int64_t *)(a + i);
|
||||
int64_t bi = *(int64_t *)(b + i);
|
||||
int64_t di = ai - bi;
|
||||
if (((di ^ ai) & (ai ^ bi)) < 0) {
|
||||
/* Signed overflow. */
|
||||
di = (di < 0 ? INT64_MAX : INT64_MIN);
|
||||
}
|
||||
*(int64_t *)(d + i) = di;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_usadd8)(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)) {
|
||||
unsigned r = *(uint8_t *)(a + i) + *(uint8_t *)(b + i);
|
||||
if (r > UINT8_MAX) {
|
||||
r = UINT8_MAX;
|
||||
}
|
||||
*(uint8_t *)(d + i) = r;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_usadd16)(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)) {
|
||||
unsigned r = *(uint16_t *)(a + i) + *(uint16_t *)(b + i);
|
||||
if (r > UINT16_MAX) {
|
||||
r = UINT16_MAX;
|
||||
}
|
||||
*(uint16_t *)(d + i) = r;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_usadd32)(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 ai = *(uint32_t *)(a + i);
|
||||
uint32_t bi = *(uint32_t *)(b + i);
|
||||
uint32_t di = ai + bi;
|
||||
if (di < ai) {
|
||||
di = UINT32_MAX;
|
||||
}
|
||||
*(uint32_t *)(d + i) = di;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_usadd64)(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 ai = *(uint64_t *)(a + i);
|
||||
uint64_t bi = *(uint64_t *)(b + i);
|
||||
uint64_t di = ai + bi;
|
||||
if (di < ai) {
|
||||
di = UINT64_MAX;
|
||||
}
|
||||
*(uint64_t *)(d + i) = di;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_ussub8)(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)) {
|
||||
int r = *(uint8_t *)(a + i) - *(uint8_t *)(b + i);
|
||||
if (r < 0) {
|
||||
r = 0;
|
||||
}
|
||||
*(uint8_t *)(d + i) = r;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_ussub16)(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)) {
|
||||
int r = *(uint16_t *)(a + i) - *(uint16_t *)(b + i);
|
||||
if (r < 0) {
|
||||
r = 0;
|
||||
}
|
||||
*(uint16_t *)(d + i) = r;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_ussub32)(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 ai = *(uint32_t *)(a + i);
|
||||
uint32_t bi = *(uint32_t *)(b + i);
|
||||
uint32_t di = ai - bi;
|
||||
if (ai < bi) {
|
||||
di = 0;
|
||||
}
|
||||
*(uint32_t *)(d + i) = di;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_ussub64)(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 ai = *(uint64_t *)(a + i);
|
||||
uint64_t bi = *(uint64_t *)(b + i);
|
||||
uint64_t di = ai - bi;
|
||||
if (ai < bi) {
|
||||
di = 0;
|
||||
}
|
||||
*(uint64_t *)(d + i) = di;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
@@ -156,9 +156,8 @@ void *HELPER(lookup_tb_ptr)(CPUArchState *env)
|
||||
return tcg_ctx->code_gen_epilogue;
|
||||
}
|
||||
qemu_log_mask_and_addr(CPU_LOG_EXEC, pc,
|
||||
"Chain %d: %p ["
|
||||
TARGET_FMT_lx "/" TARGET_FMT_lx "/%#x] %s\n",
|
||||
cpu->cpu_index, tb->tc.ptr, cs_base, pc, flags,
|
||||
"Chain %p [%d: " TARGET_FMT_lx "] %s\n",
|
||||
tb->tc.ptr, cpu->cpu_index, pc,
|
||||
lookup_symbol(pc));
|
||||
return tb->tc.ptr;
|
||||
}
|
||||
|
@@ -134,121 +134,3 @@ GEN_ATOMIC_HELPERS(xor_fetch)
|
||||
GEN_ATOMIC_HELPERS(xchg)
|
||||
|
||||
#undef GEN_ATOMIC_HELPERS
|
||||
|
||||
DEF_HELPER_FLAGS_3(gvec_mov, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(gvec_dup8, TCG_CALL_NO_RWG, void, ptr, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_dup16, TCG_CALL_NO_RWG, void, ptr, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_dup32, TCG_CALL_NO_RWG, void, ptr, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_dup64, TCG_CALL_NO_RWG, void, ptr, i32, i64)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_add8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_add16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_add32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_add64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_adds8, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_adds16, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_adds32, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_adds64, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_sub8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_sub16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_sub32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_sub64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_subs8, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_subs16, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_subs32, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_subs64, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_mul8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_mul16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_mul32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_mul64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_muls8, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_muls16, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_muls32, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_muls64, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_ssadd8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_ssadd16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_ssadd32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_ssadd64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_sssub8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_sssub16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_sssub32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_sssub64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_usadd8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_usadd16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_usadd32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_usadd64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_ussub8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_ussub16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_ussub32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_ussub64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(gvec_neg8, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_neg16, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_neg32, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_neg64, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(gvec_not, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_and, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_or, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_xor, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_andc, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_orc, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_ands, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_xors, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_ors, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(gvec_shl8i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_shl16i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_shl32i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_shl64i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(gvec_shr8i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_shr16i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_shr32i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_shr64i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(gvec_sar8i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_sar16i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_sar32i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_sar64i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_eq8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_eq16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_eq32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_eq64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_ne8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_ne16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_ne32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_ne64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_lt8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_lt16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_lt32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_lt64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_le8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_le16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_le32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_le64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_ltu8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_ltu16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_ltu32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_ltu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_leu8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_leu16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_leu32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include "tcg.h"
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#include "qemu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include <sys/param.h>
|
||||
#if __FreeBSD_version >= 700104
|
||||
@@ -256,7 +257,7 @@ static target_long decode_sleb128(uint8_t **pp)
|
||||
/* Encode the data collected about the instructions while compiling TB.
|
||||
Place the data at BLOCK, and return the number of bytes consumed.
|
||||
|
||||
The logical table consists of TARGET_INSN_START_WORDS target_ulong's,
|
||||
The logical table consisits of TARGET_INSN_START_WORDS target_ulong's,
|
||||
which come from the target's insn_start data, followed by a uintptr_t
|
||||
which comes from the host pc of the end of the code implementing the insn.
|
||||
|
||||
@@ -2181,41 +2182,29 @@ int page_unprotect(target_ulong address, uintptr_t pc)
|
||||
|
||||
/* if the page was really writable, then we change its
|
||||
protection back to writable */
|
||||
if (p->flags & PAGE_WRITE_ORG) {
|
||||
if ((p->flags & PAGE_WRITE_ORG) && !(p->flags & PAGE_WRITE)) {
|
||||
host_start = address & qemu_host_page_mask;
|
||||
host_end = host_start + qemu_host_page_size;
|
||||
|
||||
prot = 0;
|
||||
current_tb_invalidated = false;
|
||||
if (p->flags & PAGE_WRITE) {
|
||||
/* If the page is actually marked WRITE then assume this is because
|
||||
* this thread raced with another one which got here first and
|
||||
* set the page to PAGE_WRITE and did the TB invalidate for us.
|
||||
*/
|
||||
#ifdef TARGET_HAS_PRECISE_SMC
|
||||
TranslationBlock *current_tb = tb_find_pc(pc);
|
||||
if (current_tb) {
|
||||
current_tb_invalidated = tb_cflags(current_tb) & CF_INVALID;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
host_start = address & qemu_host_page_mask;
|
||||
host_end = host_start + qemu_host_page_size;
|
||||
for (addr = host_start ; addr < host_end ; addr += TARGET_PAGE_SIZE) {
|
||||
p = page_find(addr >> TARGET_PAGE_BITS);
|
||||
p->flags |= PAGE_WRITE;
|
||||
prot |= p->flags;
|
||||
|
||||
prot = 0;
|
||||
for (addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
p = page_find(addr >> TARGET_PAGE_BITS);
|
||||
p->flags |= PAGE_WRITE;
|
||||
prot |= p->flags;
|
||||
|
||||
/* and since the content will be modified, we must invalidate
|
||||
the corresponding translated code. */
|
||||
current_tb_invalidated |= tb_invalidate_phys_page(addr, pc);
|
||||
/* and since the content will be modified, we must invalidate
|
||||
the corresponding translated code. */
|
||||
current_tb_invalidated |= tb_invalidate_phys_page(addr, pc);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
if (DEBUG_TB_CHECK_GATE) {
|
||||
tb_invalidate_check(addr);
|
||||
}
|
||||
#endif
|
||||
if (DEBUG_TB_CHECK_GATE) {
|
||||
tb_invalidate_check(addr);
|
||||
}
|
||||
mprotect((void *)g2h(host_start), qemu_host_page_size,
|
||||
prot & PAGE_BITS);
|
||||
#endif
|
||||
}
|
||||
mprotect((void *)g2h(host_start), qemu_host_page_size,
|
||||
prot & PAGE_BITS);
|
||||
|
||||
mmap_unlock();
|
||||
/* If current TB was invalidated return to main loop */
|
||||
return current_tb_invalidated ? 2 : 1;
|
||||
|
@@ -57,13 +57,12 @@ static void cpu_exit_tb_from_sighandler(CPUState *cpu, sigset_t *old_set)
|
||||
the effective address of the memory exception. 'is_write' is 1 if a
|
||||
write caused the exception and otherwise 0'. 'old_set' is the
|
||||
signal set which should be restored */
|
||||
static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
||||
static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set)
|
||||
{
|
||||
CPUState *cpu = current_cpu;
|
||||
CPUClass *cc;
|
||||
int ret;
|
||||
unsigned long address = (unsigned long)info->si_addr;
|
||||
|
||||
/* We must handle PC addresses from two different sources:
|
||||
* a call return address and a signal frame address.
|
||||
@@ -104,18 +103,7 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
||||
pc, address, is_write, *(unsigned long *)old_set);
|
||||
#endif
|
||||
/* XXX: locking issue */
|
||||
/* Note that it is important that we don't call page_unprotect() unless
|
||||
* this is really a "write to nonwriteable page" fault, because
|
||||
* page_unprotect() assumes that if it is called for an access to
|
||||
* a page that's writeable this means we had two threads racing and
|
||||
* another thread got there first and already made the page writeable;
|
||||
* so we will retry the access. If we were to call page_unprotect()
|
||||
* for some other kind of fault that should really be passed to the
|
||||
* guest, we'd end up in an infinite loop of retrying the faulting
|
||||
* access.
|
||||
*/
|
||||
if (is_write && info->si_signo == SIGSEGV && info->si_code == SEGV_ACCERR &&
|
||||
h2g_valid(address)) {
|
||||
if (is_write && h2g_valid(address)) {
|
||||
switch (page_unprotect(h2g(address), pc)) {
|
||||
case 0:
|
||||
/* Fault not caused by a page marked unwritable to protect
|
||||
@@ -149,7 +137,7 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
||||
cc = CPU_GET_CLASS(cpu);
|
||||
/* see if it is an MMU fault */
|
||||
g_assert(cc->handle_mmu_fault);
|
||||
ret = cc->handle_mmu_fault(cpu, address, 0, is_write, MMU_USER_IDX);
|
||||
ret = cc->handle_mmu_fault(cpu, address, is_write, MMU_USER_IDX);
|
||||
|
||||
if (ret == 0) {
|
||||
/* The MMU fault was handled without causing real CPU fault.
|
||||
@@ -227,8 +215,9 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
#endif
|
||||
pc = EIP_sig(uc);
|
||||
trapno = TRAP_sig(uc);
|
||||
return handle_cpu_signal(pc, info,
|
||||
trapno == 0xe ? (ERROR_sig(uc) >> 1) & 1 : 0,
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
trapno == 0xe ?
|
||||
(ERROR_sig(uc) >> 1) & 1 : 0,
|
||||
&MASK_sig(uc));
|
||||
}
|
||||
|
||||
@@ -272,8 +261,9 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
#endif
|
||||
|
||||
pc = PC_sig(uc);
|
||||
return handle_cpu_signal(pc, info,
|
||||
TRAP_sig(uc) == 0xe ? (ERROR_sig(uc) >> 1) & 1 : 0,
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
TRAP_sig(uc) == 0xe ?
|
||||
(ERROR_sig(uc) >> 1) & 1 : 0,
|
||||
&MASK_sig(uc));
|
||||
}
|
||||
|
||||
@@ -351,7 +341,8 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
is_write = 1;
|
||||
}
|
||||
#endif
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__alpha__)
|
||||
@@ -381,7 +372,8 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
is_write = 1;
|
||||
}
|
||||
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, &uc->uc_sigmask);
|
||||
}
|
||||
#elif defined(__sparc__)
|
||||
|
||||
@@ -440,7 +432,8 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
break;
|
||||
}
|
||||
}
|
||||
return handle_cpu_signal(pc, info, is_write, sigmask);
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__arm__)
|
||||
@@ -473,7 +466,9 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
* later processor; on v5 we will always report this as a read).
|
||||
*/
|
||||
is_write = extract32(uc->uc_mcontext.error_code, 11, 1);
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write,
|
||||
&uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
@@ -500,7 +495,43 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
|
||||
/* Ignore bits 23 & 24, controlling indexing. */
|
||||
|| (insn & 0x3a400000) == 0x28000000); /* C3.3.7,14-16 */
|
||||
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
return handle_cpu_signal(pc, (uintptr_t)info->si_addr,
|
||||
is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__ia64)
|
||||
|
||||
#ifndef __ISR_VALID
|
||||
/* This ought to be in <bits/siginfo.h>... */
|
||||
# define __ISR_VALID 1
|
||||
#endif
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
ucontext_t *uc = puc;
|
||||
unsigned long ip;
|
||||
int is_write = 0;
|
||||
|
||||
ip = uc->uc_mcontext.sc_ip;
|
||||
switch (host_signum) {
|
||||
case SIGILL:
|
||||
case SIGFPE:
|
||||
case SIGSEGV:
|
||||
case SIGBUS:
|
||||
case SIGTRAP:
|
||||
if (info->si_code && (info->si_segvflags & __ISR_VALID)) {
|
||||
/* ISR.W (write-access) is bit 33: */
|
||||
is_write = (info->si_isr >> 33) & 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return handle_cpu_signal(ip, (unsigned long)info->si_addr,
|
||||
is_write,
|
||||
(sigset_t *)&uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__s390__)
|
||||
@@ -552,7 +583,8 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
}
|
||||
break;
|
||||
}
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__mips__)
|
||||
@@ -567,7 +599,8 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
|
||||
/* XXX: compute is_write */
|
||||
is_write = 0;
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@@ -53,8 +53,6 @@ int graphic_depth = 32;
|
||||
#define QEMU_ARCH QEMU_ARCH_CRIS
|
||||
#elif defined(TARGET_I386)
|
||||
#define QEMU_ARCH QEMU_ARCH_I386
|
||||
#elif defined(TARGET_HPPA)
|
||||
#define QEMU_ARCH QEMU_ARCH_HPPA
|
||||
#elif defined(TARGET_M68K)
|
||||
#define QEMU_ARCH QEMU_ARCH_M68K
|
||||
#elif defined(TARGET_LM32)
|
||||
|
@@ -823,7 +823,7 @@ static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
hw->samples = obt.samples;
|
||||
|
||||
alsa->pcm_buf = audio_calloc(__func__, obt.samples, 1 << hw->info.shift);
|
||||
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
|
||||
if (!alsa->pcm_buf) {
|
||||
dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
|
||||
hw->samples, 1 << hw->info.shift);
|
||||
@@ -934,7 +934,7 @@ static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
hw->samples = obt.samples;
|
||||
|
||||
alsa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
|
||||
if (!alsa->pcm_buf) {
|
||||
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
|
||||
hw->samples, 1 << hw->info.shift);
|
||||
|
@@ -424,12 +424,12 @@ static void audio_process_options (const char *prefix,
|
||||
const char qemu_prefix[] = "QEMU_";
|
||||
size_t preflen, optlen;
|
||||
|
||||
if (audio_bug(__func__, !prefix)) {
|
||||
if (audio_bug (AUDIO_FUNC, !prefix)) {
|
||||
dolog ("prefix = NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, !opt)) {
|
||||
if (audio_bug (AUDIO_FUNC, !opt)) {
|
||||
dolog ("opt = NULL\n");
|
||||
return;
|
||||
}
|
||||
@@ -792,7 +792,7 @@ static int audio_attach_capture (HWVoiceOut *hw)
|
||||
SWVoiceOut *sw;
|
||||
HWVoiceOut *hw_cap = &cap->hw;
|
||||
|
||||
sc = audio_calloc(__func__, 1, sizeof(*sc));
|
||||
sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc));
|
||||
if (!sc) {
|
||||
dolog ("Could not allocate soft capture voice (%zu bytes)\n",
|
||||
sizeof (*sc));
|
||||
@@ -848,7 +848,7 @@ static int audio_pcm_hw_find_min_in (HWVoiceIn *hw)
|
||||
int audio_pcm_hw_get_live_in (HWVoiceIn *hw)
|
||||
{
|
||||
int live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
|
||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
||||
if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
|
||||
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
|
||||
return 0;
|
||||
}
|
||||
@@ -886,7 +886,7 @@ static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw)
|
||||
int live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||
int rpos;
|
||||
|
||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
||||
if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
|
||||
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
|
||||
return 0;
|
||||
}
|
||||
@@ -909,7 +909,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
|
||||
rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
|
||||
|
||||
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
||||
if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
|
||||
dolog ("live_in=%d hw->samples=%d\n", live, hw->samples);
|
||||
return 0;
|
||||
}
|
||||
@@ -935,7 +935,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
|
||||
}
|
||||
osamp = swlim;
|
||||
|
||||
if (audio_bug(__func__, osamp < 0)) {
|
||||
if (audio_bug (AUDIO_FUNC, osamp < 0)) {
|
||||
dolog ("osamp=%d\n", osamp);
|
||||
return 0;
|
||||
}
|
||||
@@ -990,7 +990,7 @@ static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
|
||||
if (nb_live1) {
|
||||
int live = smin;
|
||||
|
||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
||||
if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
|
||||
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
|
||||
return 0;
|
||||
}
|
||||
@@ -1014,7 +1014,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
|
||||
hwsamples = sw->hw->samples;
|
||||
|
||||
live = sw->total_hw_samples_mixed;
|
||||
if (audio_bug(__func__, live < 0 || live > hwsamples)) {
|
||||
if (audio_bug (AUDIO_FUNC, live < 0 || live > hwsamples)){
|
||||
dolog ("live=%d hw->samples=%d\n", live, hwsamples);
|
||||
return 0;
|
||||
}
|
||||
@@ -1263,7 +1263,7 @@ static int audio_get_avail (SWVoiceIn *sw)
|
||||
}
|
||||
|
||||
live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||
if (audio_bug(__func__, live < 0 || live > sw->hw->samples)) {
|
||||
if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
|
||||
dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
|
||||
return 0;
|
||||
}
|
||||
@@ -1287,7 +1287,7 @@ static int audio_get_free (SWVoiceOut *sw)
|
||||
|
||||
live = sw->total_hw_samples_mixed;
|
||||
|
||||
if (audio_bug(__func__, live < 0 || live > sw->hw->samples)) {
|
||||
if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
|
||||
dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
|
||||
return 0;
|
||||
}
|
||||
@@ -1354,7 +1354,7 @@ static void audio_run_out (AudioState *s)
|
||||
live = 0;
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
||||
if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
|
||||
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
|
||||
continue;
|
||||
}
|
||||
@@ -1389,7 +1389,7 @@ static void audio_run_out (AudioState *s)
|
||||
prev_rpos = hw->rpos;
|
||||
played = hw->pcm_ops->run_out (hw, live);
|
||||
replay_audio_out(&played);
|
||||
if (audio_bug(__func__, hw->rpos >= hw->samples)) {
|
||||
if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
|
||||
dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
|
||||
hw->rpos, hw->samples, played);
|
||||
hw->rpos = 0;
|
||||
@@ -1410,7 +1410,7 @@ static void audio_run_out (AudioState *s)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, played > sw->total_hw_samples_mixed)) {
|
||||
if (audio_bug (AUDIO_FUNC, played > sw->total_hw_samples_mixed)) {
|
||||
dolog ("played=%d sw->total_hw_samples_mixed=%d\n",
|
||||
played, sw->total_hw_samples_mixed);
|
||||
played = sw->total_hw_samples_mixed;
|
||||
@@ -1513,7 +1513,7 @@ static void audio_run_capture (AudioState *s)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, captured > sw->total_hw_samples_mixed)) {
|
||||
if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) {
|
||||
dolog ("captured=%d sw->total_hw_samples_mixed=%d\n",
|
||||
captured, sw->total_hw_samples_mixed);
|
||||
captured = sw->total_hw_samples_mixed;
|
||||
@@ -1924,7 +1924,7 @@ CaptureVoiceOut *AUD_add_capture (
|
||||
goto err0;
|
||||
}
|
||||
|
||||
cb = audio_calloc(__func__, 1, sizeof(*cb));
|
||||
cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb));
|
||||
if (!cb) {
|
||||
dolog ("Could not allocate capture callback information, size %zu\n",
|
||||
sizeof (*cb));
|
||||
@@ -1942,7 +1942,7 @@ CaptureVoiceOut *AUD_add_capture (
|
||||
HWVoiceOut *hw;
|
||||
CaptureVoiceOut *cap;
|
||||
|
||||
cap = audio_calloc(__func__, 1, sizeof(*cap));
|
||||
cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap));
|
||||
if (!cap) {
|
||||
dolog ("Could not allocate capture voice, size %zu\n",
|
||||
sizeof (*cap));
|
||||
@@ -1955,8 +1955,8 @@ CaptureVoiceOut *AUD_add_capture (
|
||||
|
||||
/* XXX find a more elegant way */
|
||||
hw->samples = 4096 * 4;
|
||||
hw->mix_buf = audio_calloc(__func__, hw->samples,
|
||||
sizeof(struct st_sample));
|
||||
hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples,
|
||||
sizeof (struct st_sample));
|
||||
if (!hw->mix_buf) {
|
||||
dolog ("Could not allocate capture mix buffer (%d samples)\n",
|
||||
hw->samples);
|
||||
@@ -1965,7 +1965,7 @@ CaptureVoiceOut *AUD_add_capture (
|
||||
|
||||
audio_pcm_init_info (&hw->info, as);
|
||||
|
||||
cap->buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||
cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
|
||||
if (!cap->buf) {
|
||||
dolog ("Could not allocate capture buffer "
|
||||
"(%d samples, each %d bytes)\n",
|
||||
|
@@ -252,4 +252,10 @@ static inline int audio_ring_dist (int dst, int src, int len)
|
||||
#define AUDIO_STRINGIFY_(n) #n
|
||||
#define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n)
|
||||
|
||||
#if defined _MSC_VER || defined __GNUC__
|
||||
#define AUDIO_FUNC __FUNCTION__
|
||||
#else
|
||||
#define AUDIO_FUNC __FILE__ ":" AUDIO_STRINGIFY (__LINE__)
|
||||
#endif
|
||||
|
||||
#endif /* QEMU_AUDIO_INT_H */
|
||||
|
@@ -31,7 +31,7 @@ int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
|
||||
|
||||
err = sigfillset (&set);
|
||||
if (err) {
|
||||
logerr(p, errno, "%s(%s): sigfillset failed", cap, __func__);
|
||||
logerr (p, errno, "%s(%s): sigfillset failed", cap, AUDIO_FUNC);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
|
||||
|
||||
err2 = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
|
||||
if (err2) {
|
||||
logerr(p, err2, "%s(%s): pthread_sigmask (restore) failed",
|
||||
cap, __func__);
|
||||
logerr (p, err2, "%s(%s): pthread_sigmask (restore) failed",
|
||||
cap, AUDIO_FUNC);
|
||||
/* We have failed to restore original signal mask, all bets are off,
|
||||
so terminate the process */
|
||||
exit (EXIT_FAILURE);
|
||||
@@ -74,17 +74,17 @@ int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
|
||||
err2:
|
||||
err2 = pthread_cond_destroy (&p->cond);
|
||||
if (err2) {
|
||||
logerr(p, err2, "%s(%s): pthread_cond_destroy failed", cap, __func__);
|
||||
logerr (p, err2, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC);
|
||||
}
|
||||
|
||||
err1:
|
||||
err2 = pthread_mutex_destroy (&p->mutex);
|
||||
if (err2) {
|
||||
logerr(p, err2, "%s(%s): pthread_mutex_destroy failed", cap, __func__);
|
||||
logerr (p, err2, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC);
|
||||
}
|
||||
|
||||
err0:
|
||||
logerr(p, err, "%s(%s): %s failed", cap, __func__, efunc);
|
||||
logerr (p, err, "%s(%s): %s failed", cap, AUDIO_FUNC, efunc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -94,13 +94,13 @@ int audio_pt_fini (struct audio_pt *p, const char *cap)
|
||||
|
||||
err = pthread_cond_destroy (&p->cond);
|
||||
if (err) {
|
||||
logerr(p, err, "%s(%s): pthread_cond_destroy failed", cap, __func__);
|
||||
logerr (p, err, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
err = pthread_mutex_destroy (&p->mutex);
|
||||
if (err) {
|
||||
logerr(p, err, "%s(%s): pthread_mutex_destroy failed", cap, __func__);
|
||||
logerr (p, err, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC);
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
@@ -112,7 +112,7 @@ int audio_pt_lock (struct audio_pt *p, const char *cap)
|
||||
|
||||
err = pthread_mutex_lock (&p->mutex);
|
||||
if (err) {
|
||||
logerr(p, err, "%s(%s): pthread_mutex_lock failed", cap, __func__);
|
||||
logerr (p, err, "%s(%s): pthread_mutex_lock failed", cap, AUDIO_FUNC);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -124,7 +124,7 @@ int audio_pt_unlock (struct audio_pt *p, const char *cap)
|
||||
|
||||
err = pthread_mutex_unlock (&p->mutex);
|
||||
if (err) {
|
||||
logerr(p, err, "%s(%s): pthread_mutex_unlock failed", cap, __func__);
|
||||
logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -136,7 +136,7 @@ int audio_pt_wait (struct audio_pt *p, const char *cap)
|
||||
|
||||
err = pthread_cond_wait (&p->cond, &p->mutex);
|
||||
if (err) {
|
||||
logerr(p, err, "%s(%s): pthread_cond_wait failed", cap, __func__);
|
||||
logerr (p, err, "%s(%s): pthread_cond_wait failed", cap, AUDIO_FUNC);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -148,12 +148,12 @@ int audio_pt_unlock_and_signal (struct audio_pt *p, const char *cap)
|
||||
|
||||
err = pthread_mutex_unlock (&p->mutex);
|
||||
if (err) {
|
||||
logerr(p, err, "%s(%s): pthread_mutex_unlock failed", cap, __func__);
|
||||
logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC);
|
||||
return -1;
|
||||
}
|
||||
err = pthread_cond_signal (&p->cond);
|
||||
if (err) {
|
||||
logerr(p, err, "%s(%s): pthread_cond_signal failed", cap, __func__);
|
||||
logerr (p, err, "%s(%s): pthread_cond_signal failed", cap, AUDIO_FUNC);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -166,7 +166,7 @@ int audio_pt_join (struct audio_pt *p, void **arg, const char *cap)
|
||||
|
||||
err = pthread_join (p->thread, &ret);
|
||||
if (err) {
|
||||
logerr(p, err, "%s(%s): pthread_join failed", cap, __func__);
|
||||
logerr (p, err, "%s(%s): pthread_join failed", cap, AUDIO_FUNC);
|
||||
return -1;
|
||||
}
|
||||
*arg = ret;
|
||||
|
@@ -57,13 +57,13 @@ static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv)
|
||||
glue (s->nb_hw_voices_, TYPE) = max_voices;
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, !voice_size && max_voices)) {
|
||||
if (audio_bug (AUDIO_FUNC, !voice_size && max_voices)) {
|
||||
dolog ("drv=`%s' voice_size=0 max_voices=%d\n",
|
||||
drv->name, max_voices);
|
||||
glue (s->nb_hw_voices_, TYPE) = 0;
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, voice_size && !max_voices)) {
|
||||
if (audio_bug (AUDIO_FUNC, voice_size && !max_voices)) {
|
||||
dolog ("drv=`%s' voice_size=%d max_voices=0\n",
|
||||
drv->name, voice_size);
|
||||
}
|
||||
@@ -77,7 +77,7 @@ static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
|
||||
|
||||
static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
|
||||
{
|
||||
HWBUF = audio_calloc(__func__, hw->samples, sizeof(struct st_sample));
|
||||
HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (struct st_sample));
|
||||
if (!HWBUF) {
|
||||
dolog ("Could not allocate " NAME " buffer (%d samples)\n",
|
||||
hw->samples);
|
||||
@@ -105,7 +105,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
|
||||
|
||||
samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
|
||||
|
||||
sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
|
||||
sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample));
|
||||
if (!sw->buf) {
|
||||
dolog ("Could not allocate buffer for `%s' (%d samples)\n",
|
||||
SW_NAME (sw), samples);
|
||||
@@ -238,17 +238,17 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, !drv)) {
|
||||
if (audio_bug (AUDIO_FUNC, !drv)) {
|
||||
dolog ("No host audio driver\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, !drv->pcm_ops)) {
|
||||
if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) {
|
||||
dolog ("Host audio driver without pcm_ops\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hw = audio_calloc(__func__, 1, glue(drv->voice_size_, TYPE));
|
||||
hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE));
|
||||
if (!hw) {
|
||||
dolog ("Can not allocate voice `%s' size %d\n",
|
||||
drv->name, glue (drv->voice_size_, TYPE));
|
||||
@@ -266,7 +266,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, hw->samples <= 0)) {
|
||||
if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) {
|
||||
dolog ("hw->samples=%d\n", hw->samples);
|
||||
goto err1;
|
||||
}
|
||||
@@ -339,7 +339,7 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
||||
hw_as = *as;
|
||||
}
|
||||
|
||||
sw = audio_calloc(__func__, 1, sizeof(*sw));
|
||||
sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw));
|
||||
if (!sw) {
|
||||
dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
|
||||
sw_name ? sw_name : "unknown", sizeof (*sw));
|
||||
@@ -379,7 +379,7 @@ static void glue (audio_close_, TYPE) (SW *sw)
|
||||
void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
|
||||
{
|
||||
if (sw) {
|
||||
if (audio_bug(__func__, !card)) {
|
||||
if (audio_bug (AUDIO_FUNC, !card)) {
|
||||
dolog ("card=%p\n", card);
|
||||
return;
|
||||
}
|
||||
@@ -399,7 +399,7 @@ SW *glue (AUD_open_, TYPE) (
|
||||
{
|
||||
AudioState *s = &glob_audio_state;
|
||||
|
||||
if (audio_bug(__func__, !card || !name || !callback_fn || !as)) {
|
||||
if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) {
|
||||
dolog ("card=%p name=%p callback_fn=%p as=%p\n",
|
||||
card, name, callback_fn, as);
|
||||
goto fail;
|
||||
@@ -408,12 +408,12 @@ SW *glue (AUD_open_, TYPE) (
|
||||
ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
|
||||
name, as->freq, as->nchannels, as->fmt);
|
||||
|
||||
if (audio_bug(__func__, audio_validate_settings(as))) {
|
||||
if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
|
||||
audio_print_settings (as);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, !s->drv)) {
|
||||
if (audio_bug (AUDIO_FUNC, !s->drv)) {
|
||||
dolog ("Can not open `%s' (no host audio driver)\n", name);
|
||||
goto fail;
|
||||
}
|
||||
|
@@ -543,7 +543,7 @@ static int dsound_run_out (HWVoiceOut *hw, int live)
|
||||
}
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, len < 0 || len > bufsize)) {
|
||||
if (audio_bug (AUDIO_FUNC, len < 0 || len > bufsize)) {
|
||||
dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n",
|
||||
len, bufsize, old_pos, ppos);
|
||||
return 0;
|
||||
|
@@ -344,7 +344,7 @@ struct rate {
|
||||
*/
|
||||
void *st_rate_start (int inrate, int outrate)
|
||||
{
|
||||
struct rate *rate = audio_calloc(__func__, 1, sizeof(*rate));
|
||||
struct rate *rate = audio_calloc (AUDIO_FUNC, 1, sizeof (*rate));
|
||||
|
||||
if (!rate) {
|
||||
dolog ("Could not allocate resampler (%zu bytes)\n", sizeof (*rate));
|
||||
|
@@ -582,9 +582,11 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
}
|
||||
|
||||
if (!oss->mmapped) {
|
||||
oss->pcm_buf = audio_calloc(__func__,
|
||||
hw->samples,
|
||||
1 << hw->info.shift);
|
||||
oss->pcm_buf = audio_calloc (
|
||||
AUDIO_FUNC,
|
||||
hw->samples,
|
||||
1 << hw->info.shift
|
||||
);
|
||||
if (!oss->pcm_buf) {
|
||||
dolog (
|
||||
"Could not allocate DAC buffer (%d samples, each %d bytes)\n",
|
||||
@@ -703,7 +705,7 @@ static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
}
|
||||
|
||||
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
|
||||
oss->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||
oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
|
||||
if (!oss->pcm_buf) {
|
||||
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
|
||||
hw->samples, 1 << hw->info.shift);
|
||||
|
@@ -89,7 +89,7 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
|
||||
} \
|
||||
goto label; \
|
||||
} \
|
||||
} while (0)
|
||||
} while (0);
|
||||
|
||||
#define CHECK_DEAD_GOTO(c, stream, rerror, label) \
|
||||
do { \
|
||||
@@ -107,7 +107,7 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
|
||||
} \
|
||||
goto label; \
|
||||
} \
|
||||
} while (0)
|
||||
} while (0);
|
||||
|
||||
static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
|
||||
{
|
||||
@@ -206,7 +206,7 @@ static void *qpa_thread_out (void *arg)
|
||||
PAVoiceOut *pa = arg;
|
||||
HWVoiceOut *hw = &pa->hw;
|
||||
|
||||
if (audio_pt_lock(&pa->pt, __func__)) {
|
||||
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ static void *qpa_thread_out (void *arg)
|
||||
break;
|
||||
}
|
||||
|
||||
if (audio_pt_wait(&pa->pt, __func__)) {
|
||||
if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
@@ -230,7 +230,7 @@ static void *qpa_thread_out (void *arg)
|
||||
decr = to_mix = audio_MIN (pa->live, pa->g->conf.samples >> 2);
|
||||
rpos = pa->rpos;
|
||||
|
||||
if (audio_pt_unlock(&pa->pt, __func__)) {
|
||||
if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ static void *qpa_thread_out (void *arg)
|
||||
to_mix -= chunk;
|
||||
}
|
||||
|
||||
if (audio_pt_lock(&pa->pt, __func__)) {
|
||||
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ static void *qpa_thread_out (void *arg)
|
||||
}
|
||||
|
||||
exit:
|
||||
audio_pt_unlock(&pa->pt, __func__);
|
||||
audio_pt_unlock (&pa->pt, AUDIO_FUNC);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ static int qpa_run_out (HWVoiceOut *hw, int live)
|
||||
int decr;
|
||||
PAVoiceOut *pa = (PAVoiceOut *) hw;
|
||||
|
||||
if (audio_pt_lock(&pa->pt, __func__)) {
|
||||
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -279,10 +279,10 @@ static int qpa_run_out (HWVoiceOut *hw, int live)
|
||||
pa->live = live - decr;
|
||||
hw->rpos = pa->rpos;
|
||||
if (pa->live > 0) {
|
||||
audio_pt_unlock_and_signal(&pa->pt, __func__);
|
||||
audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
|
||||
}
|
||||
else {
|
||||
audio_pt_unlock(&pa->pt, __func__);
|
||||
audio_pt_unlock (&pa->pt, AUDIO_FUNC);
|
||||
}
|
||||
return decr;
|
||||
}
|
||||
@@ -298,7 +298,7 @@ static void *qpa_thread_in (void *arg)
|
||||
PAVoiceIn *pa = arg;
|
||||
HWVoiceIn *hw = &pa->hw;
|
||||
|
||||
if (audio_pt_lock(&pa->pt, __func__)) {
|
||||
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -314,7 +314,7 @@ static void *qpa_thread_in (void *arg)
|
||||
break;
|
||||
}
|
||||
|
||||
if (audio_pt_wait(&pa->pt, __func__)) {
|
||||
if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
@@ -322,7 +322,7 @@ static void *qpa_thread_in (void *arg)
|
||||
incr = to_grab = audio_MIN (pa->dead, pa->g->conf.samples >> 2);
|
||||
wpos = pa->wpos;
|
||||
|
||||
if (audio_pt_unlock(&pa->pt, __func__)) {
|
||||
if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ static void *qpa_thread_in (void *arg)
|
||||
to_grab -= chunk;
|
||||
}
|
||||
|
||||
if (audio_pt_lock(&pa->pt, __func__)) {
|
||||
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ static void *qpa_thread_in (void *arg)
|
||||
}
|
||||
|
||||
exit:
|
||||
audio_pt_unlock(&pa->pt, __func__);
|
||||
audio_pt_unlock (&pa->pt, AUDIO_FUNC);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -361,7 +361,7 @@ static int qpa_run_in (HWVoiceIn *hw)
|
||||
int live, incr, dead;
|
||||
PAVoiceIn *pa = (PAVoiceIn *) hw;
|
||||
|
||||
if (audio_pt_lock(&pa->pt, __func__)) {
|
||||
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -372,10 +372,10 @@ static int qpa_run_in (HWVoiceIn *hw)
|
||||
pa->dead = dead - incr;
|
||||
hw->wpos = pa->wpos;
|
||||
if (pa->dead > 0) {
|
||||
audio_pt_unlock_and_signal(&pa->pt, __func__);
|
||||
audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
|
||||
}
|
||||
else {
|
||||
audio_pt_unlock(&pa->pt, __func__);
|
||||
audio_pt_unlock (&pa->pt, AUDIO_FUNC);
|
||||
}
|
||||
return incr;
|
||||
}
|
||||
@@ -579,7 +579,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
hw->samples = g->conf.samples;
|
||||
pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||
pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
|
||||
pa->rpos = hw->rpos;
|
||||
if (!pa->pcm_buf) {
|
||||
dolog ("Could not allocate buffer (%d bytes)\n",
|
||||
@@ -587,7 +587,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
if (audio_pt_init(&pa->pt, qpa_thread_out, hw, AUDIO_CAP, __func__)) {
|
||||
if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) {
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
@@ -636,7 +636,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
hw->samples = g->conf.samples;
|
||||
pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||
pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
|
||||
pa->wpos = hw->wpos;
|
||||
if (!pa->pcm_buf) {
|
||||
dolog ("Could not allocate buffer (%d bytes)\n",
|
||||
@@ -644,7 +644,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
if (audio_pt_init(&pa->pt, qpa_thread_in, hw, AUDIO_CAP, __func__)) {
|
||||
if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) {
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
@@ -667,17 +667,17 @@ static void qpa_fini_out (HWVoiceOut *hw)
|
||||
void *ret;
|
||||
PAVoiceOut *pa = (PAVoiceOut *) hw;
|
||||
|
||||
audio_pt_lock(&pa->pt, __func__);
|
||||
audio_pt_lock (&pa->pt, AUDIO_FUNC);
|
||||
pa->done = 1;
|
||||
audio_pt_unlock_and_signal(&pa->pt, __func__);
|
||||
audio_pt_join(&pa->pt, &ret, __func__);
|
||||
audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
|
||||
audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
|
||||
|
||||
if (pa->stream) {
|
||||
pa_stream_unref (pa->stream);
|
||||
pa->stream = NULL;
|
||||
}
|
||||
|
||||
audio_pt_fini(&pa->pt, __func__);
|
||||
audio_pt_fini (&pa->pt, AUDIO_FUNC);
|
||||
g_free (pa->pcm_buf);
|
||||
pa->pcm_buf = NULL;
|
||||
}
|
||||
@@ -687,17 +687,17 @@ static void qpa_fini_in (HWVoiceIn *hw)
|
||||
void *ret;
|
||||
PAVoiceIn *pa = (PAVoiceIn *) hw;
|
||||
|
||||
audio_pt_lock(&pa->pt, __func__);
|
||||
audio_pt_lock (&pa->pt, AUDIO_FUNC);
|
||||
pa->done = 1;
|
||||
audio_pt_unlock_and_signal(&pa->pt, __func__);
|
||||
audio_pt_join(&pa->pt, &ret, __func__);
|
||||
audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
|
||||
audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
|
||||
|
||||
if (pa->stream) {
|
||||
pa_stream_unref (pa->stream);
|
||||
pa->stream = NULL;
|
||||
}
|
||||
|
||||
audio_pt_fini(&pa->pt, __func__);
|
||||
audio_pt_fini (&pa->pt, AUDIO_FUNC);
|
||||
g_free (pa->pcm_buf);
|
||||
pa->pcm_buf = NULL;
|
||||
}
|
||||
|
@@ -277,7 +277,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||
return;
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, sdl->live < 0 || sdl->live > hw->samples)) {
|
||||
if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) {
|
||||
dolog ("sdl->live=%d hw->samples=%d\n",
|
||||
sdl->live, hw->samples);
|
||||
return;
|
||||
|
@@ -139,7 +139,7 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
audio_pcm_init_info (&hw->info, &wav_as);
|
||||
|
||||
hw->samples = 1024;
|
||||
wav->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||
wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
|
||||
if (!wav->pcm_buf) {
|
||||
dolog ("Could not allocate buffer (%d bytes)\n",
|
||||
hw->samples << hw->info.shift);
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "audio.h"
|
||||
|
||||
|
@@ -8,5 +8,3 @@ common-obj-$(CONFIG_LINUX) += hostmem-file.o
|
||||
|
||||
common-obj-y += cryptodev.o
|
||||
common-obj-y += cryptodev-builtin.o
|
||||
|
||||
common-obj-$(CONFIG_LINUX) += hostmem-memfd.o
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "hw/boards.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi-types.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
|
@@ -31,9 +31,9 @@ typedef struct HostMemoryBackendFile HostMemoryBackendFile;
|
||||
struct HostMemoryBackendFile {
|
||||
HostMemoryBackend parent_obj;
|
||||
|
||||
bool share;
|
||||
bool discard_data;
|
||||
char *mem_path;
|
||||
uint64_t align;
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -58,7 +58,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
path = object_get_canonical_path(OBJECT(backend));
|
||||
memory_region_init_ram_from_file(&backend->mr, OBJECT(backend),
|
||||
path,
|
||||
backend->size, fb->align, backend->share,
|
||||
backend->size, fb->share,
|
||||
fb->mem_path, errp);
|
||||
g_free(path);
|
||||
}
|
||||
@@ -85,6 +85,25 @@ static void set_mem_path(Object *o, const char *str, Error **errp)
|
||||
fb->mem_path = g_strdup(str);
|
||||
}
|
||||
|
||||
static bool file_memory_backend_get_share(Object *o, Error **errp)
|
||||
{
|
||||
HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
|
||||
|
||||
return fb->share;
|
||||
}
|
||||
|
||||
static void file_memory_backend_set_share(Object *o, bool value, Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(o);
|
||||
HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
|
||||
|
||||
if (host_memory_backend_mr_inited(backend)) {
|
||||
error_setg(errp, "cannot change property value");
|
||||
return;
|
||||
}
|
||||
fb->share = value;
|
||||
}
|
||||
|
||||
static bool file_memory_backend_get_discard_data(Object *o, Error **errp)
|
||||
{
|
||||
return MEMORY_BACKEND_FILE(o)->discard_data;
|
||||
@@ -96,40 +115,6 @@ static void file_memory_backend_set_discard_data(Object *o, bool value,
|
||||
MEMORY_BACKEND_FILE(o)->discard_data = value;
|
||||
}
|
||||
|
||||
static void file_memory_backend_get_align(Object *o, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
|
||||
uint64_t val = fb->align;
|
||||
|
||||
visit_type_size(v, name, &val, errp);
|
||||
}
|
||||
|
||||
static void file_memory_backend_set_align(Object *o, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(o);
|
||||
HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
|
||||
Error *local_err = NULL;
|
||||
uint64_t val;
|
||||
|
||||
if (host_memory_backend_mr_inited(backend)) {
|
||||
error_setg(&local_err, "cannot change property value");
|
||||
goto out;
|
||||
}
|
||||
|
||||
visit_type_size(v, name, &val, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
fb->align = val;
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static void file_backend_unparent(Object *obj)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
@@ -151,16 +136,15 @@ file_backend_class_init(ObjectClass *oc, void *data)
|
||||
bc->alloc = file_backend_memory_alloc;
|
||||
oc->unparent = file_backend_unparent;
|
||||
|
||||
object_class_property_add_bool(oc, "share",
|
||||
file_memory_backend_get_share, file_memory_backend_set_share,
|
||||
&error_abort);
|
||||
object_class_property_add_bool(oc, "discard-data",
|
||||
file_memory_backend_get_discard_data, file_memory_backend_set_discard_data,
|
||||
&error_abort);
|
||||
object_class_property_add_str(oc, "mem-path",
|
||||
get_mem_path, set_mem_path,
|
||||
&error_abort);
|
||||
object_class_property_add(oc, "align", "int",
|
||||
file_memory_backend_get_align,
|
||||
file_memory_backend_set_align,
|
||||
NULL, NULL, &error_abort);
|
||||
}
|
||||
|
||||
static void file_backend_instance_finalize(Object *o)
|
||||
|
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* QEMU host memfd memory backend
|
||||
*
|
||||
* Copyright (C) 2018 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-common.h"
|
||||
#include "sysemu/hostmem.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qemu/memfd.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#define TYPE_MEMORY_BACKEND_MEMFD "memory-backend-memfd"
|
||||
|
||||
#define MEMORY_BACKEND_MEMFD(obj) \
|
||||
OBJECT_CHECK(HostMemoryBackendMemfd, (obj), TYPE_MEMORY_BACKEND_MEMFD)
|
||||
|
||||
typedef struct HostMemoryBackendMemfd HostMemoryBackendMemfd;
|
||||
|
||||
struct HostMemoryBackendMemfd {
|
||||
HostMemoryBackend parent_obj;
|
||||
|
||||
bool hugetlb;
|
||||
uint64_t hugetlbsize;
|
||||
bool seal;
|
||||
};
|
||||
|
||||
static void
|
||||
memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
{
|
||||
HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(backend);
|
||||
char *name;
|
||||
int fd;
|
||||
|
||||
if (!backend->size) {
|
||||
error_setg(errp, "can't create backend with size 0");
|
||||
return;
|
||||
}
|
||||
|
||||
if (host_memory_backend_mr_inited(backend)) {
|
||||
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,
|
||||
errp);
|
||||
if (fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
name = object_get_canonical_path(OBJECT(backend));
|
||||
memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
|
||||
name, backend->size, true, fd, errp);
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
static bool
|
||||
memfd_backend_get_hugetlb(Object *o, Error **errp)
|
||||
{
|
||||
return MEMORY_BACKEND_MEMFD(o)->hugetlb;
|
||||
}
|
||||
|
||||
static void
|
||||
memfd_backend_set_hugetlb(Object *o, bool value, Error **errp)
|
||||
{
|
||||
MEMORY_BACKEND_MEMFD(o)->hugetlb = value;
|
||||
}
|
||||
|
||||
static void
|
||||
memfd_backend_set_hugetlbsize(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj);
|
||||
Error *local_err = NULL;
|
||||
uint64_t value;
|
||||
|
||||
if (host_memory_backend_mr_inited(MEMORY_BACKEND(obj))) {
|
||||
error_setg(&local_err, "cannot change property value");
|
||||
goto out;
|
||||
}
|
||||
|
||||
visit_type_size(v, name, &value, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
if (!value) {
|
||||
error_setg(&local_err, "Property '%s.%s' doesn't take value '%"
|
||||
PRIu64 "'", object_get_typename(obj), name, value);
|
||||
goto out;
|
||||
}
|
||||
m->hugetlbsize = value;
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static void
|
||||
memfd_backend_get_hugetlbsize(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj);
|
||||
uint64_t value = m->hugetlbsize;
|
||||
|
||||
visit_type_size(v, name, &value, errp);
|
||||
}
|
||||
|
||||
static bool
|
||||
memfd_backend_get_seal(Object *o, Error **errp)
|
||||
{
|
||||
return MEMORY_BACKEND_MEMFD(o)->seal;
|
||||
}
|
||||
|
||||
static void
|
||||
memfd_backend_set_seal(Object *o, bool value, Error **errp)
|
||||
{
|
||||
MEMORY_BACKEND_MEMFD(o)->seal = value;
|
||||
}
|
||||
|
||||
static void
|
||||
memfd_backend_instance_init(Object *obj)
|
||||
{
|
||||
HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj);
|
||||
|
||||
/* default to sealed file */
|
||||
m->seal = true;
|
||||
}
|
||||
|
||||
static void
|
||||
memfd_backend_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
|
||||
|
||||
bc->alloc = memfd_backend_memory_alloc;
|
||||
|
||||
object_class_property_add_bool(oc, "hugetlb",
|
||||
memfd_backend_get_hugetlb,
|
||||
memfd_backend_set_hugetlb,
|
||||
&error_abort);
|
||||
object_class_property_add(oc, "hugetlbsize", "int",
|
||||
memfd_backend_get_hugetlbsize,
|
||||
memfd_backend_set_hugetlbsize,
|
||||
NULL, NULL, &error_abort);
|
||||
object_class_property_add_bool(oc, "seal",
|
||||
memfd_backend_get_seal,
|
||||
memfd_backend_set_seal,
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static const TypeInfo memfd_backend_info = {
|
||||
.name = TYPE_MEMORY_BACKEND_MEMFD,
|
||||
.parent = TYPE_MEMORY_BACKEND,
|
||||
.instance_init = memfd_backend_instance_init,
|
||||
.class_init = memfd_backend_class_init,
|
||||
.instance_size = sizeof(HostMemoryBackendMemfd),
|
||||
};
|
||||
|
||||
static void register_types(void)
|
||||
{
|
||||
type_register_static(&memfd_backend_info);
|
||||
}
|
||||
|
||||
type_init(register_types);
|
@@ -28,8 +28,8 @@ ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
}
|
||||
|
||||
path = object_get_canonical_path_component(OBJECT(backend));
|
||||
memory_region_init_ram_shared_nomigrate(&backend->mr, OBJECT(backend), path,
|
||||
backend->size, backend->share, errp);
|
||||
memory_region_init_ram_nomigrate(&backend->mr, OBJECT(backend), path,
|
||||
backend->size, errp);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include "hw/boards.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi-types.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
@@ -368,24 +369,6 @@ static void set_id(Object *o, const char *str, Error **errp)
|
||||
backend->id = g_strdup(str);
|
||||
}
|
||||
|
||||
static bool host_memory_backend_get_share(Object *o, Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(o);
|
||||
|
||||
return backend->share;
|
||||
}
|
||||
|
||||
static void host_memory_backend_set_share(Object *o, bool value, Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(o);
|
||||
|
||||
if (host_memory_backend_mr_inited(backend)) {
|
||||
error_setg(errp, "cannot change property value");
|
||||
return;
|
||||
}
|
||||
backend->share = value;
|
||||
}
|
||||
|
||||
static void
|
||||
host_memory_backend_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
@@ -416,9 +399,6 @@ host_memory_backend_class_init(ObjectClass *oc, void *data)
|
||||
host_memory_backend_get_policy,
|
||||
host_memory_backend_set_policy, &error_abort);
|
||||
object_class_property_add_str(oc, "id", get_id, set_id, &error_abort);
|
||||
object_class_property_add_bool(oc, "share",
|
||||
host_memory_backend_get_share, host_memory_backend_set_share,
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static void host_memory_backend_finalize(Object *o)
|
||||
|
144
backends/tpm.c
144
backends/tpm.c
@@ -15,43 +15,25 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "sysemu/tpm_backend.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "sysemu/tpm.h"
|
||||
#include "hw/tpm/tpm_int.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "block/thread-pool.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
static void tpm_backend_request_completed(void *opaque, int ret)
|
||||
static void tpm_backend_worker_thread(gpointer data, gpointer user_data)
|
||||
{
|
||||
TPMBackend *s = TPM_BACKEND(opaque);
|
||||
TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif);
|
||||
TPMBackend *s = TPM_BACKEND(user_data);
|
||||
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
|
||||
|
||||
tic->request_completed(s->tpmif, ret);
|
||||
|
||||
/* no need for atomic, as long the BQL is taken */
|
||||
s->cmd = NULL;
|
||||
object_unref(OBJECT(s));
|
||||
assert(k->handle_request != NULL);
|
||||
k->handle_request(s, (TPMBackendCmd *)data);
|
||||
}
|
||||
|
||||
static int tpm_backend_worker_thread(gpointer data)
|
||||
static void tpm_backend_thread_end(TPMBackend *s)
|
||||
{
|
||||
TPMBackend *s = TPM_BACKEND(data);
|
||||
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
|
||||
Error *err = NULL;
|
||||
|
||||
k->handle_request(s, s->cmd, &err);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tpm_backend_finish_sync(TPMBackend *s)
|
||||
{
|
||||
while (s->cmd) {
|
||||
aio_poll(qemu_get_aio_context(), true);
|
||||
if (s->thread_pool) {
|
||||
g_thread_pool_free(s->thread_pool, FALSE, TRUE);
|
||||
s->thread_pool = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,30 +44,26 @@ enum TpmType tpm_backend_get_type(TPMBackend *s)
|
||||
return k->type;
|
||||
}
|
||||
|
||||
int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp)
|
||||
int tpm_backend_init(TPMBackend *s, TPMState *state)
|
||||
{
|
||||
if (s->tpmif) {
|
||||
error_setg(errp, "TPM backend '%s' is already initialized", s->id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->tpmif = tpmif;
|
||||
object_ref(OBJECT(tpmif));
|
||||
|
||||
s->tpm_state = state;
|
||||
s->had_startup_error = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize)
|
||||
int tpm_backend_startup_tpm(TPMBackend *s)
|
||||
{
|
||||
int res = 0;
|
||||
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
|
||||
|
||||
/* terminate a running TPM */
|
||||
tpm_backend_finish_sync(s);
|
||||
tpm_backend_thread_end(s);
|
||||
|
||||
res = k->startup_tpm ? k->startup_tpm(s, buffersize) : 0;
|
||||
s->thread_pool = g_thread_pool_new(tpm_backend_worker_thread, s, 1, TRUE,
|
||||
NULL);
|
||||
|
||||
res = k->startup_tpm ? k->startup_tpm(s) : 0;
|
||||
|
||||
s->had_startup_error = (res != 0);
|
||||
|
||||
@@ -99,17 +77,7 @@ bool tpm_backend_had_startup_error(TPMBackend *s)
|
||||
|
||||
void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd)
|
||||
{
|
||||
ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
|
||||
|
||||
if (s->cmd != NULL) {
|
||||
error_report("There is a TPM request pending");
|
||||
return;
|
||||
}
|
||||
|
||||
s->cmd = cmd;
|
||||
object_ref(OBJECT(s));
|
||||
thread_pool_submit_aio(pool, tpm_backend_worker_thread, s,
|
||||
tpm_backend_request_completed, s);
|
||||
g_thread_pool_push(s->thread_pool, cmd, NULL);
|
||||
}
|
||||
|
||||
void tpm_backend_reset(TPMBackend *s)
|
||||
@@ -120,7 +88,7 @@ void tpm_backend_reset(TPMBackend *s)
|
||||
k->reset(s);
|
||||
}
|
||||
|
||||
tpm_backend_finish_sync(s);
|
||||
tpm_backend_thread_end(s);
|
||||
|
||||
s->had_startup_error = false;
|
||||
}
|
||||
@@ -129,6 +97,8 @@ void tpm_backend_cancel_cmd(TPMBackend *s)
|
||||
{
|
||||
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
|
||||
|
||||
assert(k->cancel_cmd);
|
||||
|
||||
k->cancel_cmd(s);
|
||||
}
|
||||
|
||||
@@ -152,41 +122,87 @@ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)
|
||||
{
|
||||
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
|
||||
|
||||
assert(k->get_tpm_version);
|
||||
|
||||
return k->get_tpm_version(s);
|
||||
}
|
||||
|
||||
size_t tpm_backend_get_buffer_size(TPMBackend *s)
|
||||
{
|
||||
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
|
||||
|
||||
return k->get_buffer_size(s);
|
||||
}
|
||||
|
||||
TPMInfo *tpm_backend_query_tpm(TPMBackend *s)
|
||||
{
|
||||
TPMInfo *info = g_new0(TPMInfo, 1);
|
||||
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
|
||||
TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif);
|
||||
|
||||
info->id = g_strdup(s->id);
|
||||
info->model = tic->model;
|
||||
info->options = k->get_tpm_options(s);
|
||||
info->model = s->fe_model;
|
||||
if (k->get_tpm_options) {
|
||||
info->options = k->get_tpm_options(s);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
|
||||
{
|
||||
TPMBackend *s = TPM_BACKEND(obj);
|
||||
|
||||
return s->opened;
|
||||
}
|
||||
|
||||
void tpm_backend_open(TPMBackend *s, Error **errp)
|
||||
{
|
||||
object_property_set_bool(OBJECT(s), true, "opened", errp);
|
||||
}
|
||||
|
||||
static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
TPMBackend *s = TPM_BACKEND(obj);
|
||||
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (value == s->opened) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!value && s->opened) {
|
||||
error_setg(errp, QERR_PERMISSION_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (k->opened) {
|
||||
k->opened(s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
s->opened = true;
|
||||
}
|
||||
|
||||
static void tpm_backend_instance_init(Object *obj)
|
||||
{
|
||||
TPMBackend *s = TPM_BACKEND(obj);
|
||||
|
||||
object_property_add_bool(obj, "opened",
|
||||
tpm_backend_prop_get_opened,
|
||||
tpm_backend_prop_set_opened,
|
||||
NULL);
|
||||
s->fe_model = -1;
|
||||
}
|
||||
|
||||
static void tpm_backend_instance_finalize(Object *obj)
|
||||
{
|
||||
TPMBackend *s = TPM_BACKEND(obj);
|
||||
|
||||
object_unref(OBJECT(s->tpmif));
|
||||
g_free(s->id);
|
||||
tpm_backend_thread_end(s);
|
||||
}
|
||||
|
||||
static const TypeInfo tpm_backend_info = {
|
||||
.name = TYPE_TPM_BACKEND,
|
||||
.parent = TYPE_OBJECT,
|
||||
.instance_size = sizeof(TPMBackend),
|
||||
.instance_init = tpm_backend_instance_init,
|
||||
.instance_finalize = tpm_backend_instance_finalize,
|
||||
.class_size = sizeof(TPMBackendClass),
|
||||
.abstract = true,
|
||||
|
@@ -31,8 +31,8 @@
|
||||
#include "sysemu/balloon.h"
|
||||
#include "trace-root.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
|
||||
static QEMUBalloonEvent *balloon_event_fn;
|
||||
static QEMUBalloonStatus *balloon_stat_fn;
|
||||
|
101
block.c
101
block.c
@@ -21,7 +21,6 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "block/trace.h"
|
||||
#include "block/block_int.h"
|
||||
@@ -30,17 +29,15 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "module_block.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/notify.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/coroutine.h"
|
||||
#include "block/qapi.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qapi-event.h"
|
||||
#include "qemu/cutils.h"
|
||||
@@ -825,18 +822,6 @@ static void bdrv_child_cb_drained_end(BdrvChild *child)
|
||||
bdrv_drained_end(bs);
|
||||
}
|
||||
|
||||
static void bdrv_child_cb_attach(BdrvChild *child)
|
||||
{
|
||||
BlockDriverState *bs = child->opaque;
|
||||
bdrv_apply_subtree_drain(child, bs);
|
||||
}
|
||||
|
||||
static void bdrv_child_cb_detach(BdrvChild *child)
|
||||
{
|
||||
BlockDriverState *bs = child->opaque;
|
||||
bdrv_unapply_subtree_drain(child, bs);
|
||||
}
|
||||
|
||||
static int bdrv_child_cb_inactivate(BdrvChild *child)
|
||||
{
|
||||
BlockDriverState *bs = child->opaque;
|
||||
@@ -904,8 +889,6 @@ const BdrvChildRole child_file = {
|
||||
.inherit_options = bdrv_inherited_options,
|
||||
.drained_begin = bdrv_child_cb_drained_begin,
|
||||
.drained_end = bdrv_child_cb_drained_end,
|
||||
.attach = bdrv_child_cb_attach,
|
||||
.detach = bdrv_child_cb_detach,
|
||||
.inactivate = bdrv_child_cb_inactivate,
|
||||
};
|
||||
|
||||
@@ -928,8 +911,6 @@ const BdrvChildRole child_format = {
|
||||
.inherit_options = bdrv_inherited_fmt_options,
|
||||
.drained_begin = bdrv_child_cb_drained_begin,
|
||||
.drained_end = bdrv_child_cb_drained_end,
|
||||
.attach = bdrv_child_cb_attach,
|
||||
.detach = bdrv_child_cb_detach,
|
||||
.inactivate = bdrv_child_cb_inactivate,
|
||||
};
|
||||
|
||||
@@ -972,8 +953,6 @@ static void bdrv_backing_attach(BdrvChild *c)
|
||||
parent->backing_blocker);
|
||||
bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_TARGET,
|
||||
parent->backing_blocker);
|
||||
|
||||
bdrv_child_cb_attach(c);
|
||||
}
|
||||
|
||||
static void bdrv_backing_detach(BdrvChild *c)
|
||||
@@ -984,8 +963,6 @@ static void bdrv_backing_detach(BdrvChild *c)
|
||||
bdrv_op_unblock_all(c->bs, parent->backing_blocker);
|
||||
error_free(parent->backing_blocker);
|
||||
parent->backing_blocker = NULL;
|
||||
|
||||
bdrv_child_cb_detach(c);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1947,8 +1924,6 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
|
||||
assert(role == &child_backing || role == &child_file);
|
||||
|
||||
if (!backing) {
|
||||
int flags = bdrv_reopen_get_flags(reopen_queue, bs);
|
||||
|
||||
/* Apart from the modifications below, the same permissions are
|
||||
* forwarded and left alone as for filters */
|
||||
bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
|
||||
@@ -1961,9 +1936,7 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
|
||||
|
||||
/* bs->file always needs to be consistent because of the metadata. We
|
||||
* can never allow other users to resize or write to it. */
|
||||
if (!(flags & BDRV_O_NO_IO)) {
|
||||
perm |= BLK_PERM_CONSISTENT_READ;
|
||||
}
|
||||
perm |= BLK_PERM_CONSISTENT_READ;
|
||||
shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
|
||||
} else {
|
||||
/* We want consistent read from backing files if the parent needs it.
|
||||
@@ -1995,23 +1968,17 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
|
||||
BlockDriverState *new_bs)
|
||||
{
|
||||
BlockDriverState *old_bs = child->bs;
|
||||
int i;
|
||||
|
||||
if (old_bs && new_bs) {
|
||||
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
|
||||
}
|
||||
if (old_bs) {
|
||||
/* Detach first so that the recursive drain sections coming from @child
|
||||
* are already gone and we only end the drain sections that came from
|
||||
* elsewhere. */
|
||||
if (old_bs->quiesce_counter && child->role->drained_end) {
|
||||
child->role->drained_end(child);
|
||||
}
|
||||
if (child->role->detach) {
|
||||
child->role->detach(child);
|
||||
}
|
||||
if (old_bs->quiesce_counter && child->role->drained_end) {
|
||||
for (i = 0; i < old_bs->quiesce_counter; i++) {
|
||||
child->role->drained_end(child);
|
||||
}
|
||||
}
|
||||
QLIST_REMOVE(child, next_parent);
|
||||
}
|
||||
|
||||
@@ -2020,14 +1987,9 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
|
||||
if (new_bs) {
|
||||
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
|
||||
if (new_bs->quiesce_counter && child->role->drained_begin) {
|
||||
for (i = 0; i < new_bs->quiesce_counter; i++) {
|
||||
child->role->drained_begin(child);
|
||||
}
|
||||
child->role->drained_begin(child);
|
||||
}
|
||||
|
||||
/* Attach only after starting new drained sections, so that recursive
|
||||
* drain sections coming from @child don't get an extra .drained_begin
|
||||
* callback. */
|
||||
if (child->role->attach) {
|
||||
child->role->attach(child);
|
||||
}
|
||||
@@ -2769,7 +2731,6 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
|
||||
* returns a pointer to bs_queue, which is either the newly allocated
|
||||
* bs_queue, or the existing bs_queue being used.
|
||||
*
|
||||
* bs must be drained between bdrv_reopen_queue() and bdrv_reopen_multiple().
|
||||
*/
|
||||
static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
|
||||
BlockDriverState *bs,
|
||||
@@ -2785,11 +2746,6 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
|
||||
BdrvChild *child;
|
||||
QDict *old_options, *explicit_options;
|
||||
|
||||
/* Make sure that the caller remembered to use a drained section. This is
|
||||
* important to avoid graph changes between the recursive queuing here and
|
||||
* bdrv_reopen_multiple(). */
|
||||
assert(bs->quiesce_counter > 0);
|
||||
|
||||
if (bs_queue == NULL) {
|
||||
bs_queue = g_new0(BlockReopenQueue, 1);
|
||||
QSIMPLEQ_INIT(bs_queue);
|
||||
@@ -2914,8 +2870,6 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
|
||||
* If all devices prepare successfully, then the changes are committed
|
||||
* to all devices.
|
||||
*
|
||||
* All affected nodes must be drained between bdrv_reopen_queue() and
|
||||
* bdrv_reopen_multiple().
|
||||
*/
|
||||
int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp)
|
||||
{
|
||||
@@ -2925,8 +2879,11 @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er
|
||||
|
||||
assert(bs_queue != NULL);
|
||||
|
||||
aio_context_release(ctx);
|
||||
bdrv_drain_all_begin();
|
||||
aio_context_acquire(ctx);
|
||||
|
||||
QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
|
||||
assert(bs_entry->state.bs->quiesce_counter > 0);
|
||||
if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, &local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
goto cleanup;
|
||||
@@ -2955,6 +2912,8 @@ cleanup:
|
||||
}
|
||||
g_free(bs_queue);
|
||||
|
||||
bdrv_drain_all_end();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2964,18 +2923,12 @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp)
|
||||
{
|
||||
int ret = -1;
|
||||
Error *local_err = NULL;
|
||||
BlockReopenQueue *queue;
|
||||
BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
|
||||
|
||||
bdrv_subtree_drained_begin(bs);
|
||||
|
||||
queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
|
||||
ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
bdrv_subtree_drained_end(bs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -4010,11 +3963,17 @@ bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs)
|
||||
|
||||
bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs)
|
||||
{
|
||||
BlockDriverInfo bdi;
|
||||
|
||||
if (!(bs->open_flags & BDRV_O_UNMAP)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bs->supported_zero_flags & BDRV_REQ_MAY_UNMAP;
|
||||
if (bdrv_get_info(bs, &bdi) == 0) {
|
||||
return bdi.can_write_zeroes_with_unmap;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
|
||||
@@ -4361,15 +4320,9 @@ int bdrv_inactivate_all(void)
|
||||
BdrvNextIterator it;
|
||||
int ret = 0;
|
||||
int pass;
|
||||
GSList *aio_ctxs = NULL, *ctx;
|
||||
|
||||
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
if (!g_slist_find(aio_ctxs, aio_context)) {
|
||||
aio_ctxs = g_slist_prepend(aio_ctxs, aio_context);
|
||||
aio_context_acquire(aio_context);
|
||||
}
|
||||
aio_context_acquire(bdrv_get_aio_context(bs));
|
||||
}
|
||||
|
||||
/* We do two passes of inactivation. The first pass calls to drivers'
|
||||
@@ -4387,11 +4340,9 @@ int bdrv_inactivate_all(void)
|
||||
}
|
||||
|
||||
out:
|
||||
for (ctx = aio_ctxs; ctx != NULL; ctx = ctx->next) {
|
||||
AioContext *aio_context = ctx->data;
|
||||
aio_context_release(aio_context);
|
||||
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
||||
aio_context_release(bdrv_get_aio_context(bs));
|
||||
}
|
||||
g_slist_free(aio_ctxs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -4796,7 +4747,7 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
|
||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_disable_external(ctx);
|
||||
bdrv_parent_drained_begin(bs, NULL);
|
||||
bdrv_parent_drained_begin(bs);
|
||||
bdrv_drain(bs); /* ensure there are no in-flight requests */
|
||||
|
||||
while (aio_poll(ctx, false)) {
|
||||
@@ -4810,7 +4761,7 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
|
||||
*/
|
||||
aio_context_acquire(new_context);
|
||||
bdrv_attach_aio_context(bs, new_context);
|
||||
bdrv_parent_drained_end(bs, NULL);
|
||||
bdrv_parent_drained_end(bs);
|
||||
aio_enable_external(ctx);
|
||||
aio_context_release(new_context);
|
||||
}
|
||||
|
@@ -11,7 +11,6 @@ block-obj-$(CONFIG_POSIX) += file-posix.o
|
||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
block-obj-y += null.o mirror.o commit.o io.o
|
||||
block-obj-y += throttle-groups.o
|
||||
block-obj-$(CONFIG_LINUX) += nvme.o
|
||||
|
||||
block-obj-y += nbd.o nbd-client.o sheepdog.o
|
||||
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
|
||||
@@ -48,5 +47,3 @@ block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
|
||||
dmg-bz2.o-libs := $(BZIP2_LIBS)
|
||||
qcow.o-libs := -lz
|
||||
linux-aio.o-libs := -laio
|
||||
parallels.o-cflags := $(LIBXML2_CFLAGS)
|
||||
parallels.o-libs := $(LIBXML2_LIBS)
|
||||
|
118
block/backup.c
118
block/backup.c
@@ -40,12 +40,11 @@ typedef struct BackupBlockJob {
|
||||
BlockdevOnError on_target_error;
|
||||
CoRwlock flush_rwlock;
|
||||
uint64_t bytes_read;
|
||||
unsigned long *done_bitmap;
|
||||
int64_t cluster_size;
|
||||
bool compress;
|
||||
NotifierWithReturn before_write;
|
||||
QLIST_HEAD(, CowRequest) inflight_reqs;
|
||||
|
||||
HBitmap *copy_bitmap;
|
||||
} BackupBlockJob;
|
||||
|
||||
/* See if in-flight requests overlap and wait for them to complete */
|
||||
@@ -110,11 +109,10 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
|
||||
cow_request_begin(&cow_request, job, start, end);
|
||||
|
||||
for (; start < end; start += job->cluster_size) {
|
||||
if (!hbitmap_get(job->copy_bitmap, start / job->cluster_size)) {
|
||||
if (test_bit(start / job->cluster_size, job->done_bitmap)) {
|
||||
trace_backup_do_cow_skip(job, start);
|
||||
continue; /* already copied */
|
||||
}
|
||||
hbitmap_reset(job->copy_bitmap, start / job->cluster_size, 1);
|
||||
|
||||
trace_backup_do_cow_process(job, start);
|
||||
|
||||
@@ -134,7 +132,6 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
|
||||
if (error_is_read) {
|
||||
*error_is_read = true;
|
||||
}
|
||||
hbitmap_set(job->copy_bitmap, start / job->cluster_size, 1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -151,10 +148,11 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
|
||||
if (error_is_read) {
|
||||
*error_is_read = false;
|
||||
}
|
||||
hbitmap_set(job->copy_bitmap, start / job->cluster_size, 1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
set_bit(start / job->cluster_size, job->done_bitmap);
|
||||
|
||||
/* Publish progress, guest I/O counts as progress too. Note that the
|
||||
* offset field is an opaque progress value, it is not a disk offset.
|
||||
*/
|
||||
@@ -262,7 +260,7 @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
|
||||
}
|
||||
|
||||
len = DIV_ROUND_UP(backup_job->common.len, backup_job->cluster_size);
|
||||
hbitmap_set(backup_job->copy_bitmap, 0, len);
|
||||
bitmap_zero(backup_job->done_bitmap, len);
|
||||
}
|
||||
|
||||
void backup_wait_for_overlapping_requests(BlockJob *job, int64_t offset,
|
||||
@@ -362,68 +360,64 @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job)
|
||||
|
||||
static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
|
||||
{
|
||||
int ret;
|
||||
bool error_is_read;
|
||||
int64_t cluster;
|
||||
HBitmapIter hbi;
|
||||
|
||||
hbitmap_iter_init(&hbi, job->copy_bitmap, 0);
|
||||
while ((cluster = hbitmap_iter_next(&hbi)) != -1) {
|
||||
do {
|
||||
if (yield_and_check(job)) {
|
||||
return 0;
|
||||
}
|
||||
ret = backup_do_cow(job, cluster * job->cluster_size,
|
||||
job->cluster_size, &error_is_read, false);
|
||||
if (ret < 0 && backup_error_action(job, error_is_read, -ret) ==
|
||||
BLOCK_ERROR_ACTION_REPORT)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
} while (ret < 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* init copy_bitmap from sync_bitmap */
|
||||
static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
|
||||
{
|
||||
BdrvDirtyBitmapIter *dbi;
|
||||
int ret = 0;
|
||||
int clusters_per_iter;
|
||||
uint32_t granularity;
|
||||
int64_t offset;
|
||||
int64_t end = DIV_ROUND_UP(bdrv_dirty_bitmap_size(job->sync_bitmap),
|
||||
job->cluster_size);
|
||||
int64_t cluster;
|
||||
int64_t end;
|
||||
int64_t last_cluster = -1;
|
||||
BdrvDirtyBitmapIter *dbi;
|
||||
|
||||
granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap);
|
||||
clusters_per_iter = MAX((granularity / job->cluster_size), 1);
|
||||
dbi = bdrv_dirty_iter_new(job->sync_bitmap);
|
||||
while ((offset = bdrv_dirty_iter_next(dbi)) != -1) {
|
||||
int64_t cluster = offset / job->cluster_size;
|
||||
int64_t next_cluster;
|
||||
|
||||
offset += bdrv_dirty_bitmap_granularity(job->sync_bitmap);
|
||||
if (offset >= bdrv_dirty_bitmap_size(job->sync_bitmap)) {
|
||||
hbitmap_set(job->copy_bitmap, cluster, end - cluster);
|
||||
break;
|
||||
/* Find the next dirty sector(s) */
|
||||
while ((offset = bdrv_dirty_iter_next(dbi)) >= 0) {
|
||||
cluster = offset / job->cluster_size;
|
||||
|
||||
/* Fake progress updates for any clusters we skipped */
|
||||
if (cluster != last_cluster + 1) {
|
||||
job->common.offset += ((cluster - last_cluster - 1) *
|
||||
job->cluster_size);
|
||||
}
|
||||
|
||||
offset = bdrv_dirty_bitmap_next_zero(job->sync_bitmap, offset);
|
||||
if (offset == -1) {
|
||||
hbitmap_set(job->copy_bitmap, cluster, end - cluster);
|
||||
break;
|
||||
for (end = cluster + clusters_per_iter; cluster < end; cluster++) {
|
||||
do {
|
||||
if (yield_and_check(job)) {
|
||||
goto out;
|
||||
}
|
||||
ret = backup_do_cow(job, cluster * job->cluster_size,
|
||||
job->cluster_size, &error_is_read,
|
||||
false);
|
||||
if ((ret < 0) &&
|
||||
backup_error_action(job, error_is_read, -ret) ==
|
||||
BLOCK_ERROR_ACTION_REPORT) {
|
||||
goto out;
|
||||
}
|
||||
} while (ret < 0);
|
||||
}
|
||||
|
||||
next_cluster = DIV_ROUND_UP(offset, job->cluster_size);
|
||||
hbitmap_set(job->copy_bitmap, cluster, next_cluster - cluster);
|
||||
if (next_cluster >= end) {
|
||||
break;
|
||||
/* If the bitmap granularity is smaller than the backup granularity,
|
||||
* we need to advance the iterator pointer to the next cluster. */
|
||||
if (granularity < job->cluster_size) {
|
||||
bdrv_set_dirty_iter(dbi, cluster * job->cluster_size);
|
||||
}
|
||||
|
||||
bdrv_set_dirty_iter(dbi, next_cluster * job->cluster_size);
|
||||
last_cluster = cluster - 1;
|
||||
}
|
||||
|
||||
job->common.offset = job->common.len -
|
||||
hbitmap_count(job->copy_bitmap) * job->cluster_size;
|
||||
/* Play some final catchup with the progress meter */
|
||||
end = DIV_ROUND_UP(job->common.len, job->cluster_size);
|
||||
if (last_cluster + 1 < end) {
|
||||
job->common.offset += ((end - last_cluster - 1) * job->cluster_size);
|
||||
}
|
||||
|
||||
out:
|
||||
bdrv_dirty_iter_free(dbi);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void coroutine_fn backup_run(void *opaque)
|
||||
@@ -431,27 +425,19 @@ static void coroutine_fn backup_run(void *opaque)
|
||||
BackupBlockJob *job = opaque;
|
||||
BackupCompleteData *data;
|
||||
BlockDriverState *bs = blk_bs(job->common.blk);
|
||||
int64_t offset, nb_clusters;
|
||||
int64_t offset;
|
||||
int ret = 0;
|
||||
|
||||
QLIST_INIT(&job->inflight_reqs);
|
||||
qemu_co_rwlock_init(&job->flush_rwlock);
|
||||
|
||||
nb_clusters = DIV_ROUND_UP(job->common.len, job->cluster_size);
|
||||
job->copy_bitmap = hbitmap_alloc(nb_clusters, 0);
|
||||
if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
|
||||
backup_incremental_init_copy_bitmap(job);
|
||||
} else {
|
||||
hbitmap_set(job->copy_bitmap, 0, nb_clusters);
|
||||
}
|
||||
|
||||
job->done_bitmap = bitmap_new(DIV_ROUND_UP(job->common.len,
|
||||
job->cluster_size));
|
||||
|
||||
job->before_write.notify = backup_before_write_notify;
|
||||
bdrv_add_before_write_notifier(bs, &job->before_write);
|
||||
|
||||
if (job->sync_mode == MIRROR_SYNC_MODE_NONE) {
|
||||
/* All bits are set in copy_bitmap to allow any cluster to be copied.
|
||||
* This does not actually require them to be copied. */
|
||||
while (!block_job_is_cancelled(&job->common)) {
|
||||
/* Yield until the job is cancelled. We just let our before_write
|
||||
* notify callback service CoW requests. */
|
||||
@@ -526,7 +512,7 @@ static void coroutine_fn backup_run(void *opaque)
|
||||
/* wait until pending backup_do_cow() calls have completed */
|
||||
qemu_co_rwlock_wrlock(&job->flush_rwlock);
|
||||
qemu_co_rwlock_unlock(&job->flush_rwlock);
|
||||
hbitmap_free(job->copy_bitmap);
|
||||
g_free(job->done_bitmap);
|
||||
|
||||
data = g_malloc(sizeof(*data));
|
||||
data->ret = ret;
|
||||
|
@@ -29,7 +29,7 @@
|
||||
#include "qemu/config-file.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "sysemu/qtest.h"
|
||||
|
@@ -14,7 +14,6 @@
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/option.h"
|
||||
|
||||
typedef struct {
|
||||
BdrvChild *test_file;
|
||||
|
@@ -18,9 +18,7 @@
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qapi-event.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/id.h"
|
||||
#include "qemu/option.h"
|
||||
#include "trace.h"
|
||||
#include "migration/misc.h"
|
||||
|
||||
@@ -2098,13 +2096,3 @@ static void blk_root_drained_end(BdrvChild *child)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void blk_register_buf(BlockBackend *blk, void *host, size_t size)
|
||||
{
|
||||
bdrv_register_buf(blk_bs(blk), host, size);
|
||||
}
|
||||
|
||||
void blk_unregister_buf(BlockBackend *blk, void *host)
|
||||
{
|
||||
bdrv_unregister_buf(blk_bs(blk), host);
|
||||
}
|
||||
|
@@ -277,6 +277,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
const char *filter_node_name, Error **errp)
|
||||
{
|
||||
CommitBlockJob *s;
|
||||
BlockReopenQueue *reopen_queue = NULL;
|
||||
int orig_base_flags;
|
||||
BlockDriverState *iter;
|
||||
BlockDriverState *commit_top_bs = NULL;
|
||||
@@ -298,7 +299,12 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
/* convert base to r/w, if necessary */
|
||||
orig_base_flags = bdrv_get_flags(base);
|
||||
if (!(orig_base_flags & BDRV_O_RDWR)) {
|
||||
bdrv_reopen(base, orig_base_flags | BDRV_O_RDWR, &local_err);
|
||||
reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
|
||||
orig_base_flags | BDRV_O_RDWR);
|
||||
}
|
||||
|
||||
if (reopen_queue) {
|
||||
bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
|
@@ -24,11 +24,9 @@
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "crypto/block.h"
|
||||
#include "qapi/opts-visitor.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/option.h"
|
||||
#include "block/crypto.h"
|
||||
|
||||
typedef struct BlockCrypto BlockCrypto;
|
||||
@@ -576,6 +574,7 @@ static int block_crypto_get_info_luks(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
bdi->unallocated_blocks_are_zero = false;
|
||||
bdi->can_write_zeroes_with_unmap = false;
|
||||
bdi->cluster_size = subbdi.cluster_size;
|
||||
|
||||
return 0;
|
||||
|
49
block/curl.c
49
block/curl.c
@@ -21,13 +21,12 @@
|
||||
* 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 "qemu-common.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/option.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "crypto/secret.h"
|
||||
#include <curl/curl.h>
|
||||
@@ -90,8 +89,6 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
|
||||
|
||||
struct BDRVCURLState;
|
||||
|
||||
static bool libcurl_initialized;
|
||||
|
||||
typedef struct CURLAIOCB {
|
||||
Coroutine *co;
|
||||
QEMUIOVector *qiov;
|
||||
@@ -102,6 +99,8 @@ typedef struct CURLAIOCB {
|
||||
|
||||
size_t start;
|
||||
size_t end;
|
||||
|
||||
QSIMPLEQ_ENTRY(CURLAIOCB) next;
|
||||
} CURLAIOCB;
|
||||
|
||||
typedef struct CURLSocket {
|
||||
@@ -137,7 +136,7 @@ typedef struct BDRVCURLState {
|
||||
bool accept_range;
|
||||
AioContext *aio_context;
|
||||
QemuMutex mutex;
|
||||
CoQueue free_state_waitq;
|
||||
QSIMPLEQ_HEAD(, CURLAIOCB) free_state_waitq;
|
||||
char *username;
|
||||
char *password;
|
||||
char *proxyusername;
|
||||
@@ -537,6 +536,7 @@ static int curl_init_state(BDRVCURLState *s, CURLState *state)
|
||||
/* Called with s->mutex held. */
|
||||
static void curl_clean_state(CURLState *s)
|
||||
{
|
||||
CURLAIOCB *next;
|
||||
int j;
|
||||
for (j = 0; j < CURL_NUM_ACB; j++) {
|
||||
assert(!s->acb[j]);
|
||||
@@ -554,7 +554,13 @@ static void curl_clean_state(CURLState *s)
|
||||
|
||||
s->in_use = 0;
|
||||
|
||||
qemu_co_enter_next(&s->s->free_state_waitq, &s->s->mutex);
|
||||
next = QSIMPLEQ_FIRST(&s->s->free_state_waitq);
|
||||
if (next) {
|
||||
QSIMPLEQ_REMOVE_HEAD(&s->s->free_state_waitq, next);
|
||||
qemu_mutex_unlock(&s->s->mutex);
|
||||
aio_co_wake(next->co);
|
||||
qemu_mutex_lock(&s->s->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static void curl_parse_filename(const char *filename, QDict *options,
|
||||
@@ -680,23 +686,14 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
double d;
|
||||
const char *secretid;
|
||||
const char *protocol_delimiter;
|
||||
int ret;
|
||||
|
||||
static int inited = 0;
|
||||
|
||||
if (flags & BDRV_O_RDWR) {
|
||||
error_setg(errp, "curl block device does not support writes");
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
if (!libcurl_initialized) {
|
||||
ret = curl_global_init(CURL_GLOBAL_ALL);
|
||||
if (ret) {
|
||||
error_setg(errp, "libcurl initialization failed with %d", ret);
|
||||
return -EIO;
|
||||
}
|
||||
libcurl_initialized = true;
|
||||
}
|
||||
|
||||
qemu_mutex_init(&s->mutex);
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
@@ -775,8 +772,13 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
}
|
||||
|
||||
if (!inited) {
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
inited = 1;
|
||||
}
|
||||
|
||||
DPRINTF("CURL: Opening %s\n", file);
|
||||
qemu_co_queue_init(&s->free_state_waitq);
|
||||
QSIMPLEQ_INIT(&s->free_state_waitq);
|
||||
s->aio_context = bdrv_get_aio_context(bs);
|
||||
s->url = g_strdup(file);
|
||||
qemu_mutex_lock(&s->mutex);
|
||||
@@ -849,9 +851,6 @@ out_noclean:
|
||||
qemu_mutex_destroy(&s->mutex);
|
||||
g_free(s->cookie);
|
||||
g_free(s->url);
|
||||
g_free(s->username);
|
||||
g_free(s->proxyusername);
|
||||
g_free(s->proxypassword);
|
||||
qemu_opts_del(opts);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -880,7 +879,10 @@ static void curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb)
|
||||
if (state) {
|
||||
break;
|
||||
}
|
||||
qemu_co_queue_wait(&s->free_state_waitq, &s->mutex);
|
||||
QSIMPLEQ_INSERT_TAIL(&s->free_state_waitq, acb, next);
|
||||
qemu_mutex_unlock(&s->mutex);
|
||||
qemu_coroutine_yield();
|
||||
qemu_mutex_lock(&s->mutex);
|
||||
}
|
||||
|
||||
if (curl_init_state(s, state) < 0) {
|
||||
@@ -947,9 +949,6 @@ static void curl_close(BlockDriverState *bs)
|
||||
|
||||
g_free(s->cookie);
|
||||
g_free(s->url);
|
||||
g_free(s->username);
|
||||
g_free(s->proxyusername);
|
||||
g_free(s->proxypassword);
|
||||
}
|
||||
|
||||
static int64_t curl_getlength(BlockDriverState *bs)
|
||||
|
@@ -52,6 +52,8 @@ struct BdrvDirtyBitmap {
|
||||
Such operations must fail and both the image
|
||||
and this bitmap must remain unchanged while
|
||||
this flag is set. */
|
||||
bool autoload; /* For persistent bitmaps: bitmap must be
|
||||
autoloaded on image opening */
|
||||
bool persistent; /* bitmap must be saved to owner disk image */
|
||||
QLIST_ENTRY(BdrvDirtyBitmap) list;
|
||||
};
|
||||
@@ -102,6 +104,7 @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
|
||||
g_free(bitmap->name);
|
||||
bitmap->name = NULL;
|
||||
bitmap->persistent = false;
|
||||
bitmap->autoload = false;
|
||||
}
|
||||
|
||||
/* Called with BQL taken. */
|
||||
@@ -258,6 +261,8 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
|
||||
bitmap->successor = NULL;
|
||||
successor->persistent = bitmap->persistent;
|
||||
bitmap->persistent = false;
|
||||
successor->autoload = bitmap->autoload;
|
||||
bitmap->autoload = false;
|
||||
bdrv_release_dirty_bitmap(bs, bitmap);
|
||||
|
||||
return successor;
|
||||
@@ -661,6 +666,19 @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Called with BQL taken. */
|
||||
void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload)
|
||||
{
|
||||
qemu_mutex_lock(bitmap->mutex);
|
||||
bitmap->autoload = autoload;
|
||||
qemu_mutex_unlock(bitmap->mutex);
|
||||
}
|
||||
|
||||
bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
return bitmap->autoload;
|
||||
}
|
||||
|
||||
/* Called with BQL taken. */
|
||||
void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
|
||||
{
|
||||
@@ -697,8 +715,3 @@ char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp)
|
||||
{
|
||||
return hbitmap_sha256(bitmap->bitmap, errp);
|
||||
}
|
||||
|
||||
int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset)
|
||||
{
|
||||
return hbitmap_next_zero(bitmap->bitmap, offset);
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#ifndef BLOCK_DMG_H
|
||||
#define BLOCK_DMG_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "block/block_int.h"
|
||||
#include <zlib.h>
|
||||
|
@@ -21,19 +21,16 @@
|
||||
* 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 "qemu/cutils.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "trace.h"
|
||||
#include "block/thread-pool.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "block/raw-aio.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
|
||||
#include "scsi/pr-manager.h"
|
||||
@@ -549,6 +546,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
|
||||
s->has_discard = true;
|
||||
s->has_write_zeroes = true;
|
||||
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP;
|
||||
if ((bs->open_flags & BDRV_O_NOCACHE) != 0) {
|
||||
s->needs_alignment = true;
|
||||
}
|
||||
@@ -598,7 +596,6 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
}
|
||||
#endif
|
||||
|
||||
bs->supported_zero_flags = s->discard_zeroes ? BDRV_REQ_MAY_UNMAP : 0;
|
||||
ret = 0;
|
||||
fail:
|
||||
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
|
||||
@@ -2223,6 +2220,7 @@ static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
bdi->unallocated_blocks_are_zero = s->discard_zeroes;
|
||||
bdi->can_write_zeroes_with_unmap = s->discard_zeroes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -21,18 +21,15 @@
|
||||
* 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 "qemu/cutils.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "block/raw-aio.h"
|
||||
#include "trace.h"
|
||||
#include "block/thread-pool.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
|
119
block/gluster.c
119
block/gluster.c
@@ -7,16 +7,13 @@
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <glusterfs/api/glfs.h>
|
||||
#include "block/block_int.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/uri.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
#define GLUSTER_OPT_FILENAME "filename"
|
||||
@@ -965,68 +962,12 @@ static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
}
|
||||
#endif
|
||||
|
||||
static int qemu_gluster_do_truncate(struct glfs_fd *fd, int64_t offset,
|
||||
PreallocMode prealloc, Error **errp)
|
||||
{
|
||||
int64_t current_length;
|
||||
|
||||
current_length = glfs_lseek(fd, 0, SEEK_END);
|
||||
if (current_length < 0) {
|
||||
error_setg_errno(errp, errno, "Failed to determine current size");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (current_length > offset && prealloc != PREALLOC_MODE_OFF) {
|
||||
error_setg(errp, "Cannot use preallocation for shrinking files");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (current_length == offset) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (prealloc) {
|
||||
#ifdef CONFIG_GLUSTERFS_FALLOCATE
|
||||
case PREALLOC_MODE_FALLOC:
|
||||
if (glfs_fallocate(fd, 0, current_length, offset - current_length)) {
|
||||
error_setg_errno(errp, errno, "Could not preallocate data");
|
||||
return -errno;
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_GLUSTERFS_FALLOCATE */
|
||||
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||
case PREALLOC_MODE_FULL:
|
||||
if (glfs_ftruncate(fd, offset)) {
|
||||
error_setg_errno(errp, errno, "Could not resize file");
|
||||
return -errno;
|
||||
}
|
||||
if (glfs_zerofill(fd, current_length, offset - current_length)) {
|
||||
error_setg_errno(errp, errno, "Could not zerofill the new area");
|
||||
return -errno;
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_GLUSTERFS_ZEROFILL */
|
||||
case PREALLOC_MODE_OFF:
|
||||
if (glfs_ftruncate(fd, offset)) {
|
||||
error_setg_errno(errp, errno, "Could not resize file");
|
||||
return -errno;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Unsupported preallocation mode: %s",
|
||||
PreallocMode_str(prealloc));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qemu_gluster_create(const char *filename,
|
||||
QemuOpts *opts, Error **errp)
|
||||
{
|
||||
BlockdevOptionsGluster *gconf;
|
||||
struct glfs *glfs;
|
||||
struct glfs_fd *fd = NULL;
|
||||
struct glfs_fd *fd;
|
||||
int ret = 0;
|
||||
PreallocMode prealloc;
|
||||
int64_t total_size = 0;
|
||||
@@ -1075,14 +1016,45 @@ static int qemu_gluster_create(const char *filename,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = qemu_gluster_do_truncate(fd, total_size, prealloc, errp);
|
||||
|
||||
out:
|
||||
if (fd) {
|
||||
if (glfs_close(fd) != 0 && ret == 0) {
|
||||
switch (prealloc) {
|
||||
#ifdef CONFIG_GLUSTERFS_FALLOCATE
|
||||
case PREALLOC_MODE_FALLOC:
|
||||
if (glfs_fallocate(fd, 0, 0, total_size)) {
|
||||
error_setg(errp, "Could not preallocate data for the new file");
|
||||
ret = -errno;
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_GLUSTERFS_FALLOCATE */
|
||||
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||
case PREALLOC_MODE_FULL:
|
||||
if (!glfs_ftruncate(fd, total_size)) {
|
||||
if (glfs_zerofill(fd, 0, total_size)) {
|
||||
error_setg(errp, "Could not zerofill the new file");
|
||||
ret = -errno;
|
||||
}
|
||||
} else {
|
||||
error_setg(errp, "Could not resize file");
|
||||
ret = -errno;
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_GLUSTERFS_ZEROFILL */
|
||||
case PREALLOC_MODE_OFF:
|
||||
if (glfs_ftruncate(fd, total_size) != 0) {
|
||||
ret = -errno;
|
||||
error_setg(errp, "Could not resize file");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
error_setg(errp, "Unsupported preallocation mode: %s",
|
||||
PreallocMode_str(prealloc));
|
||||
break;
|
||||
}
|
||||
|
||||
if (glfs_close(fd) != 0) {
|
||||
ret = -errno;
|
||||
}
|
||||
out:
|
||||
qapi_free_BlockdevOptionsGluster(gconf);
|
||||
glfs_clear_preopened(glfs);
|
||||
return ret;
|
||||
@@ -1122,8 +1094,23 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
|
||||
static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset,
|
||||
PreallocMode prealloc, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
BDRVGlusterState *s = bs->opaque;
|
||||
return qemu_gluster_do_truncate(s->fd, offset, prealloc, errp);
|
||||
|
||||
if (prealloc != PREALLOC_MODE_OFF) {
|
||||
error_setg(errp, "Unsupported preallocation mode '%s'",
|
||||
PreallocMode_str(prealloc));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
ret = glfs_ftruncate(s->fd, offset);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
error_setg_errno(errp, -ret, "Failed to truncate file");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static coroutine_fn int qemu_gluster_co_readv(BlockDriverState *bs,
|
||||
|
195
block/io.c
195
block/io.c
@@ -40,28 +40,22 @@
|
||||
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int bytes, BdrvRequestFlags flags);
|
||||
|
||||
void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
|
||||
void bdrv_parent_drained_begin(BlockDriverState *bs)
|
||||
{
|
||||
BdrvChild *c, *next;
|
||||
|
||||
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
|
||||
if (c == ignore) {
|
||||
continue;
|
||||
}
|
||||
if (c->role->drained_begin) {
|
||||
c->role->drained_begin(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
|
||||
void bdrv_parent_drained_end(BlockDriverState *bs)
|
||||
{
|
||||
BdrvChild *c, *next;
|
||||
|
||||
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
|
||||
if (c == ignore) {
|
||||
continue;
|
||||
}
|
||||
if (c->role->drained_end) {
|
||||
c->role->drained_end(c);
|
||||
}
|
||||
@@ -140,13 +134,29 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
|
||||
assert(old >= 1);
|
||||
}
|
||||
|
||||
/* Check if any requests are in-flight (including throttled requests) */
|
||||
bool bdrv_requests_pending(BlockDriverState *bs)
|
||||
{
|
||||
BdrvChild *child;
|
||||
|
||||
if (atomic_read(&bs->in_flight)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
if (bdrv_requests_pending(child->bs)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Coroutine *co;
|
||||
BlockDriverState *bs;
|
||||
bool done;
|
||||
bool begin;
|
||||
bool recursive;
|
||||
BdrvChild *parent;
|
||||
} BdrvCoDrainData;
|
||||
|
||||
static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
|
||||
@@ -166,7 +176,7 @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
|
||||
}
|
||||
|
||||
/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
|
||||
static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, bool recursive)
|
||||
static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
|
||||
{
|
||||
BdrvChild *child, *tmp;
|
||||
BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
|
||||
@@ -180,14 +190,12 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, bool recursive)
|
||||
bdrv_coroutine_enter(bs, data.co);
|
||||
BDRV_POLL_WHILE(bs, !data.done);
|
||||
|
||||
if (recursive) {
|
||||
QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
|
||||
bdrv_drain_invoke(child->bs, begin, true);
|
||||
}
|
||||
QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
|
||||
bdrv_drain_invoke(child->bs, begin);
|
||||
}
|
||||
}
|
||||
|
||||
static bool bdrv_drain_recurse(BlockDriverState *bs)
|
||||
static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
|
||||
{
|
||||
BdrvChild *child, *tmp;
|
||||
bool waited;
|
||||
@@ -210,7 +218,7 @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
|
||||
*/
|
||||
bdrv_ref(bs);
|
||||
}
|
||||
waited |= bdrv_drain_recurse(bs);
|
||||
waited |= bdrv_drain_recurse(bs, begin);
|
||||
if (in_main_loop) {
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
@@ -219,11 +227,6 @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
|
||||
return waited;
|
||||
}
|
||||
|
||||
static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
|
||||
BdrvChild *parent);
|
||||
static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
|
||||
BdrvChild *parent);
|
||||
|
||||
static void bdrv_co_drain_bh_cb(void *opaque)
|
||||
{
|
||||
BdrvCoDrainData *data = opaque;
|
||||
@@ -232,9 +235,9 @@ static void bdrv_co_drain_bh_cb(void *opaque)
|
||||
|
||||
bdrv_dec_in_flight(bs);
|
||||
if (data->begin) {
|
||||
bdrv_do_drained_begin(bs, data->recursive, data->parent);
|
||||
bdrv_drained_begin(bs);
|
||||
} else {
|
||||
bdrv_do_drained_end(bs, data->recursive, data->parent);
|
||||
bdrv_drained_end(bs);
|
||||
}
|
||||
|
||||
data->done = true;
|
||||
@@ -242,8 +245,7 @@ static void bdrv_co_drain_bh_cb(void *opaque)
|
||||
}
|
||||
|
||||
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
|
||||
bool begin, bool recursive,
|
||||
BdrvChild *parent)
|
||||
bool begin)
|
||||
{
|
||||
BdrvCoDrainData data;
|
||||
|
||||
@@ -257,8 +259,6 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
|
||||
.bs = bs,
|
||||
.done = false,
|
||||
.begin = begin,
|
||||
.recursive = recursive,
|
||||
.parent = parent,
|
||||
};
|
||||
bdrv_inc_in_flight(bs);
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs),
|
||||
@@ -270,97 +270,37 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
|
||||
assert(data.done);
|
||||
}
|
||||
|
||||
void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
|
||||
BdrvChild *parent)
|
||||
{
|
||||
BdrvChild *child, *next;
|
||||
|
||||
if (qemu_in_coroutine()) {
|
||||
bdrv_co_yield_to_drain(bs, true, recursive, parent);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Stop things in parent-to-child order */
|
||||
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
|
||||
aio_disable_external(bdrv_get_aio_context(bs));
|
||||
}
|
||||
|
||||
bdrv_parent_drained_begin(bs, parent);
|
||||
bdrv_drain_invoke(bs, true, false);
|
||||
bdrv_drain_recurse(bs);
|
||||
|
||||
if (recursive) {
|
||||
bs->recursive_quiesce_counter++;
|
||||
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
|
||||
bdrv_do_drained_begin(child->bs, true, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_drained_begin(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_do_drained_begin(bs, false, NULL);
|
||||
}
|
||||
|
||||
void bdrv_subtree_drained_begin(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_do_drained_begin(bs, true, NULL);
|
||||
}
|
||||
|
||||
void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
|
||||
BdrvChild *parent)
|
||||
{
|
||||
BdrvChild *child, *next;
|
||||
int old_quiesce_counter;
|
||||
|
||||
if (qemu_in_coroutine()) {
|
||||
bdrv_co_yield_to_drain(bs, false, recursive, parent);
|
||||
bdrv_co_yield_to_drain(bs, true);
|
||||
return;
|
||||
}
|
||||
assert(bs->quiesce_counter > 0);
|
||||
old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
|
||||
|
||||
/* Re-enable things in child-to-parent order */
|
||||
bdrv_drain_invoke(bs, false, false);
|
||||
bdrv_parent_drained_end(bs, parent);
|
||||
if (old_quiesce_counter == 1) {
|
||||
aio_enable_external(bdrv_get_aio_context(bs));
|
||||
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
|
||||
aio_disable_external(bdrv_get_aio_context(bs));
|
||||
bdrv_parent_drained_begin(bs);
|
||||
}
|
||||
|
||||
if (recursive) {
|
||||
bs->recursive_quiesce_counter--;
|
||||
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
|
||||
bdrv_do_drained_end(child->bs, true, child);
|
||||
}
|
||||
}
|
||||
bdrv_drain_invoke(bs, true);
|
||||
bdrv_drain_recurse(bs, true);
|
||||
}
|
||||
|
||||
void bdrv_drained_end(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_do_drained_end(bs, false, NULL);
|
||||
}
|
||||
|
||||
void bdrv_subtree_drained_end(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_do_drained_end(bs, true, NULL);
|
||||
}
|
||||
|
||||
void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < new_parent->recursive_quiesce_counter; i++) {
|
||||
bdrv_do_drained_begin(child->bs, true, child);
|
||||
if (qemu_in_coroutine()) {
|
||||
bdrv_co_yield_to_drain(bs, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < old_parent->recursive_quiesce_counter; i++) {
|
||||
bdrv_do_drained_end(child->bs, true, child);
|
||||
assert(bs->quiesce_counter > 0);
|
||||
if (atomic_fetch_dec(&bs->quiesce_counter) > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_parent_drained_end(bs);
|
||||
bdrv_drain_invoke(bs, false);
|
||||
bdrv_drain_recurse(bs, false);
|
||||
aio_enable_external(bdrv_get_aio_context(bs));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -407,20 +347,15 @@ void bdrv_drain_all_begin(void)
|
||||
BdrvNextIterator it;
|
||||
GSList *aio_ctxs = NULL, *ctx;
|
||||
|
||||
/* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread
|
||||
* or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on
|
||||
* nodes in several different AioContexts, so make sure we're in the main
|
||||
* context. */
|
||||
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
|
||||
block_job_pause_all();
|
||||
|
||||
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
/* Stop things in parent-to-child order */
|
||||
aio_context_acquire(aio_context);
|
||||
bdrv_parent_drained_begin(bs);
|
||||
aio_disable_external(aio_context);
|
||||
bdrv_parent_drained_begin(bs, NULL);
|
||||
bdrv_drain_invoke(bs, true, true);
|
||||
bdrv_drain_invoke(bs, true);
|
||||
aio_context_release(aio_context);
|
||||
|
||||
if (!g_slist_find(aio_ctxs, aio_context)) {
|
||||
@@ -443,7 +378,7 @@ void bdrv_drain_all_begin(void)
|
||||
aio_context_acquire(aio_context);
|
||||
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
||||
if (aio_context == bdrv_get_aio_context(bs)) {
|
||||
waited |= bdrv_drain_recurse(bs);
|
||||
waited |= bdrv_drain_recurse(bs, true);
|
||||
}
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
@@ -461,13 +396,15 @@ void bdrv_drain_all_end(void)
|
||||
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
/* Re-enable things in child-to-parent order */
|
||||
aio_context_acquire(aio_context);
|
||||
bdrv_drain_invoke(bs, false, true);
|
||||
bdrv_parent_drained_end(bs, NULL);
|
||||
aio_enable_external(aio_context);
|
||||
bdrv_parent_drained_end(bs);
|
||||
bdrv_drain_invoke(bs, false);
|
||||
bdrv_drain_recurse(bs, false);
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
block_job_resume_all();
|
||||
}
|
||||
|
||||
void bdrv_drain_all(void)
|
||||
@@ -2825,27 +2762,3 @@ void bdrv_io_unplug(BlockDriverState *bs)
|
||||
bdrv_io_unplug(child->bs);
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_register_buf(BlockDriverState *bs, void *host, size_t size)
|
||||
{
|
||||
BdrvChild *child;
|
||||
|
||||
if (bs->drv && bs->drv->bdrv_register_buf) {
|
||||
bs->drv->bdrv_register_buf(bs, host, size);
|
||||
}
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
bdrv_register_buf(child->bs, host, size);
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_unregister_buf(BlockDriverState *bs, void *host)
|
||||
{
|
||||
BdrvChild *child;
|
||||
|
||||
if (bs->drv && bs->drv->bdrv_unregister_buf) {
|
||||
bs->drv->bdrv_unregister_buf(bs, host);
|
||||
}
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
bdrv_unregister_buf(child->bs, host);
|
||||
}
|
||||
}
|
||||
|
@@ -25,7 +25,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/option.h"
|
||||
|
||||
static QemuOptsList qemu_iscsi_opts = {
|
||||
.name = "iscsi",
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include <poll.h>
|
||||
#include <math.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/bitops.h"
|
||||
@@ -35,11 +36,8 @@
|
||||
#include "block/block_int.h"
|
||||
#include "scsi/constants.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/uuid.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "crypto/secret.h"
|
||||
#include "scsi/utils.h"
|
||||
@@ -106,7 +104,6 @@ typedef struct IscsiTask {
|
||||
IscsiLun *iscsilun;
|
||||
QEMUTimer retry_timer;
|
||||
int err_code;
|
||||
char *err_str;
|
||||
} IscsiTask;
|
||||
|
||||
typedef struct IscsiAIOCB {
|
||||
@@ -268,7 +265,7 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
||||
}
|
||||
}
|
||||
iTask->err_code = iscsi_translate_sense(&task->sense);
|
||||
iTask->err_str = g_strdup(iscsi_get_error(iscsi));
|
||||
error_report("iSCSI Failure: %s", iscsi_get_error(iscsi));
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -632,8 +629,6 @@ retry:
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
iscsi_allocmap_set_invalid(iscsilun, sector_num, nb_sectors);
|
||||
error_report("iSCSI WRITE10/16 failed at lba %" PRIu64 ": %s", lba,
|
||||
iTask.err_str);
|
||||
r = iTask.err_code;
|
||||
goto out_unlock;
|
||||
}
|
||||
@@ -642,7 +637,6 @@ retry:
|
||||
|
||||
out_unlock:
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
g_free(iTask.err_str);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -657,7 +651,6 @@ static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||
struct scsi_get_lba_status *lbas = NULL;
|
||||
struct scsi_lba_status_descriptor *lbasd = NULL;
|
||||
struct IscsiTask iTask;
|
||||
uint64_t lba;
|
||||
int64_t ret;
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
@@ -677,12 +670,11 @@ static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||
goto out;
|
||||
}
|
||||
|
||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
|
||||
qemu_mutex_lock(&iscsilun->mutex);
|
||||
retry:
|
||||
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
|
||||
lba, 8 + 16, iscsi_co_generic_cb,
|
||||
sector_qemu2lun(sector_num, iscsilun),
|
||||
8 + 16, iscsi_co_generic_cb,
|
||||
&iTask) == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unlock;
|
||||
@@ -709,8 +701,6 @@ retry:
|
||||
* because the device is busy or the cmd is not
|
||||
* supported) we pretend all blocks are allocated
|
||||
* for backwards compatibility */
|
||||
error_report("iSCSI GET_LBA_STATUS failed at lba %" PRIu64 ": %s",
|
||||
lba, iTask.err_str);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
@@ -748,7 +738,6 @@ retry:
|
||||
}
|
||||
out_unlock:
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
g_free(iTask.err_str);
|
||||
out:
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
@@ -767,7 +756,6 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
||||
struct IscsiTask iTask;
|
||||
uint64_t lba;
|
||||
uint32_t num_sectors;
|
||||
int r = 0;
|
||||
|
||||
if (!is_sector_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
return -EINVAL;
|
||||
@@ -865,23 +853,19 @@ retry:
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
error_report("iSCSI READ10/16 failed at lba %" PRIu64 ": %s",
|
||||
lba, iTask.err_str);
|
||||
r = iTask.err_code;
|
||||
return iTask.err_code;
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
g_free(iTask.err_str);
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coroutine_fn iscsi_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct IscsiTask iTask;
|
||||
int r = 0;
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
qemu_mutex_lock(&iscsilun->mutex);
|
||||
@@ -908,15 +892,13 @@ retry:
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
error_report("iSCSI SYNCHRONIZECACHE10 failed: %s", iTask.err_str);
|
||||
r = iTask.err_code;
|
||||
return iTask.err_code;
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
g_free(iTask.err_str);
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -1157,15 +1139,12 @@ retry:
|
||||
}
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
error_report("iSCSI UNMAP failed at lba %" PRIu64 ": %s",
|
||||
list.lba, iTask.err_str);
|
||||
r = iTask.err_code;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
g_free(iTask.err_str);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1262,8 +1241,6 @@ retry:
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS,
|
||||
bytes >> BDRV_SECTOR_BITS);
|
||||
error_report("iSCSI WRITESAME10/16 failed at lba %" PRIu64 ": %s",
|
||||
lba, iTask.err_str);
|
||||
r = iTask.err_code;
|
||||
goto out_unlock;
|
||||
}
|
||||
@@ -1278,7 +1255,6 @@ retry:
|
||||
|
||||
out_unlock:
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
g_free(iTask.err_str);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1877,6 +1853,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (iscsilun->dpofua) {
|
||||
bs->supported_write_flags = BDRV_REQ_FUA;
|
||||
}
|
||||
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP;
|
||||
|
||||
/* Check the write protect flag of the LUN if we want to write */
|
||||
if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) &&
|
||||
@@ -1960,10 +1937,6 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
}
|
||||
|
||||
if (iscsilun->lbprz && iscsilun->lbp.lbpws) {
|
||||
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP;
|
||||
}
|
||||
|
||||
out:
|
||||
qemu_opts_del(opts);
|
||||
g_free(initiator_name);
|
||||
@@ -2163,6 +2136,7 @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
bdi->unallocated_blocks_are_zero = iscsilun->lbprz;
|
||||
bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws;
|
||||
bdi->cluster_size = iscsilun->cluster_sectors * BDRV_SECTOR_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
@@ -32,11 +32,11 @@
|
||||
#include "qemu/uri.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qapi/qobject-output-visitor.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
|
@@ -25,13 +25,13 @@
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include <poll.h>
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "block/block_int.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/uri.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
@@ -14,7 +14,6 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qemu/option.h"
|
||||
#include "block/block_int.h"
|
||||
|
||||
#define NULL_OPT_LATENCY "latency-ns"
|
||||
@@ -111,7 +110,8 @@ static coroutine_fn int null_co_common(BlockDriverState *bs)
|
||||
BDRVNullState *s = bs->opaque;
|
||||
|
||||
if (s->latency_ns) {
|
||||
qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, s->latency_ns);
|
||||
co_aio_sleep_ns(bdrv_get_aio_context(bs), QEMU_CLOCK_REALTIME,
|
||||
s->latency_ns);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
1202
block/nvme.c
1202
block/nvme.c
File diff suppressed because it is too large
Load Diff
@@ -27,17 +27,15 @@
|
||||
* 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 "qemu-common.h"
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "qemu/bitmap.h"
|
||||
#include "migration/blocker.h"
|
||||
#include "parallels.h"
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
@@ -47,6 +45,30 @@
|
||||
#define HEADER_INUSE_MAGIC (0x746F6E59)
|
||||
#define MAX_PARALLELS_IMAGE_FACTOR (1ull << 32)
|
||||
|
||||
#define DEFAULT_CLUSTER_SIZE 1048576 /* 1 MiB */
|
||||
|
||||
|
||||
// always little-endian
|
||||
typedef struct ParallelsHeader {
|
||||
char magic[16]; // "WithoutFreeSpace"
|
||||
uint32_t version;
|
||||
uint32_t heads;
|
||||
uint32_t cylinders;
|
||||
uint32_t tracks;
|
||||
uint32_t bat_entries;
|
||||
uint64_t nb_sectors;
|
||||
uint32_t inuse;
|
||||
uint32_t data_off;
|
||||
char padding[12];
|
||||
} QEMU_PACKED ParallelsHeader;
|
||||
|
||||
|
||||
typedef enum ParallelsPreallocMode {
|
||||
PRL_PREALLOC_MODE_FALLOCATE = 0,
|
||||
PRL_PREALLOC_MODE_TRUNCATE = 1,
|
||||
PRL_PREALLOC_MODE__MAX = 2,
|
||||
} ParallelsPreallocMode;
|
||||
|
||||
static QEnumLookup prealloc_mode_lookup = {
|
||||
.array = (const char *const[]) {
|
||||
"falloc",
|
||||
@@ -55,6 +77,34 @@ static QEnumLookup prealloc_mode_lookup = {
|
||||
.size = PRL_PREALLOC_MODE__MAX
|
||||
};
|
||||
|
||||
typedef struct BDRVParallelsState {
|
||||
/** Locking is conservative, the lock protects
|
||||
* - image file extending (truncate, fallocate)
|
||||
* - any access to block allocation table
|
||||
*/
|
||||
CoMutex lock;
|
||||
|
||||
ParallelsHeader *header;
|
||||
uint32_t header_size;
|
||||
bool header_unclean;
|
||||
|
||||
unsigned long *bat_dirty_bmap;
|
||||
unsigned int bat_dirty_block;
|
||||
|
||||
uint32_t *bat_bitmap;
|
||||
unsigned int bat_size;
|
||||
|
||||
int64_t data_end;
|
||||
uint64_t prealloc_size;
|
||||
ParallelsPreallocMode prealloc_mode;
|
||||
|
||||
unsigned int tracks;
|
||||
|
||||
unsigned int off_multiplier;
|
||||
Error *migration_blocker;
|
||||
} BDRVParallelsState;
|
||||
|
||||
|
||||
#define PARALLELS_OPT_PREALLOC_MODE "prealloc-mode"
|
||||
#define PARALLELS_OPT_PREALLOC_SIZE "prealloc-size"
|
||||
|
||||
@@ -143,7 +193,6 @@ static int64_t block_status(BDRVParallelsState *s, int64_t sector_num,
|
||||
static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
int ret;
|
||||
BDRVParallelsState *s = bs->opaque;
|
||||
int64_t pos, space, idx, to_allocate, i, len;
|
||||
|
||||
@@ -172,6 +221,7 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
|
||||
return len;
|
||||
}
|
||||
if (s->data_end + space > (len >> BDRV_SECTOR_BITS)) {
|
||||
int ret;
|
||||
space += s->prealloc_size;
|
||||
if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) {
|
||||
ret = bdrv_pwrite_zeroes(bs->file,
|
||||
@@ -187,37 +237,6 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to read from backing to fill empty clusters
|
||||
* FIXME: 1. previous write_zeroes may be redundant
|
||||
* 2. most of data we read from backing will be rewritten by
|
||||
* parallels_co_writev. On aligned-to-cluster write we do not need
|
||||
* this read at all.
|
||||
* 3. it would be good to combine write of data from backing and new
|
||||
* data into one write call */
|
||||
if (bs->backing) {
|
||||
int64_t nb_cow_sectors = to_allocate * s->tracks;
|
||||
int64_t nb_cow_bytes = nb_cow_sectors << BDRV_SECTOR_BITS;
|
||||
QEMUIOVector qiov;
|
||||
struct iovec iov = {
|
||||
.iov_len = nb_cow_bytes,
|
||||
.iov_base = qemu_blockalign(bs, nb_cow_bytes)
|
||||
};
|
||||
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||
|
||||
ret = bdrv_co_readv(bs->backing, idx * s->tracks, nb_cow_sectors,
|
||||
&qiov);
|
||||
if (ret < 0) {
|
||||
qemu_vfree(iov.iov_base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bdrv_co_writev(bs->file, s->data_end, nb_cow_sectors, &qiov);
|
||||
qemu_vfree(iov.iov_base);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < to_allocate; i++) {
|
||||
s->bat_bitmap[idx + i] = cpu_to_le32(s->data_end / s->off_multiplier);
|
||||
s->data_end += s->tracks;
|
||||
@@ -341,19 +360,12 @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
|
||||
|
||||
nbytes = n << BDRV_SECTOR_BITS;
|
||||
|
||||
qemu_iovec_reset(&hd_qiov);
|
||||
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
|
||||
|
||||
if (position < 0) {
|
||||
if (bs->backing) {
|
||||
ret = bdrv_co_readv(bs->backing, sector_num, n, &hd_qiov);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
qemu_iovec_memset(&hd_qiov, 0, 0, nbytes);
|
||||
}
|
||||
qemu_iovec_memset(qiov, bytes_done, 0, nbytes);
|
||||
} else {
|
||||
qemu_iovec_reset(&hd_qiov);
|
||||
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
|
||||
|
||||
ret = bdrv_co_readv(bs->file, position, n, &hd_qiov);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
@@ -515,9 +527,8 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
memcpy(header.magic, HEADER_MAGIC2, sizeof(header.magic));
|
||||
header.version = cpu_to_le32(HEADER_VERSION);
|
||||
/* don't care much about geometry, it is not used on image level */
|
||||
header.heads = cpu_to_le32(HEADS_NUMBER);
|
||||
header.cylinders = cpu_to_le32(total_size / BDRV_SECTOR_SIZE
|
||||
/ HEADS_NUMBER / SEC_IN_CYL);
|
||||
header.heads = cpu_to_le32(16);
|
||||
header.cylinders = cpu_to_le32(total_size / BDRV_SECTOR_SIZE / 16 / 32);
|
||||
header.tracks = cpu_to_le32(cl_size >> BDRV_SECTOR_BITS);
|
||||
header.bat_entries = cpu_to_le32(bat_entries);
|
||||
header.nb_sectors = cpu_to_le64(DIV_ROUND_UP(total_size, BDRV_SECTOR_SIZE));
|
||||
@@ -787,7 +798,7 @@ static BlockDriver bdrv_parallels = {
|
||||
.bdrv_co_flush_to_os = parallels_co_flush_to_os,
|
||||
.bdrv_co_readv = parallels_co_readv,
|
||||
.bdrv_co_writev = parallels_co_writev,
|
||||
.supports_backing = true,
|
||||
|
||||
.bdrv_create = parallels_create,
|
||||
.bdrv_check = parallels_check,
|
||||
.create_opts = ¶llels_create_opts,
|
||||
|
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Block driver for Parallels disk image format
|
||||
*
|
||||
* Copyright (c) 2015-2017 Virtuozzo, Inc.
|
||||
* Authors:
|
||||
* 2016-2017 Klim S. Kireev <klim.kireev@virtuozzo.com>
|
||||
* 2015 Denis V. Lunev <den@openvz.org>
|
||||
*
|
||||
* This code was originally based on comparing different disk images created
|
||||
* by Parallels. Currently it is based on opened OpenVZ sources
|
||||
* available at
|
||||
* https://github.com/OpenVZ/ploop
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef BLOCK_PARALLELS_H
|
||||
#define BLOCK_PARALLELS_H
|
||||
#include "qemu/coroutine.h"
|
||||
|
||||
#define HEADS_NUMBER 16
|
||||
#define SEC_IN_CYL 32
|
||||
#define DEFAULT_CLUSTER_SIZE 1048576 /* 1 MiB */
|
||||
|
||||
/* always little-endian */
|
||||
typedef struct ParallelsHeader {
|
||||
char magic[16]; /* "WithoutFreeSpace" */
|
||||
uint32_t version;
|
||||
uint32_t heads;
|
||||
uint32_t cylinders;
|
||||
uint32_t tracks;
|
||||
uint32_t bat_entries;
|
||||
uint64_t nb_sectors;
|
||||
uint32_t inuse;
|
||||
uint32_t data_off;
|
||||
char padding[12];
|
||||
} QEMU_PACKED ParallelsHeader;
|
||||
|
||||
typedef enum ParallelsPreallocMode {
|
||||
PRL_PREALLOC_MODE_FALLOCATE = 0,
|
||||
PRL_PREALLOC_MODE_TRUNCATE = 1,
|
||||
PRL_PREALLOC_MODE__MAX = 2,
|
||||
} ParallelsPreallocMode;
|
||||
|
||||
typedef struct BDRVParallelsState {
|
||||
/** Locking is conservative, the lock protects
|
||||
* - image file extending (truncate, fallocate)
|
||||
* - any access to block allocation table
|
||||
*/
|
||||
CoMutex lock;
|
||||
|
||||
ParallelsHeader *header;
|
||||
uint32_t header_size;
|
||||
bool header_unclean;
|
||||
|
||||
unsigned long *bat_dirty_bmap;
|
||||
unsigned int bat_dirty_block;
|
||||
|
||||
uint32_t *bat_bitmap;
|
||||
unsigned int bat_size;
|
||||
|
||||
int64_t data_end;
|
||||
uint64_t prealloc_size;
|
||||
ParallelsPreallocMode prealloc_mode;
|
||||
|
||||
unsigned int tracks;
|
||||
|
||||
unsigned int off_multiplier;
|
||||
Error *migration_blocker;
|
||||
} BDRVParallelsState;
|
||||
|
||||
#endif
|
@@ -29,13 +29,8 @@
|
||||
#include "block/write-threshold.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qobject-output-visitor.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qapi/qmp/qnum.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
|
21
block/qcow.c
21
block/qcow.c
@@ -21,17 +21,16 @@
|
||||
* 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 "qemu-common.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include <zlib.h>
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "crypto/block.h"
|
||||
#include "migration/blocker.h"
|
||||
@@ -380,7 +379,6 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||
/* update the L1 entry */
|
||||
s->l1_table[l1_index] = l2_offset;
|
||||
tmp = cpu_to_be64(l2_offset);
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
|
||||
ret = bdrv_pwrite_sync(bs->file,
|
||||
s->l1_table_offset + l1_index * sizeof(tmp),
|
||||
&tmp, sizeof(tmp));
|
||||
@@ -411,7 +409,6 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||
}
|
||||
}
|
||||
l2_table = s->l2_cache + (min_index << s->l2_bits);
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
|
||||
if (new_l2_table) {
|
||||
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
|
||||
ret = bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
|
||||
@@ -435,7 +432,6 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||
((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
|
||||
if (!allocate)
|
||||
return 0;
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
|
||||
/* allocate a new cluster */
|
||||
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
|
||||
(n_end - n_start) < s->cluster_sectors) {
|
||||
@@ -451,7 +447,6 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||
}
|
||||
cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
|
||||
/* write the cluster content */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
||||
ret = bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache,
|
||||
s->cluster_size);
|
||||
if (ret < 0) {
|
||||
@@ -491,7 +486,6 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||
NULL) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
||||
ret = bdrv_pwrite(bs->file,
|
||||
cluster_offset + i * 512,
|
||||
s->cluster_data, 512);
|
||||
@@ -509,11 +503,6 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||
/* update L2 table */
|
||||
tmp = cpu_to_be64(cluster_offset);
|
||||
l2_table[l2_index] = tmp;
|
||||
if (allocate == 2) {
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
|
||||
} else {
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
|
||||
}
|
||||
ret = bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
|
||||
&tmp, sizeof(tmp));
|
||||
if (ret < 0) {
|
||||
@@ -590,7 +579,6 @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
|
||||
if (s->cluster_cache_offset != coffset) {
|
||||
csize = cluster_offset >> (63 - s->cluster_bits);
|
||||
csize &= (s->cluster_size - 1);
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
|
||||
ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize);
|
||||
if (ret != csize)
|
||||
return -1;
|
||||
@@ -647,8 +635,6 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
hd_iov.iov_len = n * 512;
|
||||
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
/* qcow2 emits this on bs->file instead of bs->backing */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
|
||||
ret = bdrv_co_readv(bs->backing, sector_num, n, &hd_qiov);
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
if (ret < 0) {
|
||||
@@ -675,7 +661,6 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
hd_iov.iov_len = n * 512;
|
||||
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
|
||||
ret = bdrv_co_readv(bs->file,
|
||||
(cluster_offset >> 9) + index_in_cluster,
|
||||
n, &hd_qiov);
|
||||
@@ -769,7 +754,6 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
hd_iov.iov_len = n * 512;
|
||||
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
||||
ret = bdrv_co_writev(bs->file,
|
||||
(cluster_offset >> 9) + index_in_cluster,
|
||||
n, &hd_qiov);
|
||||
@@ -1064,7 +1048,6 @@ qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||
.iov_len = out_len,
|
||||
};
|
||||
qemu_iovec_init_external(&hd_qiov, &iov, 1);
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
|
||||
ret = bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
|
@@ -933,14 +933,14 @@ static void set_readonly_helper(gpointer bitmap, gpointer value)
|
||||
bdrv_dirty_bitmap_set_readonly(bitmap, (bool)value);
|
||||
}
|
||||
|
||||
/* qcow2_load_dirty_bitmaps()
|
||||
/* qcow2_load_autoloading_dirty_bitmaps()
|
||||
* Return value is a hint for caller: true means that the Qcow2 header was
|
||||
* updated. (false doesn't mean that the header should be updated by the
|
||||
* caller, it just means that updating was not needed or the image cannot be
|
||||
* written to).
|
||||
* On failure the function returns false.
|
||||
*/
|
||||
bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp)
|
||||
bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
Qcow2BitmapList *bm_list;
|
||||
@@ -960,16 +960,14 @@ bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp)
|
||||
}
|
||||
|
||||
QSIMPLEQ_FOREACH(bm, bm_list, entry) {
|
||||
if (!(bm->flags & BME_FLAG_IN_USE)) {
|
||||
if ((bm->flags & BME_FLAG_AUTO) && !(bm->flags & BME_FLAG_IN_USE)) {
|
||||
BdrvDirtyBitmap *bitmap = load_bitmap(bs, bm, errp);
|
||||
if (bitmap == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(bm->flags & BME_FLAG_AUTO)) {
|
||||
bdrv_disable_dirty_bitmap(bitmap);
|
||||
}
|
||||
bdrv_dirty_bitmap_set_persistance(bitmap, true);
|
||||
bdrv_dirty_bitmap_set_autoload(bitmap, true);
|
||||
bm->flags |= BME_FLAG_IN_USE;
|
||||
created_dirty_bitmaps =
|
||||
g_slist_append(created_dirty_bitmaps, bitmap);
|
||||
@@ -1371,7 +1369,7 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
|
||||
bm->table.size = 0;
|
||||
QSIMPLEQ_INSERT_TAIL(&drop_tables, tb, entry);
|
||||
}
|
||||
bm->flags = bdrv_dirty_bitmap_enabled(bitmap) ? BME_FLAG_AUTO : 0;
|
||||
bm->flags = bdrv_dirty_bitmap_get_autoload(bitmap) ? BME_FLAG_AUTO : 0;
|
||||
bm->granularity_bits = ctz32(bdrv_dirty_bitmap_granularity(bitmap));
|
||||
bm->dirty_bitmap = bitmap;
|
||||
}
|
||||
@@ -1451,16 +1449,6 @@ bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs,
|
||||
bool found;
|
||||
Qcow2BitmapList *bm_list;
|
||||
|
||||
if (s->qcow_version < 3) {
|
||||
/* Without autoclear_features, we would always have to assume
|
||||
* that a program without persistent dirty bitmap support has
|
||||
* accessed this qcow2 file when opening it, and would thus
|
||||
* have to drop all dirty bitmaps (defeating their purpose).
|
||||
*/
|
||||
error_setg(errp, "Cannot store dirty bitmaps in qcow2 v2 files");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (check_constraints_on_bitmap(bs, name, granularity, errp) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
@@ -39,23 +39,26 @@ struct Qcow2Cache {
|
||||
Qcow2CachedTable *entries;
|
||||
struct Qcow2Cache *depends;
|
||||
int size;
|
||||
int table_size;
|
||||
bool depends_on_flush;
|
||||
void *table_array;
|
||||
uint64_t lru_counter;
|
||||
uint64_t cache_clean_lru_counter;
|
||||
};
|
||||
|
||||
static inline void *qcow2_cache_get_table_addr(Qcow2Cache *c, int table)
|
||||
static inline void *qcow2_cache_get_table_addr(BlockDriverState *bs,
|
||||
Qcow2Cache *c, int table)
|
||||
{
|
||||
return (uint8_t *) c->table_array + (size_t) table * c->table_size;
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
return (uint8_t *) c->table_array + (size_t) table * s->cluster_size;
|
||||
}
|
||||
|
||||
static inline int qcow2_cache_get_table_idx(Qcow2Cache *c, void *table)
|
||||
static inline int qcow2_cache_get_table_idx(BlockDriverState *bs,
|
||||
Qcow2Cache *c, void *table)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
ptrdiff_t table_offset = (uint8_t *) table - (uint8_t *) c->table_array;
|
||||
int idx = table_offset / c->table_size;
|
||||
assert(idx >= 0 && idx < c->size && table_offset % c->table_size == 0);
|
||||
int idx = table_offset / s->cluster_size;
|
||||
assert(idx >= 0 && idx < c->size && table_offset % s->cluster_size == 0);
|
||||
return idx;
|
||||
}
|
||||
|
||||
@@ -71,13 +74,15 @@ static inline const char *qcow2_cache_get_name(BDRVQcow2State *s, Qcow2Cache *c)
|
||||
}
|
||||
}
|
||||
|
||||
static void qcow2_cache_table_release(Qcow2Cache *c, int i, int num_tables)
|
||||
static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
|
||||
int i, int num_tables)
|
||||
{
|
||||
/* Using MADV_DONTNEED to discard memory is a Linux-specific feature */
|
||||
#ifdef CONFIG_LINUX
|
||||
void *t = qcow2_cache_get_table_addr(c, i);
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
void *t = qcow2_cache_get_table_addr(bs, c, i);
|
||||
int align = getpagesize();
|
||||
size_t mem_size = (size_t) c->table_size * num_tables;
|
||||
size_t mem_size = (size_t) s->cluster_size * num_tables;
|
||||
size_t offset = QEMU_ALIGN_UP((uintptr_t) t, align) - (uintptr_t) t;
|
||||
size_t length = QEMU_ALIGN_DOWN(mem_size - offset, align);
|
||||
if (mem_size > offset && length > 0) {
|
||||
@@ -93,7 +98,7 @@ static inline bool can_clean_entry(Qcow2Cache *c, int i)
|
||||
t->lru_counter <= c->cache_clean_lru_counter;
|
||||
}
|
||||
|
||||
void qcow2_cache_clean_unused(Qcow2Cache *c)
|
||||
void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < c->size) {
|
||||
@@ -113,30 +118,23 @@ void qcow2_cache_clean_unused(Qcow2Cache *c)
|
||||
}
|
||||
|
||||
if (to_clean > 0) {
|
||||
qcow2_cache_table_release(c, i - to_clean, to_clean);
|
||||
qcow2_cache_table_release(bs, c, i - to_clean, to_clean);
|
||||
}
|
||||
}
|
||||
|
||||
c->cache_clean_lru_counter = c->lru_counter;
|
||||
}
|
||||
|
||||
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
|
||||
unsigned table_size)
|
||||
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
Qcow2Cache *c;
|
||||
|
||||
assert(num_tables > 0);
|
||||
assert(is_power_of_2(table_size));
|
||||
assert(table_size >= (1 << MIN_CLUSTER_BITS));
|
||||
assert(table_size <= s->cluster_size);
|
||||
|
||||
c = g_new0(Qcow2Cache, 1);
|
||||
c->size = num_tables;
|
||||
c->table_size = table_size;
|
||||
c->entries = g_try_new0(Qcow2CachedTable, num_tables);
|
||||
c->table_array = qemu_try_blockalign(bs->file->bs,
|
||||
(size_t) num_tables * c->table_size);
|
||||
(size_t) num_tables * s->cluster_size);
|
||||
|
||||
if (!c->entries || !c->table_array) {
|
||||
qemu_vfree(c->table_array);
|
||||
@@ -148,7 +146,7 @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
|
||||
return c;
|
||||
}
|
||||
|
||||
int qcow2_cache_destroy(Qcow2Cache *c)
|
||||
int qcow2_cache_destroy(BlockDriverState *bs, Qcow2Cache *c)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -205,13 +203,13 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
|
||||
|
||||
if (c == s->refcount_block_cache) {
|
||||
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_REFCOUNT_BLOCK,
|
||||
c->entries[i].offset, c->table_size);
|
||||
c->entries[i].offset, s->cluster_size);
|
||||
} else if (c == s->l2_table_cache) {
|
||||
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2,
|
||||
c->entries[i].offset, c->table_size);
|
||||
c->entries[i].offset, s->cluster_size);
|
||||
} else {
|
||||
ret = qcow2_pre_write_overlap_check(bs, 0,
|
||||
c->entries[i].offset, c->table_size);
|
||||
c->entries[i].offset, s->cluster_size);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
@@ -225,7 +223,7 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
|
||||
}
|
||||
|
||||
ret = bdrv_pwrite(bs->file, c->entries[i].offset,
|
||||
qcow2_cache_get_table_addr(c, i), c->table_size);
|
||||
qcow2_cache_get_table_addr(bs, c, i), s->cluster_size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -311,7 +309,7 @@ int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c)
|
||||
c->entries[i].lru_counter = 0;
|
||||
}
|
||||
|
||||
qcow2_cache_table_release(c, 0, c->size);
|
||||
qcow2_cache_table_release(bs, c, 0, c->size);
|
||||
|
||||
c->lru_counter = 0;
|
||||
|
||||
@@ -333,7 +331,7 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
|
||||
trace_qcow2_cache_get(qemu_coroutine_self(), c == s->l2_table_cache,
|
||||
offset, read_from_disk);
|
||||
|
||||
if (!QEMU_IS_ALIGNED(offset, c->table_size)) {
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
qcow2_signal_corruption(bs, true, -1, -1, "Cannot get entry from %s "
|
||||
"cache: Offset %#" PRIx64 " is unaligned",
|
||||
qcow2_cache_get_name(s, c), offset);
|
||||
@@ -341,7 +339,7 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
|
||||
}
|
||||
|
||||
/* Check if the table is already cached */
|
||||
i = lookup_index = (offset / c->table_size * 4) % c->size;
|
||||
i = lookup_index = (offset / s->cluster_size * 4) % c->size;
|
||||
do {
|
||||
const Qcow2CachedTable *t = &c->entries[i];
|
||||
if (t->offset == offset) {
|
||||
@@ -381,8 +379,8 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
|
||||
}
|
||||
|
||||
ret = bdrv_pread(bs->file, offset,
|
||||
qcow2_cache_get_table_addr(c, i),
|
||||
c->table_size);
|
||||
qcow2_cache_get_table_addr(bs, c, i),
|
||||
s->cluster_size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -393,7 +391,7 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
|
||||
/* And return the right table */
|
||||
found:
|
||||
c->entries[i].ref++;
|
||||
*table = qcow2_cache_get_table_addr(c, i);
|
||||
*table = qcow2_cache_get_table_addr(bs, c, i);
|
||||
|
||||
trace_qcow2_cache_get_done(qemu_coroutine_self(),
|
||||
c == s->l2_table_cache, i);
|
||||
@@ -413,9 +411,9 @@ int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
|
||||
return qcow2_cache_do_get(bs, c, offset, table, false);
|
||||
}
|
||||
|
||||
void qcow2_cache_put(Qcow2Cache *c, void **table)
|
||||
void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
|
||||
{
|
||||
int i = qcow2_cache_get_table_idx(c, *table);
|
||||
int i = qcow2_cache_get_table_idx(bs, c, *table);
|
||||
|
||||
c->entries[i].ref--;
|
||||
*table = NULL;
|
||||
@@ -427,28 +425,30 @@ void qcow2_cache_put(Qcow2Cache *c, void **table)
|
||||
assert(c->entries[i].ref >= 0);
|
||||
}
|
||||
|
||||
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table)
|
||||
void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c,
|
||||
void *table)
|
||||
{
|
||||
int i = qcow2_cache_get_table_idx(c, table);
|
||||
int i = qcow2_cache_get_table_idx(bs, c, table);
|
||||
assert(c->entries[i].offset != 0);
|
||||
c->entries[i].dirty = true;
|
||||
}
|
||||
|
||||
void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset)
|
||||
void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
|
||||
uint64_t offset)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < c->size; i++) {
|
||||
if (c->entries[i].offset == offset) {
|
||||
return qcow2_cache_get_table_addr(c, i);
|
||||
return qcow2_cache_get_table_addr(bs, c, i);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qcow2_cache_discard(Qcow2Cache *c, void *table)
|
||||
void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table)
|
||||
{
|
||||
int i = qcow2_cache_get_table_idx(c, table);
|
||||
int i = qcow2_cache_get_table_idx(bs, c, table);
|
||||
|
||||
assert(c->entries[i].ref == 0);
|
||||
|
||||
@@ -456,5 +456,5 @@ void qcow2_cache_discard(Qcow2Cache *c, void *table)
|
||||
c->entries[i].lru_counter = 0;
|
||||
c->entries[i].dirty = false;
|
||||
|
||||
qcow2_cache_table_release(c, i, 1);
|
||||
qcow2_cache_table_release(bs, c, i, 1);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -277,7 +277,7 @@ int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
|
||||
block_index = cluster_index & (s->refcount_block_size - 1);
|
||||
*refcount = s->get_refcount(refcount_block, block_index);
|
||||
|
||||
qcow2_cache_put(s->refcount_block_cache, &refcount_block);
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -421,7 +421,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
|
||||
/* Now the new refcount block needs to be written to disk */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE);
|
||||
qcow2_cache_entry_mark_dirty(s->refcount_block_cache, *refcount_block);
|
||||
qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache, *refcount_block);
|
||||
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
@@ -449,7 +449,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
qcow2_cache_put(s->refcount_block_cache, refcount_block);
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
|
||||
|
||||
/*
|
||||
* If we come here, we need to grow the refcount table. Again, a new
|
||||
@@ -501,7 +501,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
|
||||
fail:
|
||||
if (*refcount_block != NULL) {
|
||||
qcow2_cache_put(s->refcount_block_cache, refcount_block);
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -623,7 +623,7 @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
|
||||
goto fail;
|
||||
}
|
||||
memset(refblock_data, 0, s->cluster_size);
|
||||
qcow2_cache_entry_mark_dirty(s->refcount_block_cache,
|
||||
qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
|
||||
refblock_data);
|
||||
|
||||
new_table[i] = block_offset;
|
||||
@@ -656,11 +656,11 @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
|
||||
s->set_refcount(refblock_data, j, 1);
|
||||
}
|
||||
|
||||
qcow2_cache_entry_mark_dirty(s->refcount_block_cache,
|
||||
qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
|
||||
refblock_data);
|
||||
}
|
||||
|
||||
qcow2_cache_put(s->refcount_block_cache, &refblock_data);
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, &refblock_data);
|
||||
}
|
||||
|
||||
assert(block_offset == table_offset);
|
||||
@@ -836,7 +836,7 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||
/* Load the refcount block and allocate it if needed */
|
||||
if (table_index != old_table_index) {
|
||||
if (refcount_block) {
|
||||
qcow2_cache_put(s->refcount_block_cache, &refcount_block);
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
|
||||
}
|
||||
ret = alloc_refcount_block(bs, cluster_index, &refcount_block);
|
||||
if (ret < 0) {
|
||||
@@ -845,7 +845,8 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||
}
|
||||
old_table_index = table_index;
|
||||
|
||||
qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refcount_block);
|
||||
qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
|
||||
refcount_block);
|
||||
|
||||
/* we can update the count and save it */
|
||||
block_index = cluster_index & (s->refcount_block_size - 1);
|
||||
@@ -871,16 +872,16 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||
if (refcount == 0) {
|
||||
void *table;
|
||||
|
||||
table = qcow2_cache_is_table_offset(s->refcount_block_cache,
|
||||
table = qcow2_cache_is_table_offset(bs, s->refcount_block_cache,
|
||||
offset);
|
||||
if (table != NULL) {
|
||||
qcow2_cache_put(s->refcount_block_cache, &refcount_block);
|
||||
qcow2_cache_discard(s->refcount_block_cache, table);
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
|
||||
qcow2_cache_discard(bs, s->refcount_block_cache, table);
|
||||
}
|
||||
|
||||
table = qcow2_cache_is_table_offset(s->l2_table_cache, offset);
|
||||
table = qcow2_cache_is_table_offset(bs, s->l2_table_cache, offset);
|
||||
if (table != NULL) {
|
||||
qcow2_cache_discard(s->l2_table_cache, table);
|
||||
qcow2_cache_discard(bs, s->l2_table_cache, table);
|
||||
}
|
||||
|
||||
if (s->discard_passthrough[type]) {
|
||||
@@ -897,7 +898,7 @@ fail:
|
||||
|
||||
/* Write last changed block to disk */
|
||||
if (refcount_block) {
|
||||
qcow2_cache_put(s->refcount_block_cache, &refcount_block);
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1183,20 +1184,17 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
int64_t l1_table_offset, int l1_size, int addend)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint64_t *l1_table, *l2_slice, l2_offset, entry, l1_size2, refcount;
|
||||
uint64_t *l1_table, *l2_table, l2_offset, entry, l1_size2, refcount;
|
||||
bool l1_allocated = false;
|
||||
int64_t old_entry, old_l2_offset;
|
||||
unsigned slice, slice_size2, n_slices;
|
||||
int i, j, l1_modified = 0, nb_csectors;
|
||||
int ret;
|
||||
|
||||
assert(addend >= -1 && addend <= 1);
|
||||
|
||||
l2_slice = NULL;
|
||||
l2_table = NULL;
|
||||
l1_table = NULL;
|
||||
l1_size2 = l1_size * sizeof(uint64_t);
|
||||
slice_size2 = s->l2_slice_size * sizeof(uint64_t);
|
||||
n_slices = s->cluster_size / slice_size2;
|
||||
|
||||
s->cache_discards = true;
|
||||
|
||||
@@ -1239,98 +1237,92 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (slice = 0; slice < n_slices; slice++) {
|
||||
ret = qcow2_cache_get(bs, s->l2_table_cache,
|
||||
l2_offset + slice * slice_size2,
|
||||
(void **) &l2_slice);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
|
||||
(void**) &l2_table);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (j = 0; j < s->l2_slice_size; j++) {
|
||||
uint64_t cluster_index;
|
||||
uint64_t offset;
|
||||
for (j = 0; j < s->l2_size; j++) {
|
||||
uint64_t cluster_index;
|
||||
uint64_t offset;
|
||||
|
||||
entry = be64_to_cpu(l2_slice[j]);
|
||||
old_entry = entry;
|
||||
entry &= ~QCOW_OFLAG_COPIED;
|
||||
offset = entry & L2E_OFFSET_MASK;
|
||||
entry = be64_to_cpu(l2_table[j]);
|
||||
old_entry = entry;
|
||||
entry &= ~QCOW_OFLAG_COPIED;
|
||||
offset = entry & L2E_OFFSET_MASK;
|
||||
|
||||
switch (qcow2_get_cluster_type(entry)) {
|
||||
case QCOW2_CLUSTER_COMPRESSED:
|
||||
nb_csectors = ((entry >> s->csize_shift) &
|
||||
s->csize_mask) + 1;
|
||||
if (addend != 0) {
|
||||
ret = update_refcount(
|
||||
bs, (entry & s->cluster_offset_mask) & ~511,
|
||||
switch (qcow2_get_cluster_type(entry)) {
|
||||
case QCOW2_CLUSTER_COMPRESSED:
|
||||
nb_csectors = ((entry >> s->csize_shift) &
|
||||
s->csize_mask) + 1;
|
||||
if (addend != 0) {
|
||||
ret = update_refcount(bs,
|
||||
(entry & s->cluster_offset_mask) & ~511,
|
||||
nb_csectors * 512, abs(addend), addend < 0,
|
||||
QCOW2_DISCARD_SNAPSHOT);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
/* compressed clusters are never modified */
|
||||
refcount = 2;
|
||||
break;
|
||||
|
||||
case QCOW2_CLUSTER_NORMAL:
|
||||
case QCOW2_CLUSTER_ZERO_ALLOC:
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
/* Here l2_index means table (not slice) index */
|
||||
int l2_index = slice * s->l2_slice_size + j;
|
||||
qcow2_signal_corruption(
|
||||
bs, true, -1, -1, "Cluster "
|
||||
"allocation offset %#" PRIx64
|
||||
" unaligned (L2 offset: %#"
|
||||
PRIx64 ", L2 index: %#x)",
|
||||
offset, l2_offset, l2_index);
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
cluster_index = offset >> s->cluster_bits;
|
||||
assert(cluster_index);
|
||||
if (addend != 0) {
|
||||
ret = qcow2_update_cluster_refcount(
|
||||
bs, cluster_index, abs(addend), addend < 0,
|
||||
QCOW2_DISCARD_SNAPSHOT);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = qcow2_get_refcount(bs, cluster_index, &refcount);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* compressed clusters are never modified */
|
||||
refcount = 2;
|
||||
break;
|
||||
|
||||
case QCOW2_CLUSTER_ZERO_PLAIN:
|
||||
case QCOW2_CLUSTER_UNALLOCATED:
|
||||
refcount = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
case QCOW2_CLUSTER_NORMAL:
|
||||
case QCOW2_CLUSTER_ZERO_ALLOC:
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
qcow2_signal_corruption(bs, true, -1, -1, "Cluster "
|
||||
"allocation offset %#" PRIx64
|
||||
" unaligned (L2 offset: %#"
|
||||
PRIx64 ", L2 index: %#x)",
|
||||
offset, l2_offset, j);
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (refcount == 1) {
|
||||
entry |= QCOW_OFLAG_COPIED;
|
||||
}
|
||||
if (entry != old_entry) {
|
||||
if (addend > 0) {
|
||||
qcow2_cache_set_dependency(bs, s->l2_table_cache,
|
||||
s->refcount_block_cache);
|
||||
cluster_index = offset >> s->cluster_bits;
|
||||
assert(cluster_index);
|
||||
if (addend != 0) {
|
||||
ret = qcow2_update_cluster_refcount(bs,
|
||||
cluster_index, abs(addend), addend < 0,
|
||||
QCOW2_DISCARD_SNAPSHOT);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
l2_slice[j] = cpu_to_be64(entry);
|
||||
qcow2_cache_entry_mark_dirty(s->l2_table_cache,
|
||||
l2_slice);
|
||||
}
|
||||
|
||||
ret = qcow2_get_refcount(bs, cluster_index, &refcount);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
||||
case QCOW2_CLUSTER_ZERO_PLAIN:
|
||||
case QCOW2_CLUSTER_UNALLOCATED:
|
||||
refcount = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
|
||||
if (refcount == 1) {
|
||||
entry |= QCOW_OFLAG_COPIED;
|
||||
}
|
||||
if (entry != old_entry) {
|
||||
if (addend > 0) {
|
||||
qcow2_cache_set_dependency(bs, s->l2_table_cache,
|
||||
s->refcount_block_cache);
|
||||
}
|
||||
l2_table[j] = cpu_to_be64(entry);
|
||||
qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache,
|
||||
l2_table);
|
||||
}
|
||||
}
|
||||
|
||||
qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
|
||||
|
||||
if (addend != 0) {
|
||||
ret = qcow2_update_cluster_refcount(bs, l2_offset >>
|
||||
s->cluster_bits,
|
||||
@@ -1356,8 +1348,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
|
||||
ret = bdrv_flush(bs);
|
||||
fail:
|
||||
if (l2_slice) {
|
||||
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
|
||||
if (l2_table) {
|
||||
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||
}
|
||||
|
||||
s->cache_discards = false;
|
||||
@@ -1516,7 +1508,7 @@ enum {
|
||||
static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
void **refcount_table,
|
||||
int64_t *refcount_table_size, int64_t l2_offset,
|
||||
int flags, BdrvCheckMode fix)
|
||||
int flags)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint64_t *l2_table, l2_entry;
|
||||
@@ -1587,57 +1579,6 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
next_contiguous_offset = offset + s->cluster_size;
|
||||
}
|
||||
|
||||
/* Correct offsets are cluster aligned */
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
if (qcow2_get_cluster_type(l2_entry) ==
|
||||
QCOW2_CLUSTER_ZERO_ALLOC)
|
||||
{
|
||||
fprintf(stderr, "%s offset=%" PRIx64 ": Preallocated zero "
|
||||
"cluster is not properly aligned; L2 entry "
|
||||
"corrupted.\n",
|
||||
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR",
|
||||
offset);
|
||||
if (fix & BDRV_FIX_ERRORS) {
|
||||
uint64_t l2e_offset =
|
||||
l2_offset + (uint64_t)i * sizeof(uint64_t);
|
||||
|
||||
l2_entry = QCOW_OFLAG_ZERO;
|
||||
l2_table[i] = cpu_to_be64(l2_entry);
|
||||
ret = qcow2_pre_write_overlap_check(bs,
|
||||
QCOW2_OL_ACTIVE_L2 | QCOW2_OL_INACTIVE_L2,
|
||||
l2e_offset, sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ERROR: Overlap check failed\n");
|
||||
res->check_errors++;
|
||||
/* Something is seriously wrong, so abort checking
|
||||
* this L2 table */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = bdrv_pwrite_sync(bs->file, l2e_offset,
|
||||
&l2_table[i], sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ERROR: Failed to overwrite L2 "
|
||||
"table entry: %s\n", strerror(-ret));
|
||||
res->check_errors++;
|
||||
/* Do not abort, continue checking the rest of this
|
||||
* L2 table's entries */
|
||||
} else {
|
||||
res->corruptions_fixed++;
|
||||
/* Skip marking the cluster as used
|
||||
* (it is unused now) */
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
res->corruptions++;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "ERROR offset=%" PRIx64 ": Data cluster is "
|
||||
"not properly aligned; L2 entry corrupted.\n", offset);
|
||||
res->corruptions++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark cluster as used */
|
||||
ret = qcow2_inc_refcounts_imrt(bs, res,
|
||||
refcount_table, refcount_table_size,
|
||||
@@ -1645,6 +1586,13 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Correct offsets are cluster aligned */
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
|
||||
"properly aligned; L2 entry corrupted.\n", offset);
|
||||
res->corruptions++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1678,7 +1626,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
||||
void **refcount_table,
|
||||
int64_t *refcount_table_size,
|
||||
int64_t l1_table_offset, int l1_size,
|
||||
int flags, BdrvCheckMode fix)
|
||||
int flags)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint64_t *l1_table = NULL, l2_offset, l1_size2;
|
||||
@@ -1733,8 +1681,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
||||
|
||||
/* Process and check L2 entries */
|
||||
ret = check_refcounts_l2(bs, res, refcount_table,
|
||||
refcount_table_size, l2_offset, flags,
|
||||
fix);
|
||||
refcount_table_size, l2_offset, flags);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -2010,8 +1957,7 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
|
||||
/* current L1 table */
|
||||
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
|
||||
s->l1_table_offset, s->l1_size, CHECK_FRAG_INFO,
|
||||
fix);
|
||||
s->l1_table_offset, s->l1_size, CHECK_FRAG_INFO);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -2020,7 +1966,7 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
for (i = 0; i < s->nb_snapshots; i++) {
|
||||
sn = s->snapshots + i;
|
||||
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
|
||||
sn->l1_table_offset, sn->l1_size, 0, fix);
|
||||
sn->l1_table_offset, sn->l1_size, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -2857,7 +2803,7 @@ static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
|
||||
new_reftable_size, new_refblock,
|
||||
new_refblock_empty, allocated, errp);
|
||||
if (ret < 0) {
|
||||
qcow2_cache_put(s->refcount_block_cache, &refblock);
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2870,7 +2816,7 @@ static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
|
||||
if (new_refcount_bits < 64 && refcount >> new_refcount_bits) {
|
||||
uint64_t offset;
|
||||
|
||||
qcow2_cache_put(s->refcount_block_cache, &refblock);
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
|
||||
|
||||
offset = ((reftable_index << s->refcount_block_bits)
|
||||
+ refblock_index) << s->cluster_bits;
|
||||
@@ -2891,7 +2837,7 @@ static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
|
||||
new_refblock_empty = new_refblock_empty && refcount == 0;
|
||||
}
|
||||
|
||||
qcow2_cache_put(s->refcount_block_cache, &refblock);
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
|
||||
} else {
|
||||
/* No refblock means every refcount is 0 */
|
||||
for (refblock_index = 0; refblock_index < s->refcount_block_size;
|
||||
@@ -3183,24 +3129,24 @@ static int qcow2_discard_refcount_block(BlockDriverState *bs,
|
||||
offset_to_reftable_index(s, discard_block_offs),
|
||||
discard_block_offs,
|
||||
s->get_refcount(refblock, block_index));
|
||||
qcow2_cache_put(s->refcount_block_cache, &refblock);
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
|
||||
return -EINVAL;
|
||||
}
|
||||
s->set_refcount(refblock, block_index, 0);
|
||||
|
||||
qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refblock);
|
||||
qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache, refblock);
|
||||
|
||||
qcow2_cache_put(s->refcount_block_cache, &refblock);
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
|
||||
|
||||
if (cluster_index < s->free_cluster_index) {
|
||||
s->free_cluster_index = cluster_index;
|
||||
}
|
||||
|
||||
refblock = qcow2_cache_is_table_offset(s->refcount_block_cache,
|
||||
refblock = qcow2_cache_is_table_offset(bs, s->refcount_block_cache,
|
||||
discard_block_offs);
|
||||
if (refblock) {
|
||||
/* discard refblock from the cache if refblock is cached */
|
||||
qcow2_cache_discard(s->refcount_block_cache, refblock);
|
||||
qcow2_cache_discard(bs, s->refcount_block_cache, refblock);
|
||||
}
|
||||
update_refcount_discard(bs, discard_block_offs, s->cluster_size);
|
||||
|
||||
@@ -3243,7 +3189,7 @@ int qcow2_shrink_reftable(BlockDriverState *bs)
|
||||
} else {
|
||||
unused_block = buffer_is_zero(refblock, s->cluster_size);
|
||||
}
|
||||
qcow2_cache_put(s->refcount_block_cache, &refblock);
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
|
||||
|
||||
reftable_tmp[i] = unused_block ? 0 : cpu_to_be64(s->refcount_table[i]);
|
||||
}
|
||||
|
137
block/qcow2.c
137
block/qcow2.c
@@ -21,7 +21,6 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
@@ -29,10 +28,9 @@
|
||||
#include <zlib.h>
|
||||
#include "block/qcow2.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "qapi-event.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/option_int.h"
|
||||
@@ -304,17 +302,9 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||
}
|
||||
|
||||
if (!(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS)) {
|
||||
if (s->qcow_version < 3) {
|
||||
/* Let's be a bit more specific */
|
||||
warn_report("This qcow2 v2 image contains bitmaps, but "
|
||||
"they may have been modified by a program "
|
||||
"without persistent bitmap support; so now "
|
||||
"they must all be considered inconsistent");
|
||||
} else {
|
||||
warn_report("a program lacking bitmap support "
|
||||
"modified this file, so all bitmaps are now "
|
||||
"considered inconsistent");
|
||||
}
|
||||
warn_report("a program lacking bitmap support "
|
||||
"modified this file, so all bitmaps are now "
|
||||
"considered inconsistent");
|
||||
error_printf("Some clusters may be leaked, "
|
||||
"run 'qemu-img check -r' on the image "
|
||||
"file to fix.");
|
||||
@@ -675,11 +665,6 @@ static QemuOptsList qcow2_runtime_opts = {
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "Maximum L2 table cache size",
|
||||
},
|
||||
{
|
||||
.name = QCOW2_OPT_L2_CACHE_ENTRY_SIZE,
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "Size of each entry in the L2 cache",
|
||||
},
|
||||
{
|
||||
.name = QCOW2_OPT_REFCOUNT_CACHE_SIZE,
|
||||
.type = QEMU_OPT_SIZE,
|
||||
@@ -711,8 +696,8 @@ static void cache_clean_timer_cb(void *opaque)
|
||||
{
|
||||
BlockDriverState *bs = opaque;
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
qcow2_cache_clean_unused(s->l2_table_cache);
|
||||
qcow2_cache_clean_unused(s->refcount_block_cache);
|
||||
qcow2_cache_clean_unused(bs, s->l2_table_cache);
|
||||
qcow2_cache_clean_unused(bs, s->refcount_block_cache);
|
||||
timer_mod(s->cache_clean_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
|
||||
(int64_t) s->cache_clean_interval * 1000);
|
||||
}
|
||||
@@ -752,7 +737,6 @@ static void qcow2_attach_aio_context(BlockDriverState *bs,
|
||||
|
||||
static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
|
||||
uint64_t *l2_cache_size,
|
||||
uint64_t *l2_cache_entry_size,
|
||||
uint64_t *refcount_cache_size, Error **errp)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
@@ -768,9 +752,6 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
|
||||
*refcount_cache_size = qemu_opt_get_size(opts,
|
||||
QCOW2_OPT_REFCOUNT_CACHE_SIZE, 0);
|
||||
|
||||
*l2_cache_entry_size = qemu_opt_get_size(
|
||||
opts, QCOW2_OPT_L2_CACHE_ENTRY_SIZE, s->cluster_size);
|
||||
|
||||
if (combined_cache_size_set) {
|
||||
if (l2_cache_size_set && refcount_cache_size_set) {
|
||||
error_setg(errp, QCOW2_OPT_CACHE_SIZE ", " QCOW2_OPT_L2_CACHE_SIZE
|
||||
@@ -811,21 +792,11 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
|
||||
/ DEFAULT_L2_REFCOUNT_SIZE_RATIO;
|
||||
}
|
||||
}
|
||||
|
||||
if (*l2_cache_entry_size < (1 << MIN_CLUSTER_BITS) ||
|
||||
*l2_cache_entry_size > s->cluster_size ||
|
||||
!is_power_of_2(*l2_cache_entry_size)) {
|
||||
error_setg(errp, "L2 cache entry size must be a power of two "
|
||||
"between %d and the cluster size (%d)",
|
||||
1 << MIN_CLUSTER_BITS, s->cluster_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct Qcow2ReopenState {
|
||||
Qcow2Cache *l2_table_cache;
|
||||
Qcow2Cache *refcount_block_cache;
|
||||
int l2_slice_size; /* Number of entries in a slice of the L2 table */
|
||||
bool use_lazy_refcounts;
|
||||
int overlap_check;
|
||||
bool discard_passthrough[QCOW2_DISCARD_MAX];
|
||||
@@ -842,7 +813,7 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
|
||||
QemuOpts *opts = NULL;
|
||||
const char *opt_overlap_check, *opt_overlap_check_template;
|
||||
int overlap_check_template = 0;
|
||||
uint64_t l2_cache_size, l2_cache_entry_size, refcount_cache_size;
|
||||
uint64_t l2_cache_size, refcount_cache_size;
|
||||
int i;
|
||||
const char *encryptfmt;
|
||||
QDict *encryptopts = NULL;
|
||||
@@ -861,15 +832,15 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
/* get L2 table/refcount block cache size from command line options */
|
||||
read_cache_sizes(bs, opts, &l2_cache_size, &l2_cache_entry_size,
|
||||
&refcount_cache_size, &local_err);
|
||||
read_cache_sizes(bs, opts, &l2_cache_size, &refcount_cache_size,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
l2_cache_size /= l2_cache_entry_size;
|
||||
l2_cache_size /= s->cluster_size;
|
||||
if (l2_cache_size < MIN_L2_CACHE_SIZE) {
|
||||
l2_cache_size = MIN_L2_CACHE_SIZE;
|
||||
}
|
||||
@@ -907,11 +878,8 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
|
||||
}
|
||||
}
|
||||
|
||||
r->l2_slice_size = l2_cache_entry_size / sizeof(uint64_t);
|
||||
r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size,
|
||||
l2_cache_entry_size);
|
||||
r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size,
|
||||
s->cluster_size);
|
||||
r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
|
||||
r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
|
||||
if (r->l2_table_cache == NULL || r->refcount_block_cache == NULL) {
|
||||
error_setg(errp, "Could not allocate metadata caches");
|
||||
ret = -ENOMEM;
|
||||
@@ -1066,14 +1034,13 @@ static void qcow2_update_options_commit(BlockDriverState *bs,
|
||||
int i;
|
||||
|
||||
if (s->l2_table_cache) {
|
||||
qcow2_cache_destroy(s->l2_table_cache);
|
||||
qcow2_cache_destroy(bs, s->l2_table_cache);
|
||||
}
|
||||
if (s->refcount_block_cache) {
|
||||
qcow2_cache_destroy(s->refcount_block_cache);
|
||||
qcow2_cache_destroy(bs, s->refcount_block_cache);
|
||||
}
|
||||
s->l2_table_cache = r->l2_table_cache;
|
||||
s->refcount_block_cache = r->refcount_block_cache;
|
||||
s->l2_slice_size = r->l2_slice_size;
|
||||
|
||||
s->overlap_check = r->overlap_check;
|
||||
s->use_lazy_refcounts = r->use_lazy_refcounts;
|
||||
@@ -1096,10 +1063,10 @@ static void qcow2_update_options_abort(BlockDriverState *bs,
|
||||
Qcow2ReopenState *r)
|
||||
{
|
||||
if (r->l2_table_cache) {
|
||||
qcow2_cache_destroy(r->l2_table_cache);
|
||||
qcow2_cache_destroy(bs, r->l2_table_cache);
|
||||
}
|
||||
if (r->refcount_block_cache) {
|
||||
qcow2_cache_destroy(r->refcount_block_cache);
|
||||
qcow2_cache_destroy(bs, r->refcount_block_cache);
|
||||
}
|
||||
qapi_free_QCryptoBlockOpenOptions(r->crypto_opts);
|
||||
}
|
||||
@@ -1483,7 +1450,7 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->autoclear_features &= QCOW2_AUTOCLEAR_MASK;
|
||||
}
|
||||
|
||||
if (qcow2_load_dirty_bitmaps(bs, &local_err)) {
|
||||
if (qcow2_load_autoloading_dirty_bitmaps(bs, &local_err)) {
|
||||
update_header = false;
|
||||
}
|
||||
if (local_err != NULL) {
|
||||
@@ -1502,7 +1469,7 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
/* Initialise locks */
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
bs->supported_zero_flags = header.version >= 3 ? BDRV_REQ_MAY_UNMAP : 0;
|
||||
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP;
|
||||
|
||||
/* Repair image if dirty */
|
||||
if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
|
||||
@@ -1537,10 +1504,10 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->l1_table = NULL;
|
||||
cache_clean_timer_del(bs);
|
||||
if (s->l2_table_cache) {
|
||||
qcow2_cache_destroy(s->l2_table_cache);
|
||||
qcow2_cache_destroy(bs, s->l2_table_cache);
|
||||
}
|
||||
if (s->refcount_block_cache) {
|
||||
qcow2_cache_destroy(s->refcount_block_cache);
|
||||
qcow2_cache_destroy(bs, s->refcount_block_cache);
|
||||
}
|
||||
qcrypto_block_free(s->crypto);
|
||||
qapi_free_QCryptoBlockOpenOptions(s->crypto_opts);
|
||||
@@ -1705,12 +1672,34 @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
|
||||
return status;
|
||||
}
|
||||
|
||||
/* handle reading after the end of the backing file */
|
||||
int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
uint64_t bs_size = bs->total_sectors * BDRV_SECTOR_SIZE;
|
||||
int n1;
|
||||
|
||||
if ((offset + bytes) <= bs_size) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
if (offset >= bs_size) {
|
||||
n1 = 0;
|
||||
} else {
|
||||
n1 = bs_size - offset;
|
||||
}
|
||||
|
||||
qemu_iovec_memset(qiov, n1, 0, bytes - n1);
|
||||
|
||||
return n1;
|
||||
}
|
||||
|
||||
static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov,
|
||||
int flags)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int offset_in_cluster;
|
||||
int offset_in_cluster, n1;
|
||||
int ret;
|
||||
unsigned int cur_bytes; /* number of bytes in current iteration */
|
||||
uint64_t cluster_offset = 0;
|
||||
@@ -1745,13 +1734,26 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
case QCOW2_CLUSTER_UNALLOCATED:
|
||||
|
||||
if (bs->backing) {
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
ret = bdrv_co_preadv(bs->backing, offset, cur_bytes,
|
||||
&hd_qiov, 0);
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
/* read from the base image */
|
||||
n1 = qcow2_backing_read1(bs->backing->bs, &hd_qiov,
|
||||
offset, cur_bytes);
|
||||
if (n1 > 0) {
|
||||
QEMUIOVector local_qiov;
|
||||
|
||||
qemu_iovec_init(&local_qiov, hd_qiov.niov);
|
||||
qemu_iovec_concat(&local_qiov, &hd_qiov, 0, n1);
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
ret = bdrv_co_preadv(bs->backing, offset, n1,
|
||||
&local_qiov, 0);
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
|
||||
qemu_iovec_destroy(&local_qiov);
|
||||
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Note: in this case, no need to wait */
|
||||
@@ -2088,8 +2090,8 @@ static void qcow2_close(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
cache_clean_timer_del(bs);
|
||||
qcow2_cache_destroy(s->l2_table_cache);
|
||||
qcow2_cache_destroy(s->refcount_block_cache);
|
||||
qcow2_cache_destroy(bs, s->l2_table_cache);
|
||||
qcow2_cache_destroy(bs, s->refcount_block_cache);
|
||||
|
||||
qcrypto_block_free(s->crypto);
|
||||
s->crypto = NULL;
|
||||
@@ -3282,9 +3284,9 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
|
||||
host_offset = allocation_start;
|
||||
guest_offset = old_length;
|
||||
while (nb_new_data_clusters) {
|
||||
int64_t nb_clusters = MIN(
|
||||
nb_new_data_clusters,
|
||||
s->l2_slice_size - offset_to_l2_slice_index(s, guest_offset));
|
||||
int64_t guest_cluster = guest_offset >> s->cluster_bits;
|
||||
int64_t nb_clusters = MIN(nb_new_data_clusters,
|
||||
s->l2_size - guest_cluster % s->l2_size);
|
||||
QCowL2Meta allocation = {
|
||||
.offset = guest_offset,
|
||||
.alloc_offset = host_offset,
|
||||
@@ -3794,6 +3796,7 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
bdi->unallocated_blocks_are_zero = true;
|
||||
bdi->can_write_zeroes_with_unmap = (s->qcow_version >= 3);
|
||||
bdi->cluster_size = s->cluster_size;
|
||||
bdi->vm_state_offset = qcow2_vm_state_offset(s);
|
||||
return 0;
|
||||
|
@@ -68,7 +68,7 @@
|
||||
#define MAX_CLUSTER_BITS 21
|
||||
|
||||
/* Must be at least 2 to cover COW */
|
||||
#define MIN_L2_CACHE_SIZE 2 /* cache entries */
|
||||
#define MIN_L2_CACHE_SIZE 2 /* clusters */
|
||||
|
||||
/* Must be at least 4 to cover all cases of refcount table growth */
|
||||
#define MIN_REFCOUNT_CACHE_SIZE 4 /* clusters */
|
||||
@@ -100,7 +100,6 @@
|
||||
#define QCOW2_OPT_OVERLAP_INACTIVE_L2 "overlap-check.inactive-l2"
|
||||
#define QCOW2_OPT_CACHE_SIZE "cache-size"
|
||||
#define QCOW2_OPT_L2_CACHE_SIZE "l2-cache-size"
|
||||
#define QCOW2_OPT_L2_CACHE_ENTRY_SIZE "l2-cache-entry-size"
|
||||
#define QCOW2_OPT_REFCOUNT_CACHE_SIZE "refcount-cache-size"
|
||||
#define QCOW2_OPT_CACHE_CLEAN_INTERVAL "cache-clean-interval"
|
||||
|
||||
@@ -252,7 +251,6 @@ typedef struct BDRVQcow2State {
|
||||
int cluster_bits;
|
||||
int cluster_size;
|
||||
int cluster_sectors;
|
||||
int l2_slice_size;
|
||||
int l2_bits;
|
||||
int l2_size;
|
||||
int l1_size;
|
||||
@@ -465,21 +463,11 @@ static inline int64_t size_to_l1(BDRVQcow2State *s, int64_t size)
|
||||
return (size + (1ULL << shift) - 1) >> shift;
|
||||
}
|
||||
|
||||
static inline int offset_to_l1_index(BDRVQcow2State *s, uint64_t offset)
|
||||
{
|
||||
return offset >> (s->l2_bits + s->cluster_bits);
|
||||
}
|
||||
|
||||
static inline int offset_to_l2_index(BDRVQcow2State *s, int64_t offset)
|
||||
{
|
||||
return (offset >> s->cluster_bits) & (s->l2_size - 1);
|
||||
}
|
||||
|
||||
static inline int offset_to_l2_slice_index(BDRVQcow2State *s, int64_t offset)
|
||||
{
|
||||
return (offset >> s->cluster_bits) & (s->l2_slice_size - 1);
|
||||
}
|
||||
|
||||
static inline int64_t align_offset(int64_t offset, int n)
|
||||
{
|
||||
offset = (offset + n - 1) & ~(n - 1);
|
||||
@@ -540,6 +528,9 @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset)
|
||||
}
|
||||
|
||||
/* qcow2.c functions */
|
||||
int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||
int64_t sector_num, int nb_sectors);
|
||||
|
||||
int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
|
||||
int refcount_order, bool generous_increase,
|
||||
uint64_t *refblock_count);
|
||||
@@ -648,33 +639,34 @@ void qcow2_free_snapshots(BlockDriverState *bs);
|
||||
int qcow2_read_snapshots(BlockDriverState *bs);
|
||||
|
||||
/* qcow2-cache.c functions */
|
||||
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
|
||||
unsigned table_size);
|
||||
int qcow2_cache_destroy(Qcow2Cache *c);
|
||||
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables);
|
||||
int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
|
||||
|
||||
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
|
||||
void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c,
|
||||
void *table);
|
||||
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
|
||||
int qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c);
|
||||
int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
|
||||
Qcow2Cache *dependency);
|
||||
void qcow2_cache_depends_on_flush(Qcow2Cache *c);
|
||||
|
||||
void qcow2_cache_clean_unused(Qcow2Cache *c);
|
||||
void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c);
|
||||
int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c);
|
||||
|
||||
int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
|
||||
void **table);
|
||||
int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
|
||||
void **table);
|
||||
void qcow2_cache_put(Qcow2Cache *c, void **table);
|
||||
void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset);
|
||||
void qcow2_cache_discard(Qcow2Cache *c, void *table);
|
||||
void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
|
||||
void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
|
||||
uint64_t offset);
|
||||
void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table);
|
||||
|
||||
/* qcow2-bitmap.c functions */
|
||||
int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
void **refcount_table,
|
||||
int64_t *refcount_table_size);
|
||||
bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp);
|
||||
bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
|
||||
int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
|
||||
void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
|
||||
int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
|
||||
|
@@ -16,9 +16,9 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "qemu/option.h"
|
||||
#include "trace.h"
|
||||
#include "qed.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
|
||||
static int bdrv_qed_probe(const uint8_t *buf, int buf_size,
|
||||
@@ -1438,6 +1438,7 @@ static int bdrv_qed_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
bdi->cluster_size = s->header.cluster_size;
|
||||
bdi->is_dirty = s->header.features & QED_F_NEED_CHECK;
|
||||
bdi->unallocated_blocks_are_zero = true;
|
||||
bdi->can_write_zeroes_with_unmap = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -15,11 +15,11 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/option.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi-event.h"
|
||||
|
@@ -16,14 +16,11 @@
|
||||
#include <rbd/librbd.h>
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/option.h"
|
||||
#include "block/block_int.h"
|
||||
#include "crypto/secret.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
|
||||
/*
|
||||
* When specifying the image filename use:
|
||||
|
@@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu-common.h"
|
||||
#include "block/nbd.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "block/block_int.h"
|
||||
@@ -394,9 +394,6 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
|
||||
new_secondary_flags = s->orig_secondary_flags;
|
||||
}
|
||||
|
||||
bdrv_subtree_drained_begin(s->hidden_disk->bs);
|
||||
bdrv_subtree_drained_begin(s->secondary_disk->bs);
|
||||
|
||||
if (orig_hidden_flags != new_hidden_flags) {
|
||||
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL,
|
||||
new_hidden_flags);
|
||||
@@ -412,9 +409,6 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
|
||||
reopen_queue, &local_err);
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
bdrv_subtree_drained_end(s->hidden_disk->bs);
|
||||
bdrv_subtree_drained_end(s->secondary_disk->bs);
|
||||
}
|
||||
|
||||
static void backup_job_cleanup(BlockDriverState *bs)
|
||||
|
226
block/sheepdog.c
226
block/sheepdog.c
@@ -19,7 +19,6 @@
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qemu/uri.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
@@ -401,7 +400,7 @@ typedef struct BDRVSheepdogReopenState {
|
||||
int cache_flags;
|
||||
} BDRVSheepdogReopenState;
|
||||
|
||||
static const char *sd_strerror(int err)
|
||||
static const char * sd_strerror(int err)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -777,7 +776,8 @@ static coroutine_fn void reconnect_to_sdog(void *opaque)
|
||||
if (s->fd < 0) {
|
||||
DPRINTF("Wait for connection to be established\n");
|
||||
error_report_err(local_err);
|
||||
qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000000ULL);
|
||||
co_aio_sleep_ns(bdrv_get_aio_context(s->bs), QEMU_CLOCK_REALTIME,
|
||||
1000000000ULL);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1632,7 +1632,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (!tag) {
|
||||
tag = "";
|
||||
}
|
||||
if (strlen(tag) >= SD_MAX_VDI_TAG_LEN) {
|
||||
if (tag && strlen(tag) >= SD_MAX_VDI_TAG_LEN) {
|
||||
error_setg(errp, "value of parameter 'tag' is too long");
|
||||
ret = -EINVAL;
|
||||
goto err_no_fd;
|
||||
@@ -1826,34 +1826,40 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_prealloc(BlockDriverState *bs, int64_t old_size, int64_t new_size,
|
||||
Error **errp)
|
||||
static int sd_prealloc(const char *filename, Error **errp)
|
||||
{
|
||||
BlockBackend *blk = NULL;
|
||||
BDRVSheepdogState *base = bs->opaque;
|
||||
BDRVSheepdogState *base = NULL;
|
||||
unsigned long buf_size;
|
||||
uint32_t idx, max_idx;
|
||||
uint32_t object_size;
|
||||
int64_t vdi_size;
|
||||
void *buf = NULL;
|
||||
int ret;
|
||||
|
||||
blk = blk_new(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE,
|
||||
BLK_PERM_ALL);
|
||||
|
||||
ret = blk_insert_bs(blk, bs, errp);
|
||||
if (ret < 0) {
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
|
||||
if (blk == NULL) {
|
||||
ret = -EIO;
|
||||
goto out_with_err_set;
|
||||
}
|
||||
|
||||
blk_set_allow_write_beyond_eof(blk, true);
|
||||
|
||||
vdi_size = blk_getlength(blk);
|
||||
if (vdi_size < 0) {
|
||||
ret = vdi_size;
|
||||
goto out;
|
||||
}
|
||||
|
||||
base = blk_bs(blk)->opaque;
|
||||
object_size = (UINT32_C(1) << base->inode.block_size_shift);
|
||||
buf_size = MIN(object_size, SD_DATA_OBJ_SIZE);
|
||||
buf = g_malloc0(buf_size);
|
||||
|
||||
max_idx = DIV_ROUND_UP(new_size, buf_size);
|
||||
max_idx = DIV_ROUND_UP(vdi_size, buf_size);
|
||||
|
||||
for (idx = old_size / buf_size; idx < max_idx; idx++) {
|
||||
for (idx = 0; idx < max_idx; idx++) {
|
||||
/*
|
||||
* The created image can be a cloned image, so we need to read
|
||||
* a data from the source image.
|
||||
@@ -2102,20 +2108,7 @@ static int sd_create(const char *filename, QemuOpts *opts,
|
||||
}
|
||||
|
||||
if (prealloc) {
|
||||
BlockDriverState *bs;
|
||||
QDict *opts;
|
||||
|
||||
opts = qdict_new();
|
||||
qdict_put_str(opts, "driver", "sheepdog");
|
||||
bs = bdrv_open(filename, NULL, opts, BDRV_O_PROTOCOL | BDRV_O_RDWR,
|
||||
errp);
|
||||
if (!bs) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = sd_prealloc(bs, 0, s->inode.vdi_size, errp);
|
||||
|
||||
bdrv_unref(bs);
|
||||
ret = sd_prealloc(filename, errp);
|
||||
}
|
||||
out:
|
||||
g_free(backing_file);
|
||||
@@ -2180,16 +2173,15 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset,
|
||||
int ret, fd;
|
||||
unsigned int datalen;
|
||||
uint64_t max_vdi_size;
|
||||
int64_t old_size = s->inode.vdi_size;
|
||||
|
||||
if (prealloc != PREALLOC_MODE_OFF && prealloc != PREALLOC_MODE_FULL) {
|
||||
if (prealloc != PREALLOC_MODE_OFF) {
|
||||
error_setg(errp, "Unsupported preallocation mode '%s'",
|
||||
PreallocMode_str(prealloc));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
max_vdi_size = (UINT64_C(1) << s->inode.block_size_shift) * MAX_DATA_OBJS;
|
||||
if (offset < old_size) {
|
||||
if (offset < s->inode.vdi_size) {
|
||||
error_setg(errp, "shrinking is not supported");
|
||||
return -EINVAL;
|
||||
} else if (offset > max_vdi_size) {
|
||||
@@ -2212,17 +2204,9 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset,
|
||||
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "failed to update an inode");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (prealloc == PREALLOC_MODE_FULL) {
|
||||
ret = sd_prealloc(bs, old_size, offset, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3094,111 +3078,111 @@ static QemuOptsList sd_create_opts = {
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_sheepdog = {
|
||||
.format_name = "sheepdog",
|
||||
.protocol_name = "sheepdog",
|
||||
.instance_size = sizeof(BDRVSheepdogState),
|
||||
.bdrv_parse_filename = sd_parse_filename,
|
||||
.bdrv_file_open = sd_open,
|
||||
.bdrv_reopen_prepare = sd_reopen_prepare,
|
||||
.bdrv_reopen_commit = sd_reopen_commit,
|
||||
.bdrv_reopen_abort = sd_reopen_abort,
|
||||
.bdrv_close = sd_close,
|
||||
.bdrv_create = sd_create,
|
||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||
.bdrv_getlength = sd_getlength,
|
||||
.format_name = "sheepdog",
|
||||
.protocol_name = "sheepdog",
|
||||
.instance_size = sizeof(BDRVSheepdogState),
|
||||
.bdrv_parse_filename = sd_parse_filename,
|
||||
.bdrv_file_open = sd_open,
|
||||
.bdrv_reopen_prepare = sd_reopen_prepare,
|
||||
.bdrv_reopen_commit = sd_reopen_commit,
|
||||
.bdrv_reopen_abort = sd_reopen_abort,
|
||||
.bdrv_close = sd_close,
|
||||
.bdrv_create = sd_create,
|
||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||
.bdrv_getlength = sd_getlength,
|
||||
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
|
||||
.bdrv_truncate = sd_truncate,
|
||||
.bdrv_truncate = sd_truncate,
|
||||
|
||||
.bdrv_co_readv = sd_co_readv,
|
||||
.bdrv_co_writev = sd_co_writev,
|
||||
.bdrv_co_flush_to_disk = sd_co_flush_to_disk,
|
||||
.bdrv_co_pdiscard = sd_co_pdiscard,
|
||||
.bdrv_co_get_block_status = sd_co_get_block_status,
|
||||
.bdrv_co_readv = sd_co_readv,
|
||||
.bdrv_co_writev = sd_co_writev,
|
||||
.bdrv_co_flush_to_disk = sd_co_flush_to_disk,
|
||||
.bdrv_co_pdiscard = sd_co_pdiscard,
|
||||
.bdrv_co_get_block_status = sd_co_get_block_status,
|
||||
|
||||
.bdrv_snapshot_create = sd_snapshot_create,
|
||||
.bdrv_snapshot_goto = sd_snapshot_goto,
|
||||
.bdrv_snapshot_delete = sd_snapshot_delete,
|
||||
.bdrv_snapshot_list = sd_snapshot_list,
|
||||
.bdrv_snapshot_create = sd_snapshot_create,
|
||||
.bdrv_snapshot_goto = sd_snapshot_goto,
|
||||
.bdrv_snapshot_delete = sd_snapshot_delete,
|
||||
.bdrv_snapshot_list = sd_snapshot_list,
|
||||
|
||||
.bdrv_save_vmstate = sd_save_vmstate,
|
||||
.bdrv_load_vmstate = sd_load_vmstate,
|
||||
.bdrv_save_vmstate = sd_save_vmstate,
|
||||
.bdrv_load_vmstate = sd_load_vmstate,
|
||||
|
||||
.bdrv_detach_aio_context = sd_detach_aio_context,
|
||||
.bdrv_attach_aio_context = sd_attach_aio_context,
|
||||
.bdrv_detach_aio_context = sd_detach_aio_context,
|
||||
.bdrv_attach_aio_context = sd_attach_aio_context,
|
||||
|
||||
.create_opts = &sd_create_opts,
|
||||
.create_opts = &sd_create_opts,
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_sheepdog_tcp = {
|
||||
.format_name = "sheepdog",
|
||||
.protocol_name = "sheepdog+tcp",
|
||||
.instance_size = sizeof(BDRVSheepdogState),
|
||||
.bdrv_parse_filename = sd_parse_filename,
|
||||
.bdrv_file_open = sd_open,
|
||||
.bdrv_reopen_prepare = sd_reopen_prepare,
|
||||
.bdrv_reopen_commit = sd_reopen_commit,
|
||||
.bdrv_reopen_abort = sd_reopen_abort,
|
||||
.bdrv_close = sd_close,
|
||||
.bdrv_create = sd_create,
|
||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||
.bdrv_getlength = sd_getlength,
|
||||
.format_name = "sheepdog",
|
||||
.protocol_name = "sheepdog+tcp",
|
||||
.instance_size = sizeof(BDRVSheepdogState),
|
||||
.bdrv_parse_filename = sd_parse_filename,
|
||||
.bdrv_file_open = sd_open,
|
||||
.bdrv_reopen_prepare = sd_reopen_prepare,
|
||||
.bdrv_reopen_commit = sd_reopen_commit,
|
||||
.bdrv_reopen_abort = sd_reopen_abort,
|
||||
.bdrv_close = sd_close,
|
||||
.bdrv_create = sd_create,
|
||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||
.bdrv_getlength = sd_getlength,
|
||||
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
|
||||
.bdrv_truncate = sd_truncate,
|
||||
.bdrv_truncate = sd_truncate,
|
||||
|
||||
.bdrv_co_readv = sd_co_readv,
|
||||
.bdrv_co_writev = sd_co_writev,
|
||||
.bdrv_co_flush_to_disk = sd_co_flush_to_disk,
|
||||
.bdrv_co_pdiscard = sd_co_pdiscard,
|
||||
.bdrv_co_get_block_status = sd_co_get_block_status,
|
||||
.bdrv_co_readv = sd_co_readv,
|
||||
.bdrv_co_writev = sd_co_writev,
|
||||
.bdrv_co_flush_to_disk = sd_co_flush_to_disk,
|
||||
.bdrv_co_pdiscard = sd_co_pdiscard,
|
||||
.bdrv_co_get_block_status = sd_co_get_block_status,
|
||||
|
||||
.bdrv_snapshot_create = sd_snapshot_create,
|
||||
.bdrv_snapshot_goto = sd_snapshot_goto,
|
||||
.bdrv_snapshot_delete = sd_snapshot_delete,
|
||||
.bdrv_snapshot_list = sd_snapshot_list,
|
||||
.bdrv_snapshot_create = sd_snapshot_create,
|
||||
.bdrv_snapshot_goto = sd_snapshot_goto,
|
||||
.bdrv_snapshot_delete = sd_snapshot_delete,
|
||||
.bdrv_snapshot_list = sd_snapshot_list,
|
||||
|
||||
.bdrv_save_vmstate = sd_save_vmstate,
|
||||
.bdrv_load_vmstate = sd_load_vmstate,
|
||||
.bdrv_save_vmstate = sd_save_vmstate,
|
||||
.bdrv_load_vmstate = sd_load_vmstate,
|
||||
|
||||
.bdrv_detach_aio_context = sd_detach_aio_context,
|
||||
.bdrv_attach_aio_context = sd_attach_aio_context,
|
||||
.bdrv_detach_aio_context = sd_detach_aio_context,
|
||||
.bdrv_attach_aio_context = sd_attach_aio_context,
|
||||
|
||||
.create_opts = &sd_create_opts,
|
||||
.create_opts = &sd_create_opts,
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_sheepdog_unix = {
|
||||
.format_name = "sheepdog",
|
||||
.protocol_name = "sheepdog+unix",
|
||||
.instance_size = sizeof(BDRVSheepdogState),
|
||||
.bdrv_parse_filename = sd_parse_filename,
|
||||
.bdrv_file_open = sd_open,
|
||||
.bdrv_reopen_prepare = sd_reopen_prepare,
|
||||
.bdrv_reopen_commit = sd_reopen_commit,
|
||||
.bdrv_reopen_abort = sd_reopen_abort,
|
||||
.bdrv_close = sd_close,
|
||||
.bdrv_create = sd_create,
|
||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||
.bdrv_getlength = sd_getlength,
|
||||
.format_name = "sheepdog",
|
||||
.protocol_name = "sheepdog+unix",
|
||||
.instance_size = sizeof(BDRVSheepdogState),
|
||||
.bdrv_parse_filename = sd_parse_filename,
|
||||
.bdrv_file_open = sd_open,
|
||||
.bdrv_reopen_prepare = sd_reopen_prepare,
|
||||
.bdrv_reopen_commit = sd_reopen_commit,
|
||||
.bdrv_reopen_abort = sd_reopen_abort,
|
||||
.bdrv_close = sd_close,
|
||||
.bdrv_create = sd_create,
|
||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||
.bdrv_getlength = sd_getlength,
|
||||
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
|
||||
.bdrv_truncate = sd_truncate,
|
||||
.bdrv_truncate = sd_truncate,
|
||||
|
||||
.bdrv_co_readv = sd_co_readv,
|
||||
.bdrv_co_writev = sd_co_writev,
|
||||
.bdrv_co_flush_to_disk = sd_co_flush_to_disk,
|
||||
.bdrv_co_pdiscard = sd_co_pdiscard,
|
||||
.bdrv_co_get_block_status = sd_co_get_block_status,
|
||||
.bdrv_co_readv = sd_co_readv,
|
||||
.bdrv_co_writev = sd_co_writev,
|
||||
.bdrv_co_flush_to_disk = sd_co_flush_to_disk,
|
||||
.bdrv_co_pdiscard = sd_co_pdiscard,
|
||||
.bdrv_co_get_block_status = sd_co_get_block_status,
|
||||
|
||||
.bdrv_snapshot_create = sd_snapshot_create,
|
||||
.bdrv_snapshot_goto = sd_snapshot_goto,
|
||||
.bdrv_snapshot_delete = sd_snapshot_delete,
|
||||
.bdrv_snapshot_list = sd_snapshot_list,
|
||||
.bdrv_snapshot_create = sd_snapshot_create,
|
||||
.bdrv_snapshot_goto = sd_snapshot_goto,
|
||||
.bdrv_snapshot_delete = sd_snapshot_delete,
|
||||
.bdrv_snapshot_list = sd_snapshot_list,
|
||||
|
||||
.bdrv_save_vmstate = sd_save_vmstate,
|
||||
.bdrv_load_vmstate = sd_load_vmstate,
|
||||
.bdrv_save_vmstate = sd_save_vmstate,
|
||||
.bdrv_load_vmstate = sd_load_vmstate,
|
||||
|
||||
.bdrv_detach_aio_context = sd_detach_aio_context,
|
||||
.bdrv_attach_aio_context = sd_attach_aio_context,
|
||||
.bdrv_detach_aio_context = sd_detach_aio_context,
|
||||
.bdrv_attach_aio_context = sd_attach_aio_context,
|
||||
|
||||
.create_opts = &sd_create_opts,
|
||||
.create_opts = &sd_create_opts,
|
||||
};
|
||||
|
||||
static void bdrv_sheepdog_init(void)
|
||||
|
@@ -26,10 +26,8 @@
|
||||
#include "block/snapshot.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qemu/option.h"
|
||||
|
||||
QemuOptsList internal_snapshot_opts = {
|
||||
.name = "snapshot",
|
||||
|
@@ -30,12 +30,10 @@
|
||||
#include "block/block_int.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qemu/uri.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qapi/qobject-output-visitor.h"
|
||||
@@ -558,7 +556,6 @@ static QemuOptsList ssh_runtime_opts = {
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Defines how and what to check the host key against",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "block/throttle-groups.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/throttle-options.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
|
@@ -124,24 +124,3 @@ vxhs_open_iio_open(const char *host) "Failed to connect to storage agent on host
|
||||
vxhs_parse_uri_hostinfo(char *host, int port) "Host: IP %s, Port %d"
|
||||
vxhs_close(char *vdisk_guid) "Closing vdisk %s"
|
||||
vxhs_get_creds(const char *cacert, const char *client_key, const char *client_cert) "cacert %s, client_key %s, client_cert %s"
|
||||
|
||||
# block/nvme.c
|
||||
nvme_kick(void *s, int queue) "s %p queue %d"
|
||||
nvme_dma_flush_queue_wait(void *s) "s %p"
|
||||
nvme_error(int cmd_specific, int sq_head, int sqid, int cid, int status) "cmd_specific %d sq_head %d sqid %d cid %d status 0x%x"
|
||||
nvme_process_completion(void *s, int index, int inflight) "s %p queue %d inflight %d"
|
||||
nvme_process_completion_queue_busy(void *s, int index) "s %p queue %d"
|
||||
nvme_complete_command(void *s, int index, int cid) "s %p queue %d cid %d"
|
||||
nvme_submit_command(void *s, int index, int cid) "s %p queue %d cid %d"
|
||||
nvme_submit_command_raw(int c0, int c1, int c2, int c3, int c4, int c5, int c6, int c7) "%02x %02x %02x %02x %02x %02x %02x %02x"
|
||||
nvme_handle_event(void *s) "s %p"
|
||||
nvme_poll_cb(void *s) "s %p"
|
||||
nvme_prw_aligned(void *s, int is_write, uint64_t offset, uint64_t bytes, int flags, int niov) "s %p is_write %d offset %"PRId64" bytes %"PRId64" flags %d niov %d"
|
||||
nvme_qiov_unaligned(const void *qiov, int n, void *base, size_t size, int align) "qiov %p n %d base %p size 0x%zx align 0x%x"
|
||||
nvme_prw_buffered(void *s, uint64_t offset, uint64_t bytes, int niov, int is_write) "s %p offset %"PRId64" bytes %"PRId64" niov %d is_write %d"
|
||||
nvme_rw_done(void *s, int is_write, uint64_t offset, uint64_t bytes, int ret) "s %p is_write %d offset %"PRId64" bytes %"PRId64" ret %d"
|
||||
nvme_dma_map_flush(void *s) "s %p"
|
||||
nvme_free_req_queue_wait(void *q) "q %p"
|
||||
nvme_cmd_map_qiov(void *s, void *cmd, void *req, void *qiov, int entries) "s %p cmd %p req %p qiov %p entries %d"
|
||||
nvme_cmd_map_qiov_pages(void *s, int i, uint64_t page) "s %p page[%d] 0x%"PRIx64
|
||||
nvme_cmd_map_qiov_iov(void *s, int i, void *page, int pages) "s %p iov[%d] %p pages %d"
|
||||
|
@@ -54,7 +54,6 @@
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "migration/blocker.h"
|
||||
#include "qemu/coroutine.h"
|
||||
|
@@ -17,10 +17,10 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/crc32c.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "block/vhdx.h"
|
||||
|
19
block/vmdk.c
19
block/vmdk.c
@@ -30,7 +30,6 @@
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "migration/blocker.h"
|
||||
#include "qemu/cutils.h"
|
||||
@@ -1076,8 +1075,6 @@ static int get_whole_cluster(BlockDriverState *bs,
|
||||
/* Read backing data before skip range */
|
||||
if (skip_start_bytes > 0) {
|
||||
if (bs->backing) {
|
||||
/* qcow2 emits this on bs->file instead of bs->backing */
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
|
||||
ret = bdrv_pread(bs->backing, offset, whole_grain,
|
||||
skip_start_bytes);
|
||||
if (ret < 0) {
|
||||
@@ -1085,7 +1082,6 @@ static int get_whole_cluster(BlockDriverState *bs,
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
|
||||
ret = bdrv_pwrite(extent->file, cluster_offset, whole_grain,
|
||||
skip_start_bytes);
|
||||
if (ret < 0) {
|
||||
@@ -1096,8 +1092,6 @@ static int get_whole_cluster(BlockDriverState *bs,
|
||||
/* Read backing data after skip range */
|
||||
if (skip_end_bytes < cluster_bytes) {
|
||||
if (bs->backing) {
|
||||
/* qcow2 emits this on bs->file instead of bs->backing */
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
|
||||
ret = bdrv_pread(bs->backing, offset + skip_end_bytes,
|
||||
whole_grain + skip_end_bytes,
|
||||
cluster_bytes - skip_end_bytes);
|
||||
@@ -1106,7 +1100,6 @@ static int get_whole_cluster(BlockDriverState *bs,
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
|
||||
ret = bdrv_pwrite(extent->file, cluster_offset + skip_end_bytes,
|
||||
whole_grain + skip_end_bytes,
|
||||
cluster_bytes - skip_end_bytes);
|
||||
@@ -1127,7 +1120,6 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data,
|
||||
{
|
||||
offset = cpu_to_le32(offset);
|
||||
/* update L2 table */
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_L2_UPDATE);
|
||||
if (bdrv_pwrite_sync(extent->file,
|
||||
((int64_t)m_data->l2_offset * 512)
|
||||
+ (m_data->l2_index * sizeof(offset)),
|
||||
@@ -1226,7 +1218,6 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||
}
|
||||
}
|
||||
l2_table = extent->l2_cache + (min_index * extent->l2_size);
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD);
|
||||
if (bdrv_pread(extent->file,
|
||||
(int64_t)l2_offset * 512,
|
||||
l2_table,
|
||||
@@ -1402,16 +1393,12 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||
.iov_len = n_bytes,
|
||||
};
|
||||
qemu_iovec_init_external(&local_qiov, &iov, 1);
|
||||
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_WRITE_COMPRESSED);
|
||||
} else {
|
||||
qemu_iovec_init(&local_qiov, qiov->niov);
|
||||
qemu_iovec_concat(&local_qiov, qiov, qiov_offset, n_bytes);
|
||||
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_WRITE_AIO);
|
||||
}
|
||||
|
||||
write_offset = cluster_offset + offset_in_cluster;
|
||||
write_offset = cluster_offset + offset_in_cluster,
|
||||
ret = bdrv_co_pwritev(extent->file, write_offset, n_bytes,
|
||||
&local_qiov, 0);
|
||||
|
||||
@@ -1450,7 +1437,6 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||
|
||||
|
||||
if (!extent->compressed) {
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_READ_AIO);
|
||||
ret = bdrv_co_preadv(extent->file,
|
||||
cluster_offset + offset_in_cluster, bytes,
|
||||
qiov, 0);
|
||||
@@ -1464,7 +1450,6 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||
buf_bytes = cluster_bytes * 2;
|
||||
cluster_buf = g_malloc(buf_bytes);
|
||||
uncomp_buf = g_malloc(cluster_bytes);
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_READ_COMPRESSED);
|
||||
ret = bdrv_pread(extent->file,
|
||||
cluster_offset,
|
||||
cluster_buf, buf_bytes);
|
||||
@@ -1542,8 +1527,6 @@ vmdk_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
qemu_iovec_reset(&local_qiov);
|
||||
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
||||
|
||||
/* qcow2 emits this on bs->file instead of bs->backing */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
|
||||
ret = bdrv_co_preadv(bs->backing, offset, n_bytes,
|
||||
&local_qiov, 0);
|
||||
if (ret < 0) {
|
||||
|
@@ -22,13 +22,12 @@
|
||||
* 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 "qemu-common.h"
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "migration/blocker.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "qemu/uuid.h"
|
||||
|
@@ -22,16 +22,14 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <dirent.h>
|
||||
#include "qapi/error.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "migration/blocker.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
@@ -16,9 +16,9 @@
|
||||
#include "block/write-threshold.h"
|
||||
#include "qemu/notify.h"
|
||||
#include "qapi-event.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qmp-commands.h"
|
||||
|
||||
|
||||
uint64_t bdrv_write_threshold_get(const BlockDriverState *bs)
|
||||
{
|
||||
return bs->write_threshold_offset;
|
||||
|
@@ -13,15 +13,15 @@
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "block/nbd.h"
|
||||
#include "io/channel-socket.h"
|
||||
#include "io/net-listener.h"
|
||||
|
||||
typedef struct NBDServerData {
|
||||
QIONetListener *listener;
|
||||
QIOChannelSocket *listen_ioc;
|
||||
int watch;
|
||||
QCryptoTLSCreds *tlscreds;
|
||||
} NBDServerData;
|
||||
|
||||
@@ -32,13 +32,27 @@ static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
|
||||
nbd_client_put(client);
|
||||
}
|
||||
|
||||
static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
|
||||
gpointer opaque)
|
||||
static gboolean nbd_accept(QIOChannel *ioc, GIOCondition condition,
|
||||
gpointer opaque)
|
||||
{
|
||||
QIOChannelSocket *cioc;
|
||||
|
||||
if (!nbd_server) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
|
||||
NULL);
|
||||
if (!cioc) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
|
||||
nbd_client_new(NULL, cioc,
|
||||
nbd_server->tlscreds, NULL,
|
||||
nbd_blockdev_client_closed);
|
||||
object_unref(OBJECT(cioc));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,8 +62,10 @@ static void nbd_server_free(NBDServerData *server)
|
||||
return;
|
||||
}
|
||||
|
||||
qio_net_listener_disconnect(server->listener);
|
||||
object_unref(OBJECT(server->listener));
|
||||
if (server->watch != -1) {
|
||||
g_source_remove(server->watch);
|
||||
}
|
||||
object_unref(OBJECT(server->listen_ioc));
|
||||
if (server->tlscreds) {
|
||||
object_unref(OBJECT(server->tlscreds));
|
||||
}
|
||||
@@ -96,12 +112,12 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds,
|
||||
}
|
||||
|
||||
nbd_server = g_new0(NBDServerData, 1);
|
||||
nbd_server->listener = qio_net_listener_new();
|
||||
|
||||
qio_net_listener_set_name(nbd_server->listener,
|
||||
"nbd-listener");
|
||||
|
||||
if (qio_net_listener_open_sync(nbd_server->listener, addr, errp) < 0) {
|
||||
nbd_server->watch = -1;
|
||||
nbd_server->listen_ioc = qio_channel_socket_new();
|
||||
qio_channel_set_name(QIO_CHANNEL(nbd_server->listen_ioc),
|
||||
"nbd-listener");
|
||||
if (qio_channel_socket_listen_sync(
|
||||
nbd_server->listen_ioc, addr, errp) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -118,10 +134,12 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds,
|
||||
}
|
||||
}
|
||||
|
||||
qio_net_listener_set_client_func(nbd_server->listener,
|
||||
nbd_accept,
|
||||
NULL,
|
||||
NULL);
|
||||
nbd_server->watch = qio_channel_add_watch(
|
||||
QIO_CHANNEL(nbd_server->listen_ioc),
|
||||
G_IO_IN,
|
||||
nbd_accept,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
return;
|
||||
|
||||
@@ -140,8 +158,8 @@ void qmp_nbd_server_start(SocketAddressLegacy *addr,
|
||||
qapi_free_SocketAddress(addr_flat);
|
||||
}
|
||||
|
||||
void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
|
||||
bool has_writable, bool writable, Error **errp)
|
||||
void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = NULL;
|
||||
BlockBackend *on_eject_blk;
|
||||
@@ -152,12 +170,8 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!has_name) {
|
||||
name = device;
|
||||
}
|
||||
|
||||
if (nbd_export_find(name)) {
|
||||
error_setg(errp, "NBD server already has export named '%s'", name);
|
||||
if (nbd_export_find(device)) {
|
||||
error_setg(errp, "NBD server already exporting device '%s'", device);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -181,7 +195,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
|
||||
return;
|
||||
}
|
||||
|
||||
nbd_export_set_name(exp, name);
|
||||
nbd_export_set_name(exp, device);
|
||||
|
||||
/* The list of named exports has a strong reference to this export now and
|
||||
* our only way of accessing it is through nbd_export_find(), so we can drop
|
||||
@@ -189,30 +203,6 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
|
||||
nbd_export_put(exp);
|
||||
}
|
||||
|
||||
void qmp_nbd_server_remove(const char *name,
|
||||
bool has_mode, NbdServerRemoveMode mode,
|
||||
Error **errp)
|
||||
{
|
||||
NBDExport *exp;
|
||||
|
||||
if (!nbd_server) {
|
||||
error_setg(errp, "NBD server not running");
|
||||
return;
|
||||
}
|
||||
|
||||
exp = nbd_export_find(name);
|
||||
if (exp == NULL) {
|
||||
error_setg(errp, "Export '%s' is not found", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!has_mode) {
|
||||
mode = NBD_SERVER_REMOVE_MODE_SAFE;
|
||||
}
|
||||
|
||||
nbd_export_remove(exp, mode, errp);
|
||||
}
|
||||
|
||||
void qmp_nbd_server_stop(Error **errp)
|
||||
{
|
||||
nbd_export_close_all();
|
||||
|
321
blockdev.c
321
blockdev.c
@@ -40,16 +40,11 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qnum.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qapi/qobject-output-visitor.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/iothread.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "block/trace.h"
|
||||
@@ -64,11 +59,6 @@ static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
|
||||
|
||||
static int do_open_tray(const char *blk_name, const char *qdev_id,
|
||||
bool force, Error **errp);
|
||||
static void blockdev_remove_medium(bool has_device, const char *device,
|
||||
bool has_id, const char *id, Error **errp);
|
||||
static void blockdev_insert_medium(bool has_device, const char *device,
|
||||
bool has_id, const char *id,
|
||||
const char *node_name, Error **errp);
|
||||
|
||||
static const char *const if_name[IF_COUNT] = {
|
||||
[IF_NONE] = "none",
|
||||
@@ -743,6 +733,10 @@ QemuOptsList qemu_legacy_drive_opts = {
|
||||
.name = "trans",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "chs translation (auto, lba, none)",
|
||||
},{
|
||||
.name = "boot",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "(deprecated, ignored)",
|
||||
},{
|
||||
.name = "addr",
|
||||
.type = QEMU_OPT_STRING,
|
||||
@@ -878,6 +872,13 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Deprecated option boot=[on|off] */
|
||||
if (qemu_opt_get(legacy_opts, "boot") != NULL) {
|
||||
fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
|
||||
"ignored. Future versions will reject this parameter. Please "
|
||||
"update your scripts.\n");
|
||||
}
|
||||
|
||||
/* Other deprecated options */
|
||||
if (!qtest_enabled()) {
|
||||
for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
|
||||
@@ -1453,6 +1454,7 @@ struct BlkActionState {
|
||||
typedef struct InternalSnapshotState {
|
||||
BlkActionState common;
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
QEMUSnapshotInfo sn;
|
||||
bool created;
|
||||
} InternalSnapshotState;
|
||||
@@ -1483,7 +1485,6 @@ static void internal_snapshot_prepare(BlkActionState *common,
|
||||
qemu_timeval tv;
|
||||
BlockdevSnapshotInternal *internal;
|
||||
InternalSnapshotState *state;
|
||||
AioContext *aio_context;
|
||||
int ret1;
|
||||
|
||||
g_assert(common->action->type ==
|
||||
@@ -1505,33 +1506,32 @@ static void internal_snapshot_prepare(BlkActionState *common,
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
/* AioContext is released in .clean() */
|
||||
state->aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(state->aio_context);
|
||||
|
||||
state->bs = bs;
|
||||
|
||||
/* Paired with .clean() */
|
||||
bdrv_drained_begin(bs);
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, errp)) {
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_is_read_only(bs)) {
|
||||
error_setg(errp, "Device '%s' is read only", device);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bdrv_can_snapshot(bs)) {
|
||||
error_setg(errp, "Block format '%s' used by device '%s' "
|
||||
"does not support internal snapshots",
|
||||
bs->drv->format_name, device);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strlen(name)) {
|
||||
error_setg(errp, "Name is empty");
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
/* check whether a snapshot with name exist */
|
||||
@@ -1539,12 +1539,12 @@ static void internal_snapshot_prepare(BlkActionState *common,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
return;
|
||||
} else if (ret) {
|
||||
error_setg(errp,
|
||||
"Snapshot with name '%s' already exists on device '%s'",
|
||||
name, device);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 3. take the snapshot */
|
||||
@@ -1560,14 +1560,11 @@ static void internal_snapshot_prepare(BlkActionState *common,
|
||||
error_setg_errno(errp, -ret1,
|
||||
"Failed to create snapshot '%s' on device '%s'",
|
||||
name, device);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 4. succeed, mark a snapshot is created */
|
||||
state->created = true;
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static void internal_snapshot_abort(BlkActionState *common)
|
||||
@@ -1576,16 +1573,12 @@ static void internal_snapshot_abort(BlkActionState *common)
|
||||
DO_UPCAST(InternalSnapshotState, common, common);
|
||||
BlockDriverState *bs = state->bs;
|
||||
QEMUSnapshotInfo *sn = &state->sn;
|
||||
AioContext *aio_context;
|
||||
Error *local_error = NULL;
|
||||
|
||||
if (!state->created) {
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(state->bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
if (bdrv_snapshot_delete(bs, sn->id_str, sn->name, &local_error) < 0) {
|
||||
error_reportf_err(local_error,
|
||||
"Failed to delete snapshot with id '%s' and "
|
||||
@@ -1593,26 +1586,19 @@ static void internal_snapshot_abort(BlkActionState *common)
|
||||
sn->id_str, sn->name,
|
||||
bdrv_get_device_name(bs));
|
||||
}
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static void internal_snapshot_clean(BlkActionState *common)
|
||||
{
|
||||
InternalSnapshotState *state = DO_UPCAST(InternalSnapshotState,
|
||||
common, common);
|
||||
AioContext *aio_context;
|
||||
|
||||
if (!state->bs) {
|
||||
return;
|
||||
if (state->aio_context) {
|
||||
if (state->bs) {
|
||||
bdrv_drained_end(state->bs);
|
||||
}
|
||||
aio_context_release(state->aio_context);
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(state->bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
bdrv_drained_end(state->bs);
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
/* external snapshot private data */
|
||||
@@ -1620,6 +1606,7 @@ typedef struct ExternalSnapshotState {
|
||||
BlkActionState common;
|
||||
BlockDriverState *old_bs;
|
||||
BlockDriverState *new_bs;
|
||||
AioContext *aio_context;
|
||||
bool overlay_appended;
|
||||
} ExternalSnapshotState;
|
||||
|
||||
@@ -1639,7 +1626,6 @@ static void external_snapshot_prepare(BlkActionState *common,
|
||||
ExternalSnapshotState *state =
|
||||
DO_UPCAST(ExternalSnapshotState, common, common);
|
||||
TransactionAction *action = common->action;
|
||||
AioContext *aio_context;
|
||||
|
||||
/* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
|
||||
* purpose but a different set of parameters */
|
||||
@@ -1676,32 +1662,31 @@ static void external_snapshot_prepare(BlkActionState *common,
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(state->old_bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
/* Paired with .clean() */
|
||||
/* Acquire AioContext now so any threads operating on old_bs stop */
|
||||
state->aio_context = bdrv_get_aio_context(state->old_bs);
|
||||
aio_context_acquire(state->aio_context);
|
||||
bdrv_drained_begin(state->old_bs);
|
||||
|
||||
if (!bdrv_is_inserted(state->old_bs)) {
|
||||
error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(state->old_bs,
|
||||
BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) {
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bdrv_is_read_only(state->old_bs)) {
|
||||
if (bdrv_flush(state->old_bs)) {
|
||||
error_setg(errp, QERR_IO_ERROR);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bdrv_is_first_non_filter(state->old_bs)) {
|
||||
error_setg(errp, QERR_FEATURE_DISABLED, "snapshot");
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC) {
|
||||
@@ -1713,13 +1698,13 @@ static void external_snapshot_prepare(BlkActionState *common,
|
||||
|
||||
if (node_name && !snapshot_node_name) {
|
||||
error_setg(errp, "New snapshot node name missing");
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (snapshot_node_name &&
|
||||
bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) {
|
||||
error_setg(errp, "New snapshot node name already in use");
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
flags = state->old_bs->open_flags;
|
||||
@@ -1732,7 +1717,7 @@ static void external_snapshot_prepare(BlkActionState *common,
|
||||
int64_t size = bdrv_getlength(state->old_bs);
|
||||
if (size < 0) {
|
||||
error_setg_errno(errp, -size, "bdrv_getlength failed");
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
bdrv_img_create(new_image_file, format,
|
||||
state->old_bs->filename,
|
||||
@@ -1740,7 +1725,7 @@ static void external_snapshot_prepare(BlkActionState *common,
|
||||
NULL, size, flags, false, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1755,30 +1740,30 @@ static void external_snapshot_prepare(BlkActionState *common,
|
||||
errp);
|
||||
/* We will manually add the backing_hd field to the bs later */
|
||||
if (!state->new_bs) {
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_has_blk(state->new_bs)) {
|
||||
error_setg(errp, "The snapshot is already in use");
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(state->new_bs, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
|
||||
errp)) {
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->new_bs->backing != NULL) {
|
||||
error_setg(errp, "The snapshot already has a backing image");
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state->new_bs->drv->supports_backing) {
|
||||
error_setg(errp, "The snapshot does not support backing images");
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_set_aio_context(state->new_bs, aio_context);
|
||||
bdrv_set_aio_context(state->new_bs, state->aio_context);
|
||||
|
||||
/* This removes our old bs and adds the new bs. This is an operation that
|
||||
* can fail, so we need to do it in .prepare; undoing it for abort is
|
||||
@@ -1787,22 +1772,15 @@ static void external_snapshot_prepare(BlkActionState *common,
|
||||
bdrv_append(state->new_bs, state->old_bs, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
state->overlay_appended = true;
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static void external_snapshot_commit(BlkActionState *common)
|
||||
{
|
||||
ExternalSnapshotState *state =
|
||||
DO_UPCAST(ExternalSnapshotState, common, common);
|
||||
AioContext *aio_context;
|
||||
|
||||
aio_context = bdrv_get_aio_context(state->old_bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
/* We don't need (or want) to use the transactional
|
||||
* bdrv_reopen_multiple() across all the entries at once, because we
|
||||
@@ -1811,8 +1789,6 @@ static void external_snapshot_commit(BlkActionState *common)
|
||||
bdrv_reopen(state->old_bs, state->old_bs->open_flags & ~BDRV_O_RDWR,
|
||||
NULL);
|
||||
}
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static void external_snapshot_abort(BlkActionState *common)
|
||||
@@ -1821,18 +1797,11 @@ static void external_snapshot_abort(BlkActionState *common)
|
||||
DO_UPCAST(ExternalSnapshotState, common, common);
|
||||
if (state->new_bs) {
|
||||
if (state->overlay_appended) {
|
||||
AioContext *aio_context;
|
||||
|
||||
aio_context = bdrv_get_aio_context(state->old_bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
bdrv_ref(state->old_bs); /* we can't let bdrv_set_backind_hd()
|
||||
close state->old_bs; we need it */
|
||||
bdrv_set_backing_hd(state->new_bs, NULL, &error_abort);
|
||||
bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
|
||||
bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1841,24 +1810,17 @@ static void external_snapshot_clean(BlkActionState *common)
|
||||
{
|
||||
ExternalSnapshotState *state =
|
||||
DO_UPCAST(ExternalSnapshotState, common, common);
|
||||
AioContext *aio_context;
|
||||
|
||||
if (!state->old_bs) {
|
||||
return;
|
||||
if (state->aio_context) {
|
||||
bdrv_drained_end(state->old_bs);
|
||||
aio_context_release(state->aio_context);
|
||||
bdrv_unref(state->new_bs);
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(state->old_bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
bdrv_drained_end(state->old_bs);
|
||||
bdrv_unref(state->new_bs);
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
typedef struct DriveBackupState {
|
||||
BlkActionState common;
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
BlockJob *job;
|
||||
} DriveBackupState;
|
||||
|
||||
@@ -1870,7 +1832,6 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
|
||||
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
|
||||
BlockDriverState *bs;
|
||||
DriveBackup *backup;
|
||||
AioContext *aio_context;
|
||||
Error *local_err = NULL;
|
||||
|
||||
assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
|
||||
@@ -1881,36 +1842,24 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
/* Paired with .clean() */
|
||||
/* AioContext is released in .clean() */
|
||||
state->aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(state->aio_context);
|
||||
bdrv_drained_begin(bs);
|
||||
|
||||
state->bs = bs;
|
||||
|
||||
state->job = do_drive_backup(backup, common->block_job_txn, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static void drive_backup_commit(BlkActionState *common)
|
||||
{
|
||||
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
|
||||
AioContext *aio_context;
|
||||
|
||||
aio_context = bdrv_get_aio_context(state->bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
assert(state->job);
|
||||
block_job_start(state->job);
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static void drive_backup_abort(BlkActionState *common)
|
||||
@@ -1918,38 +1867,25 @@ static void drive_backup_abort(BlkActionState *common)
|
||||
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
|
||||
|
||||
if (state->job) {
|
||||
AioContext *aio_context;
|
||||
|
||||
aio_context = bdrv_get_aio_context(state->bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
block_job_cancel_sync(state->job);
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
}
|
||||
|
||||
static void drive_backup_clean(BlkActionState *common)
|
||||
{
|
||||
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
|
||||
AioContext *aio_context;
|
||||
|
||||
if (!state->bs) {
|
||||
return;
|
||||
if (state->aio_context) {
|
||||
bdrv_drained_end(state->bs);
|
||||
aio_context_release(state->aio_context);
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(state->bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
bdrv_drained_end(state->bs);
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
typedef struct BlockdevBackupState {
|
||||
BlkActionState common;
|
||||
BlockDriverState *bs;
|
||||
BlockJob *job;
|
||||
AioContext *aio_context;
|
||||
} BlockdevBackupState;
|
||||
|
||||
static BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
|
||||
@@ -1960,7 +1896,6 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
|
||||
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
|
||||
BlockdevBackup *backup;
|
||||
BlockDriverState *bs, *target;
|
||||
AioContext *aio_context;
|
||||
Error *local_err = NULL;
|
||||
|
||||
assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
|
||||
@@ -1976,39 +1911,29 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
if (aio_context != bdrv_get_aio_context(target)) {
|
||||
/* AioContext is released in .clean() */
|
||||
state->aio_context = bdrv_get_aio_context(bs);
|
||||
if (state->aio_context != bdrv_get_aio_context(target)) {
|
||||
state->aio_context = NULL;
|
||||
error_setg(errp, "Backup between two IO threads is not implemented");
|
||||
return;
|
||||
}
|
||||
aio_context_acquire(aio_context);
|
||||
aio_context_acquire(state->aio_context);
|
||||
state->bs = bs;
|
||||
|
||||
/* Paired with .clean() */
|
||||
bdrv_drained_begin(state->bs);
|
||||
|
||||
state->job = do_blockdev_backup(backup, common->block_job_txn, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static void blockdev_backup_commit(BlkActionState *common)
|
||||
{
|
||||
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
|
||||
AioContext *aio_context;
|
||||
|
||||
aio_context = bdrv_get_aio_context(state->bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
assert(state->job);
|
||||
block_job_start(state->job);
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static void blockdev_backup_abort(BlkActionState *common)
|
||||
@@ -2016,38 +1941,25 @@ static void blockdev_backup_abort(BlkActionState *common)
|
||||
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
|
||||
|
||||
if (state->job) {
|
||||
AioContext *aio_context;
|
||||
|
||||
aio_context = bdrv_get_aio_context(state->bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
block_job_cancel_sync(state->job);
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
}
|
||||
|
||||
static void blockdev_backup_clean(BlkActionState *common)
|
||||
{
|
||||
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
|
||||
AioContext *aio_context;
|
||||
|
||||
if (!state->bs) {
|
||||
return;
|
||||
if (state->aio_context) {
|
||||
bdrv_drained_end(state->bs);
|
||||
aio_context_release(state->aio_context);
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(state->bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
bdrv_drained_end(state->bs);
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
typedef struct BlockDirtyBitmapState {
|
||||
BlkActionState common;
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
HBitmap *backup;
|
||||
bool prepared;
|
||||
} BlockDirtyBitmapState;
|
||||
@@ -2126,6 +2038,7 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
|
||||
}
|
||||
|
||||
bdrv_clear_dirty_bitmap(state->bitmap, &state->backup);
|
||||
/* AioContext is released in .clean() */
|
||||
}
|
||||
|
||||
static void block_dirty_bitmap_clear_abort(BlkActionState *common)
|
||||
@@ -2146,6 +2059,16 @@ static void block_dirty_bitmap_clear_commit(BlkActionState *common)
|
||||
hbitmap_free(state->backup);
|
||||
}
|
||||
|
||||
static void block_dirty_bitmap_clear_clean(BlkActionState *common)
|
||||
{
|
||||
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
|
||||
common, common);
|
||||
|
||||
if (state->aio_context) {
|
||||
aio_context_release(state->aio_context);
|
||||
}
|
||||
}
|
||||
|
||||
static void abort_prepare(BlkActionState *common, Error **errp)
|
||||
{
|
||||
error_setg(errp, "Transaction aborted using Abort action");
|
||||
@@ -2206,6 +2129,7 @@ static const BlkActionOps actions[] = {
|
||||
.prepare = block_dirty_bitmap_clear_prepare,
|
||||
.commit = block_dirty_bitmap_clear_commit,
|
||||
.abort = block_dirty_bitmap_clear_abort,
|
||||
.clean = block_dirty_bitmap_clear_clean,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2332,7 +2256,7 @@ void qmp_eject(bool has_device, const char *device,
|
||||
}
|
||||
error_free(local_err);
|
||||
|
||||
blockdev_remove_medium(has_device, device, has_id, id, errp);
|
||||
qmp_x_blockdev_remove_medium(has_device, device, has_id, id, errp);
|
||||
}
|
||||
|
||||
void qmp_block_passwd(bool has_device, const char *device,
|
||||
@@ -2455,8 +2379,8 @@ void qmp_blockdev_close_tray(bool has_device, const char *device,
|
||||
}
|
||||
}
|
||||
|
||||
static void blockdev_remove_medium(bool has_device, const char *device,
|
||||
bool has_id, const char *id, Error **errp)
|
||||
void qmp_x_blockdev_remove_medium(bool has_device, const char *device,
|
||||
bool has_id, const char *id, Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
@@ -2512,11 +2436,6 @@ 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)
|
||||
{
|
||||
@@ -2562,9 +2481,9 @@ static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
|
||||
}
|
||||
}
|
||||
|
||||
static void blockdev_insert_medium(bool has_device, const char *device,
|
||||
bool has_id, const char *id,
|
||||
const char *node_name, Error **errp)
|
||||
void qmp_x_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;
|
||||
@@ -2590,12 +2509,6 @@ static void blockdev_insert_medium(bool has_device, const char *device,
|
||||
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,
|
||||
@@ -2670,7 +2583,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
|
||||
error_free(err);
|
||||
err = NULL;
|
||||
|
||||
blockdev_remove_medium(has_device, device, has_id, id, &err);
|
||||
qmp_x_blockdev_remove_medium(has_device, device, has_id, id, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
goto fail;
|
||||
@@ -2825,9 +2738,14 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
|
||||
if (!has_persistent) {
|
||||
persistent = false;
|
||||
}
|
||||
if (!has_autoload) {
|
||||
autoload = false;
|
||||
}
|
||||
|
||||
if (has_autoload) {
|
||||
warn_report("Autoload option is deprecated and its value is ignored");
|
||||
if (has_autoload && !persistent) {
|
||||
error_setg(errp, "Autoload flag must be used only for persistent "
|
||||
"bitmaps");
|
||||
return;
|
||||
}
|
||||
|
||||
if (persistent &&
|
||||
@@ -2842,6 +2760,7 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
|
||||
}
|
||||
|
||||
bdrv_dirty_bitmap_set_persistance(bitmap, persistent);
|
||||
bdrv_dirty_bitmap_set_autoload(bitmap, autoload);
|
||||
}
|
||||
|
||||
void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
|
||||
@@ -3563,11 +3482,6 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Early check to avoid creating target */
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR_SOURCE, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
@@ -4138,47 +4052,6 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp)
|
||||
return head;
|
||||
}
|
||||
|
||||
void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
|
||||
bool has_force, bool force, Error **errp)
|
||||
{
|
||||
AioContext *old_context;
|
||||
AioContext *new_context;
|
||||
BlockDriverState *bs;
|
||||
|
||||
bs = bdrv_find_node(node_name);
|
||||
if (!bs) {
|
||||
error_setg(errp, "Cannot find node %s", node_name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Protects against accidents. */
|
||||
if (!(has_force && force) && bdrv_has_blk(bs)) {
|
||||
error_setg(errp, "Node %s is associated with a BlockBackend and could "
|
||||
"be in use (use force=true to override this check)",
|
||||
node_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (iothread->type == QTYPE_QSTRING) {
|
||||
IOThread *obj = iothread_by_id(iothread->u.s);
|
||||
if (!obj) {
|
||||
error_setg(errp, "Cannot find iothread %s", iothread->u.s);
|
||||
return;
|
||||
}
|
||||
|
||||
new_context = iothread_get_aio_context(obj);
|
||||
} else {
|
||||
new_context = qemu_get_aio_context();
|
||||
}
|
||||
|
||||
old_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(old_context);
|
||||
|
||||
bdrv_set_aio_context(bs, new_context);
|
||||
|
||||
aio_context_release(old_context);
|
||||
}
|
||||
|
||||
QemuOptsList qemu_common_drive_opts = {
|
||||
.name = "drive",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),
|
||||
|
55
blockjob.c
55
blockjob.c
@@ -29,10 +29,11 @@
|
||||
#include "block/blockjob_int.h"
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qemu/coroutine.h"
|
||||
#include "qemu/id.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qapi-event.h"
|
||||
|
||||
@@ -58,7 +59,6 @@ static void __attribute__((__constructor__)) block_job_init(void)
|
||||
|
||||
static void block_job_event_cancelled(BlockJob *job);
|
||||
static void block_job_event_completed(BlockJob *job, const char *msg);
|
||||
static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job));
|
||||
|
||||
/* Transactional group of block jobs */
|
||||
struct BlockJobTxn {
|
||||
@@ -233,23 +233,26 @@ static char *child_job_get_parent_desc(BdrvChild *c)
|
||||
job->id);
|
||||
}
|
||||
|
||||
static void child_job_drained_begin(BdrvChild *c)
|
||||
static const BdrvChildRole child_job = {
|
||||
.get_parent_desc = child_job_get_parent_desc,
|
||||
.stay_at_node = true,
|
||||
};
|
||||
|
||||
static void block_job_drained_begin(void *opaque)
|
||||
{
|
||||
BlockJob *job = c->opaque;
|
||||
BlockJob *job = opaque;
|
||||
block_job_pause(job);
|
||||
}
|
||||
|
||||
static void child_job_drained_end(BdrvChild *c)
|
||||
static void block_job_drained_end(void *opaque)
|
||||
{
|
||||
BlockJob *job = c->opaque;
|
||||
BlockJob *job = opaque;
|
||||
block_job_resume(job);
|
||||
}
|
||||
|
||||
static const BdrvChildRole child_job = {
|
||||
.get_parent_desc = child_job_get_parent_desc,
|
||||
.drained_begin = child_job_drained_begin,
|
||||
.drained_end = child_job_drained_end,
|
||||
.stay_at_node = true,
|
||||
static const BlockDevOps block_job_dev_ops = {
|
||||
.drained_begin = block_job_drained_begin,
|
||||
.drained_end = block_job_drained_end,
|
||||
};
|
||||
|
||||
void block_job_remove_all_bdrv(BlockJob *job)
|
||||
@@ -477,16 +480,9 @@ static void block_job_completed_txn_success(BlockJob *job)
|
||||
}
|
||||
}
|
||||
|
||||
/* Assumes the block_job_mutex is held */
|
||||
static bool block_job_timer_pending(BlockJob *job)
|
||||
{
|
||||
return timer_pending(&job->sleep_timer);
|
||||
}
|
||||
|
||||
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int64_t old_speed = job->speed;
|
||||
|
||||
if (!job->driver->set_speed) {
|
||||
error_setg(errp, QERR_UNSUPPORTED);
|
||||
@@ -499,12 +495,6 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
||||
}
|
||||
|
||||
job->speed = speed;
|
||||
if (speed <= old_speed) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* kick only if a timer is pending */
|
||||
block_job_enter_cond(job, block_job_timer_pending);
|
||||
}
|
||||
|
||||
void block_job_complete(BlockJob *job, Error **errp)
|
||||
@@ -711,6 +701,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
||||
block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort);
|
||||
bs->job = job;
|
||||
|
||||
blk_set_dev_ops(blk, &block_job_dev_ops, job);
|
||||
bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
|
||||
|
||||
QLIST_INSERT_HEAD(&block_jobs, job, job_list);
|
||||
@@ -830,11 +821,7 @@ void block_job_resume_all(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Conditionally enter a block_job pending a call to fn() while
|
||||
* under the block_job_lock critical section.
|
||||
*/
|
||||
static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job))
|
||||
void block_job_enter(BlockJob *job)
|
||||
{
|
||||
if (!block_job_started(job)) {
|
||||
return;
|
||||
@@ -849,11 +836,6 @@ static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job))
|
||||
return;
|
||||
}
|
||||
|
||||
if (fn && !fn(job)) {
|
||||
block_job_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!job->deferred_to_main_loop);
|
||||
timer_del(&job->sleep_timer);
|
||||
job->busy = true;
|
||||
@@ -861,11 +843,6 @@ static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job))
|
||||
aio_co_wake(job->co);
|
||||
}
|
||||
|
||||
void block_job_enter(BlockJob *job)
|
||||
{
|
||||
block_job_enter_cond(job, NULL);
|
||||
}
|
||||
|
||||
bool block_job_is_cancelled(BlockJob *job)
|
||||
{
|
||||
return job->cancelled;
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "qemu/envlist.h"
|
||||
#include "exec/log.h"
|
||||
#include "trace/control.h"
|
||||
#include "glib-compat.h"
|
||||
|
||||
int singlestep;
|
||||
unsigned long mmap_min_addr;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* QEMU Baum Braille Device
|
||||
*
|
||||
* Copyright (c) 2008, 2010-2011, 2016-2017 Samuel Thibault
|
||||
* Copyright (c) 2008, 2010-2011, 2016 Samuel Thibault
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -239,12 +239,6 @@ static int baum_deferred_init(BaumChardev *baum)
|
||||
brlapi_perror("baum: brlapi__getDisplaySize");
|
||||
return 0;
|
||||
}
|
||||
if (baum->y > 1) {
|
||||
baum->y = 1;
|
||||
}
|
||||
if (baum->x > 84) {
|
||||
baum->x = 84;
|
||||
}
|
||||
|
||||
con = qemu_console_lookup_by_index(0);
|
||||
if (con && qemu_console_is_graphic(con)) {
|
||||
|
@@ -356,7 +356,7 @@ guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
|
||||
}
|
||||
|
||||
g_source_set_callback(src, (GSourceFunc)func, user_data, NULL);
|
||||
tag = g_source_attach(src, s->gcontext);
|
||||
tag = g_source_attach(src, NULL);
|
||||
g_source_unref(src);
|
||||
|
||||
return tag;
|
||||
|
@@ -21,10 +21,9 @@
|
||||
* 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 "qemu/option.h"
|
||||
#include "qemu-common.h"
|
||||
#include "chardev/char.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user