Compare commits
191 Commits
pull-ui-20
...
queue/ui+i
Author | SHA1 | Date | |
---|---|---|---|
|
6e24ee0c1e | ||
|
954ee55bd5 | ||
|
8498bb8d2e | ||
|
85970a627f | ||
|
51dbea77a2 | ||
|
77b0359bf4 | ||
|
d3b787fa7d | ||
|
e18a639164 | ||
|
469819a3e8 | ||
|
22a9e1fd63 | ||
|
84e3d0725b | ||
|
db7a99cdc1 | ||
|
32b9ca9868 | ||
|
2a747008cb | ||
|
92bd1e465b | ||
|
492734b5da | ||
|
d2a44865e8 | ||
|
a825ca0613 | ||
|
a08fc2f8cc | ||
|
c34647c18a | ||
|
2e1d6bdcce | ||
|
c9c06eb832 | ||
|
905bf0ee8a | ||
|
32809e7f7b | ||
|
8a98bfc6e3 | ||
|
8a48be0e87 | ||
|
96e659d006 | ||
|
cf80eb8d09 | ||
|
2c1c31ed55 | ||
|
438d116872 | ||
|
4c84f662c2 | ||
|
2499ee9fad | ||
|
7af25f9f6a | ||
|
896b6757f9 | ||
|
95e92000c8 | ||
|
3f8f1313e0 | ||
|
a4f113fd69 | ||
|
371c4ef637 | ||
|
d8dc67e119 | ||
|
6fafc26014 | ||
|
8dfaf23ae1 | ||
|
e85c0d1401 | ||
|
65a0e3e842 | ||
|
7e56accdaf | ||
|
269c20b2bb | ||
|
ad664c1d4c | ||
|
709fa704f6 | ||
|
61d7c14437 | ||
|
9848619a3b | ||
|
07fe095452 | ||
|
1eb4243434 | ||
|
77a7a36760 | ||
|
4ccd89d294 | ||
|
5d7fb0f254 | ||
|
c7b4efb4a0 | ||
|
1ea1572adf | ||
|
605553654f | ||
|
b81bdbf3c7 | ||
|
35f91e5069 | ||
|
6d13643a3a | ||
|
c5c6c47ce3 | ||
|
19e9cdf040 | ||
|
c03d83d55a | ||
|
b053ef6106 | ||
|
9ed442b8ae | ||
|
822335eb51 | ||
|
446de8b68a | ||
|
d528227d4c | ||
|
3fb2111fc9 | ||
|
76318657a8 | ||
|
85bbd1e7a4 | ||
|
1e507bb0fd | ||
|
d015c4ea6f | ||
|
3152779cd6 | ||
|
5923f85fb8 | ||
|
2bc7cfea09 | ||
|
61a8f418b2 | ||
|
36aeb6094f | ||
|
60390d2dc8 | ||
|
01b2ffcedd | ||
|
5135a1056d | ||
|
5837aaac25 | ||
|
8da54b2507 | ||
|
542f70c22e | ||
|
54e1d4ed1d | ||
|
b97a879de9 | ||
|
308714e6bc | ||
|
9c39b94f14 | ||
|
acb0b292b6 | ||
|
3fb53fb4d1 | ||
|
cc74d332ff | ||
|
2b48e10f88 | ||
|
6e3b2bfd6a | ||
|
b255b2c8a5 | ||
|
30ff7d1d0b | ||
|
cef8fd6836 | ||
|
a1fbe750fd | ||
|
58634047b7 | ||
|
c1214ad3dc | ||
|
7c877c8030 | ||
|
560f19f162 | ||
|
a2740ad584 | ||
|
7f3cf2d6e7 | ||
|
e7a3b91fdf | ||
|
b9313021f3 | ||
|
7feb51b709 | ||
|
e691ef6991 | ||
|
8bbf4aa96e | ||
|
2f295167e0 | ||
|
5b50bf77ce | ||
|
9caa6f3dbe | ||
|
39c1b4254e | ||
|
b64bd51efa | ||
|
c0bad49946 | ||
|
2119882c7e | ||
|
3783fa3dd3 | ||
|
47fec59941 | ||
|
f7946da274 | ||
|
ae2d489c34 | ||
|
93001e9d87 | ||
|
3b170dc867 | ||
|
7258ed930c | ||
|
850d54a2a9 | ||
|
e2a6ae7fe5 | ||
|
20fc71b25c | ||
|
d993b85804 | ||
|
414c2ec358 | ||
|
d3faa13e5f | ||
|
79f24568e5 | ||
|
80c58a5b1b | ||
|
73a27bbb69 | ||
|
f9f65a4af0 | ||
|
edf8bc9842 | ||
|
49cc0340f8 | ||
|
f12c1ebddf | ||
|
44cb280d33 | ||
|
d59157ea05 | ||
|
067b913619 | ||
|
e947738e38 | ||
|
8c372a02e0 | ||
|
2e5c9ad6f4 | ||
|
d9faeed854 | ||
|
7798d3aab9 | ||
|
c84087f2f5 | ||
|
ee898b870f | ||
|
2a6e128bfa | ||
|
572b97e722 | ||
|
a0dc63a6b7 | ||
|
2b0bbc4f88 | ||
|
44298024d3 | ||
|
d1fdf257d5 | ||
|
92229a57bb | ||
|
244f144134 | ||
|
d9bb58e510 | ||
|
a9ded6017e | ||
|
041e32b8d9 | ||
|
0c9390d978 | ||
|
457e03559d | ||
|
1d78a3c3ab | ||
|
a20fa79fa5 | ||
|
428952cfa9 | ||
|
87e459a810 | ||
|
b356807fcd | ||
|
36c327a69d | ||
|
5104fac853 | ||
|
24c0c77af5 | ||
|
134550bf81 | ||
|
660174fc1b | ||
|
6b9911d0b6 | ||
|
8381d89bec | ||
|
fea617c58b | ||
|
38b3362dd1 | ||
|
8d37b030fe | ||
|
e45e7ae281 | ||
|
73aa4692ec | ||
|
69e698220f | ||
|
c88f8107b1 | ||
|
e5b0cbe8e8 | ||
|
043b936ef6 | ||
|
5c3ad1a6a8 | ||
|
91589d9e5c | ||
|
3416ab5bb4 | ||
|
edc60127e4 | ||
|
1adc1ceef7 | ||
|
62a0265852 | ||
|
68a4a2fda1 | ||
|
076d4d39b6 | ||
|
becf8217de | ||
|
465aec4617 | ||
|
ad3c5412f2 | ||
|
d54fddea98 |
17
.gitignore
vendored
17
.gitignore
vendored
@@ -50,6 +50,7 @@
|
||||
/qemu-version.h.tmp
|
||||
/module_block.h
|
||||
/vscclient
|
||||
/vhost-user-scsi
|
||||
/fsdev/virtfs-proxy-helper
|
||||
*.[1-9]
|
||||
*.a
|
||||
@@ -99,14 +100,14 @@
|
||||
/pc-bios/optionrom/kvmvapic.img
|
||||
/pc-bios/s390-ccw/s390-ccw.elf
|
||||
/pc-bios/s390-ccw/s390-ccw.img
|
||||
/docs/qemu-ga-qapi.texi
|
||||
/docs/qemu-ga-ref.html
|
||||
/docs/qemu-ga-ref.info*
|
||||
/docs/qemu-ga-ref.txt
|
||||
/docs/qemu-qmp-qapi.texi
|
||||
/docs/qemu-qmp-ref.html
|
||||
/docs/qemu-qmp-ref.info*
|
||||
/docs/qemu-qmp-ref.txt
|
||||
/docs/interop/qemu-ga-qapi.texi
|
||||
/docs/interop/qemu-ga-ref.html
|
||||
/docs/interop/qemu-ga-ref.info*
|
||||
/docs/interop/qemu-ga-ref.txt
|
||||
/docs/interop/qemu-qmp-qapi.texi
|
||||
/docs/interop/qemu-qmp-ref.html
|
||||
/docs/interop/qemu-qmp-ref.info*
|
||||
/docs/interop/qemu-qmp-ref.txt
|
||||
/docs/version.texi
|
||||
*.tps
|
||||
.stgit-*
|
||||
|
@@ -1,15 +1,22 @@
|
||||
language: c
|
||||
git:
|
||||
submodules: false
|
||||
env:
|
||||
global:
|
||||
- LC_ALL=C
|
||||
matrix:
|
||||
- IMAGE=debian-armhf-cross
|
||||
TARGET_LIST=arm-softmmu,arm-linux-user
|
||||
TARGET_LIST=arm-softmmu,arm-linux-user,armeb-linux-user
|
||||
- IMAGE=debian-arm64-cross
|
||||
TARGET_LIST=aarch64-softmmu,aarch64-linux-user
|
||||
- IMAGE=debian-s390x-cross
|
||||
TARGET_LIST=s390x-softmmu,s390x-linux-user
|
||||
# mips64el-softmmu disabled due to libfdt problem
|
||||
- IMAGE=debian-mipsel-cross
|
||||
TARGET_LIST=mipsel-softmmu,mipsel-linux-user,mips64el-linux-user
|
||||
build:
|
||||
pre_ci:
|
||||
- make docker-image-${IMAGE}
|
||||
- make docker-image-${IMAGE} V=1
|
||||
pre_ci_boot:
|
||||
image_name: qemu
|
||||
image_tag: ${IMAGE}
|
||||
@@ -17,5 +24,13 @@ build:
|
||||
options: "-e HOME=/root"
|
||||
ci:
|
||||
- unset CC
|
||||
# some targets require newer up to date packages, for example TARGET_LIST matching
|
||||
# aarch64*-softmmu|arm*-softmmu|ppc*-softmmu|microblaze*-softmmu|mips64el-softmmu)
|
||||
# see the configure script:
|
||||
# error_exit "DTC (libfdt) version >= 1.4.2 not present. Your options:"
|
||||
# " (1) Preferred: Install the DTC (libfdt) devel package"
|
||||
# " (2) Fetch the DTC submodule, using:"
|
||||
# " git submodule update --init dtc"
|
||||
- dpkg --compare-versions `dpkg-query --showformat='${Version}' --show libfdt-dev` ge 1.4.2 || git submodule update --init dtc
|
||||
- ./configure ${QEMU_CONFIGURE_OPTS} --target-list=${TARGET_LIST}
|
||||
- make -j2
|
||||
- make -j$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||
|
@@ -1411,8 +1411,7 @@ F: include/qapi/qmp/
|
||||
X: include/qapi/qmp/dispatch.h
|
||||
F: scripts/coccinelle/qobject.cocci
|
||||
F: tests/check-qdict.c
|
||||
F: tests/check-qfloat.c
|
||||
F: tests/check-qint.c
|
||||
F: tests/check-qnum.c
|
||||
F: tests/check-qjson.c
|
||||
F: tests/check-qlist.c
|
||||
F: tests/check-qstring.c
|
||||
@@ -1858,12 +1857,14 @@ Build and test automation
|
||||
-------------------------
|
||||
M: Alex Bennée <alex.bennee@linaro.org>
|
||||
M: Fam Zheng <famz@redhat.com>
|
||||
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
L: qemu-devel@nongnu.org
|
||||
S: Maintained
|
||||
F: .travis.yml
|
||||
F: .shippable.yml
|
||||
F: tests/docker/
|
||||
W: https://travis-ci.org/qemu/qemu
|
||||
W: https://app.shippable.com/github/qemu/qemu
|
||||
W: http://patchew.org/QEMU/
|
||||
|
||||
Documentation
|
||||
|
77
Makefile
77
Makefile
@@ -207,8 +207,8 @@ HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
|
||||
|
||||
ifdef BUILD_DOCS
|
||||
DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8
|
||||
DOCS+=docs/qemu-qmp-ref.html docs/qemu-qmp-ref.txt docs/qemu-qmp-ref.7
|
||||
DOCS+=docs/qemu-ga-ref.html docs/qemu-ga-ref.txt docs/qemu-ga-ref.7
|
||||
DOCS+=docs/interop/qemu-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7
|
||||
DOCS+=docs/interop/qemu-ga-ref.html docs/interop/qemu-ga-ref.txt docs/interop/qemu-ga-ref.7
|
||||
ifdef CONFIG_VIRTFS
|
||||
DOCS+=fsdev/virtfs-proxy-helper.1
|
||||
endif
|
||||
@@ -269,6 +269,7 @@ dummy := $(call unnest-vars,, \
|
||||
ivshmem-client-obj-y \
|
||||
ivshmem-server-obj-y \
|
||||
libvhost-user-obj-y \
|
||||
vhost-user-scsi-obj-y \
|
||||
qga-vss-dll-obj-y \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
@@ -473,6 +474,8 @@ ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) $(COMMON_LDADDS)
|
||||
$(call LINK, $^)
|
||||
ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) $(COMMON_LDADDS)
|
||||
$(call LINK, $^)
|
||||
vhost-user-scsi$(EXESUF): $(vhost-user-scsi-obj-y)
|
||||
$(call LINK, $^)
|
||||
|
||||
module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak
|
||||
$(call quiet-command,$(PYTHON) $< $@ \
|
||||
@@ -519,11 +522,12 @@ distclean: clean
|
||||
rm -f qemu-doc.vr qemu-doc.txt
|
||||
rm -f config.log
|
||||
rm -f linux-headers/asm
|
||||
rm -f docs/qemu-ga-qapi.texi docs/qemu-qmp-qapi.texi docs/version.texi
|
||||
rm -f docs/qemu-qmp-ref.7 docs/qemu-ga-ref.7
|
||||
rm -f docs/qemu-qmp-ref.txt docs/qemu-ga-ref.txt
|
||||
rm -f docs/qemu-qmp-ref.pdf docs/qemu-ga-ref.pdf
|
||||
rm -f docs/qemu-qmp-ref.html docs/qemu-ga-ref.html
|
||||
rm -f docs/version.texi
|
||||
rm -f docs/interop/qemu-ga-qapi.texi docs/interop/qemu-qmp-qapi.texi
|
||||
rm -f docs/interop/qemu-qmp-ref.7 docs/interop/qemu-ga-ref.7
|
||||
rm -f docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt
|
||||
rm -f docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.pdf
|
||||
rm -f docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html
|
||||
for d in $(TARGET_DIRS); do \
|
||||
rm -rf $$d || exit 1 ; \
|
||||
done
|
||||
@@ -562,13 +566,13 @@ install-doc: $(DOCS)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) qemu-doc.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) qemu-doc.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/qemu-qmp-ref.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/qemu-qmp-ref.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
ifdef CONFIG_POSIX
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man7"
|
||||
$(INSTALL_DATA) docs/qemu-qmp-ref.7 "$(DESTDIR)$(mandir)/man7"
|
||||
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.7 "$(DESTDIR)$(mandir)/man7"
|
||||
ifneq ($(TOOLS),)
|
||||
$(INSTALL_DATA) qemu-img.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
|
||||
@@ -576,9 +580,9 @@ ifneq ($(TOOLS),)
|
||||
endif
|
||||
ifneq (,$(findstring qemu-ga,$(TOOLS)))
|
||||
$(INSTALL_DATA) qemu-ga.8 "$(DESTDIR)$(mandir)/man8"
|
||||
$(INSTALL_DATA) docs/qemu-ga-ref.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/qemu-ga-ref.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/qemu-ga-ref.7 "$(DESTDIR)$(mandir)/man7"
|
||||
$(INSTALL_DATA) docs/interop/qemu-ga-ref.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/interop/qemu-ga-ref.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/interop/qemu-ga-ref.7 "$(DESTDIR)$(mandir)/man7"
|
||||
endif
|
||||
endif
|
||||
ifdef CONFIG_VIRTFS
|
||||
@@ -666,28 +670,27 @@ ui/console-gl.o: $(SRC_PATH)/ui/console-gl.c \
|
||||
|
||||
# documentation
|
||||
MAKEINFO=makeinfo
|
||||
MAKEINFOFLAGS=--no-split --number-sections -I docs
|
||||
TEXIFLAG=$(if $(V),,--quiet)
|
||||
MAKEINFOINCLUDES= -I docs -I $(<D) -I $(@D)
|
||||
MAKEINFOFLAGS=--no-split --number-sections $(MAKEINFOINCLUDES)
|
||||
TEXI2PODFLAGS=$(MAKEINFOINCLUDES) "-DVERSION=$(VERSION)"
|
||||
TEXI2PDFFLAGS=$(if $(V),,--quiet) -I $(SRC_PATH) $(MAKEINFOINCLUDES)
|
||||
|
||||
docs/version.texi: $(SRC_PATH)/VERSION
|
||||
$(call quiet-command,echo "@set VERSION $(VERSION)" > $@,"GEN","$@")
|
||||
|
||||
%.html: %.texi
|
||||
%.html: %.texi docs/version.texi
|
||||
$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --no-headers \
|
||||
--html $< -o $@,"GEN","$@")
|
||||
|
||||
%.info: %.texi
|
||||
%.info: %.texi docs/version.texi
|
||||
$(call quiet-command,$(MAKEINFO) $(MAKEINFOFLAGS) $< -o $@,"GEN","$@")
|
||||
|
||||
%.txt: %.texi
|
||||
%.txt: %.texi docs/version.texi
|
||||
$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --no-headers \
|
||||
--plaintext $< -o $@,"GEN","$@")
|
||||
|
||||
%.pdf: %.texi
|
||||
$(call quiet-command,texi2pdf $(TEXIFLAG) -I $(SRC_PATH) -I docs $< -o $@,"GEN","$@")
|
||||
|
||||
docs/qemu-ga-ref.html docs/qemu-ga-ref.info docs/qemu-ga-ref.txt docs/qemu-ga-ref.pdf docs/qemu-ga-ref.7.pod: docs/version.texi
|
||||
docs/qemu-qmp-ref.html docs/qemu-qmp-ref.info docs/qemu-qmp-ref.txt docs/qemu-qmp-ref.pdf docs/qemu-qmp-ref.pod: docs/version.texi
|
||||
%.pdf: %.texi docs/version.texi
|
||||
$(call quiet-command,texi2pdf $(TEXI2PDFFLAGS) $< -o $@,"GEN","$@")
|
||||
|
||||
qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||
@@ -701,12 +704,12 @@ qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxt
|
||||
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||
|
||||
docs/qemu-qmp-qapi.texi docs/qemu-ga-qapi.texi: $(SRC_PATH)/scripts/qapi2texi.py $(qapi-py)
|
||||
docs/interop/qemu-qmp-qapi.texi docs/interop/qemu-ga-qapi.texi: $(SRC_PATH)/scripts/qapi2texi.py $(qapi-py)
|
||||
|
||||
docs/qemu-qmp-qapi.texi: $(qapi-modules)
|
||||
docs/interop/qemu-qmp-qapi.texi: $(qapi-modules)
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
|
||||
|
||||
docs/qemu-ga-qapi.texi: $(SRC_PATH)/qga/qapi-schema.json
|
||||
docs/interop/qemu-ga-qapi.texi: $(SRC_PATH)/qga/qapi-schema.json
|
||||
$(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
|
||||
@@ -716,21 +719,25 @@ fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
|
||||
qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi
|
||||
qemu-ga.8: qemu-ga.texi
|
||||
|
||||
html: qemu-doc.html docs/qemu-qmp-ref.html docs/qemu-ga-ref.html
|
||||
info: qemu-doc.info docs/qemu-qmp-ref.info docs/qemu-ga-ref.info
|
||||
pdf: qemu-doc.pdf docs/qemu-qmp-ref.pdf docs/qemu-ga-ref.pdf
|
||||
txt: qemu-doc.txt docs/qemu-qmp-ref.txt docs/qemu-ga-ref.txt
|
||||
html: qemu-doc.html docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html
|
||||
info: qemu-doc.info docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-ref.info
|
||||
pdf: qemu-doc.pdf docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.pdf
|
||||
txt: qemu-doc.txt docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt
|
||||
|
||||
qemu-doc.html qemu-doc.info qemu-doc.pdf qemu-doc.txt: \
|
||||
qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \
|
||||
qemu-monitor.texi qemu-img-cmds.texi qemu-ga.texi \
|
||||
qemu-monitor-info.texi
|
||||
|
||||
docs/qemu-ga-ref.dvi docs/qemu-ga-ref.html docs/qemu-ga-ref.info docs/qemu-ga-ref.pdf docs/qemu-ga-ref.txt docs/qemu-ga-ref.7: \
|
||||
docs/qemu-ga-ref.texi docs/qemu-ga-qapi.texi
|
||||
docs/interop/qemu-ga-ref.dvi docs/interop/qemu-ga-ref.html \
|
||||
docs/interop/qemu-ga-ref.info docs/interop/qemu-ga-ref.pdf \
|
||||
docs/interop/qemu-ga-ref.txt docs/interop/qemu-ga-ref.7: \
|
||||
docs/interop/qemu-ga-ref.texi docs/interop/qemu-ga-qapi.texi
|
||||
|
||||
docs/qemu-qmp-ref.dvi docs/qemu-qmp-ref.html docs/qemu-qmp-ref.info docs/qemu-qmp-ref.pdf docs/qemu-qmp-ref.txt docs/qemu-qmp-ref.7: \
|
||||
docs/qemu-qmp-ref.texi docs/qemu-qmp-qapi.texi
|
||||
docs/interop/qemu-qmp-ref.dvi docs/interop/qemu-qmp-ref.html \
|
||||
docs/interop/qemu-qmp-ref.info docs/interop/qemu-qmp-ref.pdf \
|
||||
docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7: \
|
||||
docs/interop/qemu-qmp-ref.texi docs/interop/qemu-qmp-qapi.texi
|
||||
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
@@ -791,9 +798,11 @@ endif # CONFIG_WIN
|
||||
|
||||
# Add a dependency on the generated files, so that they are always
|
||||
# rebuilt before other object files
|
||||
ifneq ($(wildcard config-host.mak),)
|
||||
ifneq ($(filter-out $(UNCHECKED_GOALS),$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail))
|
||||
Makefile: $(GENERATED_FILES)
|
||||
endif
|
||||
endif
|
||||
|
||||
.SECONDARY: $(TRACE_HEADERS) $(TRACE_HEADERS:%=%-timestamp) \
|
||||
$(TRACE_SOURCES) $(TRACE_SOURCES:%=%-timestamp) \
|
||||
|
@@ -52,7 +52,6 @@ common-obj-y += migration/
|
||||
|
||||
common-obj-y += audio/
|
||||
common-obj-y += hw/
|
||||
common-obj-y += accel.o
|
||||
|
||||
common-obj-y += replay/
|
||||
|
||||
@@ -111,6 +110,10 @@ qga-vss-dll-obj-y = qga/
|
||||
ivshmem-client-obj-y = contrib/ivshmem-client/
|
||||
ivshmem-server-obj-y = contrib/ivshmem-server/
|
||||
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-scsi-obj-y += contrib/libvhost-user/libvhost-user.o
|
||||
|
||||
######################################################################
|
||||
trace-events-subdirs =
|
||||
@@ -163,6 +166,8 @@ trace-events-subdirs += target/ppc
|
||||
trace-events-subdirs += qom
|
||||
trace-events-subdirs += linux-user
|
||||
trace-events-subdirs += qapi
|
||||
trace-events-subdirs += accel/tcg
|
||||
trace-events-subdirs += accel/kvm
|
||||
|
||||
trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)
|
||||
|
||||
|
@@ -88,20 +88,17 @@ all: $(PROGS) stap
|
||||
|
||||
#########################################################
|
||||
# cpu emulator library
|
||||
obj-y = exec.o translate-all.o cpu-exec.o
|
||||
obj-y += translate-common.o
|
||||
obj-y += cpu-exec-common.o
|
||||
obj-y += exec.o
|
||||
obj-y += accel/
|
||||
obj-y += tcg/tcg.o tcg/tcg-op.o tcg/optimize.o
|
||||
obj-$(CONFIG_TCG_INTERPRETER) += tci.o
|
||||
obj-y += tcg/tcg-common.o
|
||||
obj-y += tcg/tcg-common.o tcg/tcg-runtime.o
|
||||
obj-$(CONFIG_TCG_INTERPRETER) += tcg/tci.o
|
||||
obj-$(CONFIG_TCG_INTERPRETER) += disas/tci.o
|
||||
obj-y += fpu/softfloat.o
|
||||
obj-y += target/$(TARGET_BASE_ARCH)/
|
||||
obj-y += disas.o
|
||||
obj-y += tcg-runtime.o
|
||||
obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
|
||||
obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o
|
||||
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
|
||||
|
||||
obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/decContext.o
|
||||
obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/decNumber.o
|
||||
@@ -142,8 +139,7 @@ ifdef CONFIG_SOFTMMU
|
||||
obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o numa.o
|
||||
obj-y += qtest.o bootdevice.o
|
||||
obj-y += hw/
|
||||
obj-$(CONFIG_KVM) += kvm-all.o
|
||||
obj-y += memory.o cputlb.o
|
||||
obj-y += memory.o
|
||||
obj-y += memory_mapping.o
|
||||
obj-y += dump.o
|
||||
obj-y += migration/ram.o
|
||||
|
4
accel/Makefile.objs
Normal file
4
accel/Makefile.objs
Normal file
@@ -0,0 +1,4 @@
|
||||
obj-$(CONFIG_SOFTMMU) += accel.o
|
||||
obj-y += kvm/
|
||||
obj-y += tcg/
|
||||
obj-y += stubs/
|
@@ -34,15 +34,6 @@
|
||||
#include "hw/xen/xen.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
int tcg_tb_size;
|
||||
static bool tcg_allowed = true;
|
||||
|
||||
static int tcg_init(MachineState *ms)
|
||||
{
|
||||
tcg_exec_init(tcg_tb_size * 1024 * 1024);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const TypeInfo accel_type = {
|
||||
.name = TYPE_ACCEL,
|
||||
.parent = TYPE_OBJECT,
|
||||
@@ -129,27 +120,9 @@ void configure_accelerator(MachineState *ms)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void tcg_accel_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelClass *ac = ACCEL_CLASS(oc);
|
||||
ac->name = "tcg";
|
||||
ac->init_machine = tcg_init;
|
||||
ac->allowed = &tcg_allowed;
|
||||
}
|
||||
|
||||
#define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg")
|
||||
|
||||
static const TypeInfo tcg_accel_type = {
|
||||
.name = TYPE_TCG_ACCEL,
|
||||
.parent = TYPE_ACCEL,
|
||||
.class_init = tcg_accel_class_init,
|
||||
};
|
||||
|
||||
static void register_accel_types(void)
|
||||
{
|
||||
type_register_static(&accel_type);
|
||||
type_register_static(&tcg_accel_type);
|
||||
}
|
||||
|
||||
type_init(register_accel_types);
|
1
accel/kvm/Makefile.objs
Normal file
1
accel/kvm/Makefile.objs
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_KVM) += kvm-all.o
|
@@ -36,7 +36,7 @@
|
||||
#include "exec/ram_addr.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/event_notifier.h"
|
||||
#include "trace-root.h"
|
||||
#include "trace.h"
|
||||
#include "hw/irq.h"
|
||||
|
||||
#include "hw/boards.h"
|
||||
@@ -1977,6 +1977,7 @@ int kvm_cpu_exec(CPUState *cpu)
|
||||
}
|
||||
|
||||
qemu_mutex_unlock_iothread();
|
||||
cpu_exec_start(cpu);
|
||||
|
||||
do {
|
||||
MemTxAttrs attrs;
|
||||
@@ -2106,6 +2107,7 @@ int kvm_cpu_exec(CPUState *cpu)
|
||||
}
|
||||
} while (ret == 0);
|
||||
|
||||
cpu_exec_end(cpu);
|
||||
qemu_mutex_lock_iothread();
|
||||
|
||||
if (ret < 0) {
|
15
accel/kvm/trace-events
Normal file
15
accel/kvm/trace-events
Normal file
@@ -0,0 +1,15 @@
|
||||
# Trace events for debugging and performance instrumentation
|
||||
|
||||
# kvm-all.c
|
||||
kvm_ioctl(int type, void *arg) "type 0x%x, arg %p"
|
||||
kvm_vm_ioctl(int type, void *arg) "type 0x%x, arg %p"
|
||||
kvm_vcpu_ioctl(int cpu_index, int type, void *arg) "cpu_index %d, type 0x%x, arg %p"
|
||||
kvm_run_exit(int cpu_index, uint32_t reason) "cpu_index %d, reason %d"
|
||||
kvm_device_ioctl(int fd, int type, void *arg) "dev fd %d, type 0x%x, arg %p"
|
||||
kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s"
|
||||
kvm_failed_reg_set(uint64_t id, const char *msg) "Warning: Unable to set ONEREG %" PRIu64 " to KVM: %s"
|
||||
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"
|
||||
|
1
accel/stubs/Makefile.objs
Normal file
1
accel/stubs/Makefile.objs
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
|
3
accel/tcg/Makefile.objs
Normal file
3
accel/tcg/Makefile.objs
Normal file
@@ -0,0 +1,3 @@
|
||||
obj-$(CONFIG_SOFTMMU) += tcg-all.o
|
||||
obj-$(CONFIG_SOFTMMU) += cputlb.o
|
||||
obj-y += cpu-exec.o cpu-exec-common.o translate-all.o translate-common.o
|
@@ -18,7 +18,7 @@
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "trace-root.h"
|
||||
#include "trace.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg.h"
|
61
accel/tcg/tcg-all.c
Normal file
61
accel/tcg/tcg-all.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* QEMU System Emulator, accelerator interfaces
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2014 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "sysemu/accel.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
int tcg_tb_size;
|
||||
static bool tcg_allowed = true;
|
||||
|
||||
static int tcg_init(MachineState *ms)
|
||||
{
|
||||
tcg_exec_init(tcg_tb_size * 1024 * 1024);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tcg_accel_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelClass *ac = ACCEL_CLASS(oc);
|
||||
ac->name = "tcg";
|
||||
ac->init_machine = tcg_init;
|
||||
ac->allowed = &tcg_allowed;
|
||||
}
|
||||
|
||||
#define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg")
|
||||
|
||||
static const TypeInfo tcg_accel_type = {
|
||||
.name = TYPE_TCG_ACCEL,
|
||||
.parent = TYPE_ACCEL,
|
||||
.class_init = tcg_accel_class_init,
|
||||
};
|
||||
|
||||
static void register_accel_types(void)
|
||||
{
|
||||
type_register_static(&tcg_accel_type);
|
||||
}
|
||||
|
||||
type_init(register_accel_types);
|
10
accel/tcg/trace-events
Normal file
10
accel/tcg/trace-events
Normal file
@@ -0,0 +1,10 @@
|
||||
# Trace events for debugging and performance instrumentation
|
||||
|
||||
# TCG related tracing (mostly disabled by default)
|
||||
# cpu-exec.c
|
||||
disable exec_tb(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR
|
||||
disable exec_tb_nocache(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR
|
||||
disable exec_tb_exit(void *last_tb, unsigned int flags) "tb:%p flags=%x"
|
||||
|
||||
# translate-all.c
|
||||
translate_block(void *tb, uintptr_t pc, uint8_t *tb_code) "tb:%p, pc:0x%"PRIxPTR", tb_code:%p"
|
@@ -25,7 +25,7 @@
|
||||
#include "qemu-common.h"
|
||||
#define NO_CPU_IO_DEFS
|
||||
#include "cpu.h"
|
||||
#include "trace-root.h"
|
||||
#include "trace.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg.h"
|
||||
@@ -523,8 +523,6 @@ static inline PageDesc *page_find(tb_page_addr_t index)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (32u * 1024 * 1024)
|
||||
#elif defined(__aarch64__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (128ul * 1024 * 1024)
|
||||
#elif defined(__arm__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (16u * 1024 * 1024)
|
||||
#elif defined(__s390x__)
|
||||
/* We have a +- 4GB range on the branches; leave some slop. */
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (3ul * 1024 * 1024 * 1024)
|
||||
@@ -781,12 +779,13 @@ static inline void code_gen_alloc(size_t tb_size)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Estimate a good size for the number of TBs we can support. We
|
||||
still haven't deducted the prologue from the buffer size here,
|
||||
but that's minimal and won't affect the estimate much. */
|
||||
tcg_ctx.code_gen_max_blocks
|
||||
= tcg_ctx.code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
|
||||
tcg_ctx.tb_ctx.tbs = g_new(TranslationBlock, tcg_ctx.code_gen_max_blocks);
|
||||
/* size this conservatively -- realloc later if needed */
|
||||
tcg_ctx.tb_ctx.tbs_size =
|
||||
tcg_ctx.code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE / 8;
|
||||
if (unlikely(!tcg_ctx.tb_ctx.tbs_size)) {
|
||||
tcg_ctx.tb_ctx.tbs_size = 64 * 1024;
|
||||
}
|
||||
tcg_ctx.tb_ctx.tbs = g_new(TranslationBlock *, tcg_ctx.tb_ctx.tbs_size);
|
||||
|
||||
qemu_mutex_init(&tcg_ctx.tb_ctx.tb_lock);
|
||||
}
|
||||
@@ -828,16 +827,20 @@ bool tcg_enabled(void)
|
||||
static TranslationBlock *tb_alloc(target_ulong pc)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
TBContext *ctx;
|
||||
|
||||
assert_tb_locked();
|
||||
|
||||
if (tcg_ctx.tb_ctx.nb_tbs >= tcg_ctx.code_gen_max_blocks) {
|
||||
tb = tcg_tb_alloc(&tcg_ctx);
|
||||
if (unlikely(tb == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
tb = &tcg_ctx.tb_ctx.tbs[tcg_ctx.tb_ctx.nb_tbs++];
|
||||
tb->pc = pc;
|
||||
tb->cflags = 0;
|
||||
tb->invalid = false;
|
||||
ctx = &tcg_ctx.tb_ctx;
|
||||
if (unlikely(ctx->nb_tbs == ctx->tbs_size)) {
|
||||
ctx->tbs_size *= 2;
|
||||
ctx->tbs = g_renew(TranslationBlock *, ctx->tbs, ctx->tbs_size);
|
||||
}
|
||||
ctx->tbs[ctx->nb_tbs++] = tb;
|
||||
return tb;
|
||||
}
|
||||
|
||||
@@ -850,8 +853,10 @@ void tb_free(TranslationBlock *tb)
|
||||
Ignore the hard cases and just back up if this TB happens to
|
||||
be the last one generated. */
|
||||
if (tcg_ctx.tb_ctx.nb_tbs > 0 &&
|
||||
tb == &tcg_ctx.tb_ctx.tbs[tcg_ctx.tb_ctx.nb_tbs - 1]) {
|
||||
tcg_ctx.code_gen_ptr = tb->tc_ptr;
|
||||
tb == tcg_ctx.tb_ctx.tbs[tcg_ctx.tb_ctx.nb_tbs - 1]) {
|
||||
size_t struct_size = ROUND_UP(sizeof(*tb), qemu_icache_linesize);
|
||||
|
||||
tcg_ctx.code_gen_ptr = tb->tc_ptr - struct_size;
|
||||
tcg_ctx.tb_ctx.nb_tbs--;
|
||||
}
|
||||
}
|
||||
@@ -1279,9 +1284,11 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
|
||||
gen_code_buf = tcg_ctx.code_gen_ptr;
|
||||
tb->tc_ptr = gen_code_buf;
|
||||
tb->pc = pc;
|
||||
tb->cs_base = cs_base;
|
||||
tb->flags = flags;
|
||||
tb->cflags = cflags;
|
||||
tb->invalid = false;
|
||||
|
||||
#ifdef CONFIG_PROFILER
|
||||
tcg_ctx.tb_count1++; /* includes aborted translations because of
|
||||
@@ -1666,7 +1673,7 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr)
|
||||
m_max = tcg_ctx.tb_ctx.nb_tbs - 1;
|
||||
while (m_min <= m_max) {
|
||||
m = (m_min + m_max) >> 1;
|
||||
tb = &tcg_ctx.tb_ctx.tbs[m];
|
||||
tb = tcg_ctx.tb_ctx.tbs[m];
|
||||
v = (uintptr_t)tb->tc_ptr;
|
||||
if (v == tc_ptr) {
|
||||
return tb;
|
||||
@@ -1676,7 +1683,7 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr)
|
||||
m_min = m + 1;
|
||||
}
|
||||
}
|
||||
return &tcg_ctx.tb_ctx.tbs[m_max];
|
||||
return tcg_ctx.tb_ctx.tbs[m_max];
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
@@ -1874,7 +1881,7 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
|
||||
direct_jmp_count = 0;
|
||||
direct_jmp2_count = 0;
|
||||
for (i = 0; i < tcg_ctx.tb_ctx.nb_tbs; i++) {
|
||||
tb = &tcg_ctx.tb_ctx.tbs[i];
|
||||
tb = tcg_ctx.tb_ctx.tbs[i];
|
||||
target_code_size += tb->size;
|
||||
if (tb->size > max_target_code_size) {
|
||||
max_target_code_size = tb->size;
|
||||
@@ -1894,8 +1901,7 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
|
||||
cpu_fprintf(f, "gen code size %td/%zd\n",
|
||||
tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer,
|
||||
tcg_ctx.code_gen_highwater - tcg_ctx.code_gen_buffer);
|
||||
cpu_fprintf(f, "TB count %d/%d\n",
|
||||
tcg_ctx.tb_ctx.nb_tbs, tcg_ctx.code_gen_max_blocks);
|
||||
cpu_fprintf(f, "TB count %d\n", tcg_ctx.tb_ctx.nb_tbs);
|
||||
cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
|
||||
tcg_ctx.tb_ctx.nb_tbs ? target_code_size /
|
||||
tcg_ctx.tb_ctx.nb_tbs : 0,
|
@@ -222,7 +222,7 @@ cryptodev_backend_can_be_deleted(UserCreatable *uc, Error **errp)
|
||||
|
||||
static void cryptodev_backend_instance_init(Object *obj)
|
||||
{
|
||||
object_property_add(obj, "queues", "int",
|
||||
object_property_add(obj, "queues", "uint32",
|
||||
cryptodev_backend_get_queues,
|
||||
cryptodev_backend_set_queues,
|
||||
NULL, NULL, NULL);
|
||||
|
10
block.c
10
block.c
@@ -320,6 +320,8 @@ BlockDriverState *bdrv_new(void)
|
||||
QLIST_INIT(&bs->op_blockers[i]);
|
||||
}
|
||||
notifier_with_return_list_init(&bs->before_write_notifiers);
|
||||
qemu_co_mutex_init(&bs->reqs_lock);
|
||||
qemu_mutex_init(&bs->dirty_bitmap_mutex);
|
||||
bs->refcnt = 1;
|
||||
bs->aio_context = qemu_get_aio_context();
|
||||
|
||||
@@ -1300,7 +1302,9 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
|
||||
goto fail_opts;
|
||||
}
|
||||
|
||||
assert(bs->copy_on_read == 0); /* bdrv_new() and bdrv_close() make it so */
|
||||
/* bdrv_new() and bdrv_close() make it so */
|
||||
assert(atomic_read(&bs->copy_on_read) == 0);
|
||||
|
||||
if (bs->open_flags & BDRV_O_COPY_ON_READ) {
|
||||
if (!bs->read_only) {
|
||||
bdrv_enable_copy_on_read(bs);
|
||||
@@ -3063,7 +3067,7 @@ static void bdrv_close(BlockDriverState *bs)
|
||||
|
||||
g_free(bs->opaque);
|
||||
bs->opaque = NULL;
|
||||
bs->copy_on_read = 0;
|
||||
atomic_set(&bs->copy_on_read, 0);
|
||||
bs->backing_file[0] = '\0';
|
||||
bs->backing_format[0] = '\0';
|
||||
bs->total_sectors = 0;
|
||||
@@ -3422,7 +3426,7 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp)
|
||||
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
|
||||
bdrv_dirty_bitmap_truncate(bs);
|
||||
bdrv_parent_cb_resize(bs);
|
||||
++bs->write_gen;
|
||||
atomic_inc(&bs->write_gen);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@@ -32,23 +32,28 @@
|
||||
static QEMUClockType clock_type = QEMU_CLOCK_REALTIME;
|
||||
static const int qtest_latency_ns = NANOSECONDS_PER_SECOND / 1000;
|
||||
|
||||
void block_acct_init(BlockAcctStats *stats, bool account_invalid,
|
||||
bool account_failed)
|
||||
void block_acct_init(BlockAcctStats *stats)
|
||||
{
|
||||
stats->account_invalid = account_invalid;
|
||||
stats->account_failed = account_failed;
|
||||
|
||||
qemu_mutex_init(&stats->lock);
|
||||
if (qtest_enabled()) {
|
||||
clock_type = QEMU_CLOCK_VIRTUAL;
|
||||
}
|
||||
}
|
||||
|
||||
void block_acct_setup(BlockAcctStats *stats, bool account_invalid,
|
||||
bool account_failed)
|
||||
{
|
||||
stats->account_invalid = account_invalid;
|
||||
stats->account_failed = account_failed;
|
||||
}
|
||||
|
||||
void block_acct_cleanup(BlockAcctStats *stats)
|
||||
{
|
||||
BlockAcctTimedStats *s, *next;
|
||||
QSLIST_FOREACH_SAFE(s, &stats->intervals, entries, next) {
|
||||
g_free(s);
|
||||
}
|
||||
qemu_mutex_destroy(&stats->lock);
|
||||
}
|
||||
|
||||
void block_acct_add_interval(BlockAcctStats *stats, unsigned interval_length)
|
||||
@@ -58,12 +63,15 @@ void block_acct_add_interval(BlockAcctStats *stats, unsigned interval_length)
|
||||
|
||||
s = g_new0(BlockAcctTimedStats, 1);
|
||||
s->interval_length = interval_length;
|
||||
s->stats = stats;
|
||||
qemu_mutex_lock(&stats->lock);
|
||||
QSLIST_INSERT_HEAD(&stats->intervals, s, entries);
|
||||
|
||||
for (i = 0; i < BLOCK_MAX_IOTYPE; i++) {
|
||||
timed_average_init(&s->latency[i], clock_type,
|
||||
(uint64_t) interval_length * NANOSECONDS_PER_SECOND);
|
||||
}
|
||||
qemu_mutex_unlock(&stats->lock);
|
||||
}
|
||||
|
||||
BlockAcctTimedStats *block_acct_interval_next(BlockAcctStats *stats,
|
||||
@@ -86,7 +94,8 @@ void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
|
||||
cookie->type = type;
|
||||
}
|
||||
|
||||
void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie)
|
||||
static void block_account_one_io(BlockAcctStats *stats, BlockAcctCookie *cookie,
|
||||
bool failed)
|
||||
{
|
||||
BlockAcctTimedStats *s;
|
||||
int64_t time_ns = qemu_clock_get_ns(clock_type);
|
||||
@@ -98,31 +107,16 @@ void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie)
|
||||
|
||||
assert(cookie->type < BLOCK_MAX_IOTYPE);
|
||||
|
||||
stats->nr_bytes[cookie->type] += cookie->bytes;
|
||||
stats->nr_ops[cookie->type]++;
|
||||
stats->total_time_ns[cookie->type] += latency_ns;
|
||||
stats->last_access_time_ns = time_ns;
|
||||
qemu_mutex_lock(&stats->lock);
|
||||
|
||||
QSLIST_FOREACH(s, &stats->intervals, entries) {
|
||||
timed_average_account(&s->latency[cookie->type], latency_ns);
|
||||
if (failed) {
|
||||
stats->failed_ops[cookie->type]++;
|
||||
} else {
|
||||
stats->nr_bytes[cookie->type] += cookie->bytes;
|
||||
stats->nr_ops[cookie->type]++;
|
||||
}
|
||||
}
|
||||
|
||||
void block_acct_failed(BlockAcctStats *stats, BlockAcctCookie *cookie)
|
||||
{
|
||||
assert(cookie->type < BLOCK_MAX_IOTYPE);
|
||||
|
||||
stats->failed_ops[cookie->type]++;
|
||||
|
||||
if (stats->account_failed) {
|
||||
BlockAcctTimedStats *s;
|
||||
int64_t time_ns = qemu_clock_get_ns(clock_type);
|
||||
int64_t latency_ns = time_ns - cookie->start_time_ns;
|
||||
|
||||
if (qtest_enabled()) {
|
||||
latency_ns = qtest_latency_ns;
|
||||
}
|
||||
|
||||
if (!failed || stats->account_failed) {
|
||||
stats->total_time_ns[cookie->type] += latency_ns;
|
||||
stats->last_access_time_ns = time_ns;
|
||||
|
||||
@@ -130,29 +124,45 @@ void block_acct_failed(BlockAcctStats *stats, BlockAcctCookie *cookie)
|
||||
timed_average_account(&s->latency[cookie->type], latency_ns);
|
||||
}
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&stats->lock);
|
||||
}
|
||||
|
||||
void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie)
|
||||
{
|
||||
block_account_one_io(stats, cookie, false);
|
||||
}
|
||||
|
||||
void block_acct_failed(BlockAcctStats *stats, BlockAcctCookie *cookie)
|
||||
{
|
||||
block_account_one_io(stats, cookie, true);
|
||||
}
|
||||
|
||||
void block_acct_invalid(BlockAcctStats *stats, enum BlockAcctType type)
|
||||
{
|
||||
assert(type < BLOCK_MAX_IOTYPE);
|
||||
|
||||
/* block_acct_done() and block_acct_failed() update
|
||||
* total_time_ns[], but this one does not. The reason is that
|
||||
* invalid requests are accounted during their submission,
|
||||
* therefore there's no actual I/O involved. */
|
||||
|
||||
/* block_account_one_io() updates total_time_ns[], but this one does
|
||||
* not. The reason is that invalid requests are accounted during their
|
||||
* submission, therefore there's no actual I/O involved.
|
||||
*/
|
||||
qemu_mutex_lock(&stats->lock);
|
||||
stats->invalid_ops[type]++;
|
||||
|
||||
if (stats->account_invalid) {
|
||||
stats->last_access_time_ns = qemu_clock_get_ns(clock_type);
|
||||
}
|
||||
qemu_mutex_unlock(&stats->lock);
|
||||
}
|
||||
|
||||
void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type,
|
||||
int num_requests)
|
||||
{
|
||||
assert(type < BLOCK_MAX_IOTYPE);
|
||||
|
||||
qemu_mutex_lock(&stats->lock);
|
||||
stats->merged[type] += num_requests;
|
||||
qemu_mutex_unlock(&stats->lock);
|
||||
}
|
||||
|
||||
int64_t block_acct_idle_time_ns(BlockAcctStats *stats)
|
||||
@@ -167,7 +177,9 @@ double block_acct_queue_depth(BlockAcctTimedStats *stats,
|
||||
|
||||
assert(type < BLOCK_MAX_IOTYPE);
|
||||
|
||||
qemu_mutex_lock(&stats->stats->lock);
|
||||
sum = timed_average_sum(&stats->latency[type], &elapsed);
|
||||
qemu_mutex_unlock(&stats->stats->lock);
|
||||
|
||||
return (double) sum / elapsed;
|
||||
}
|
||||
|
@@ -31,7 +31,6 @@
|
||||
#include "qemu/module.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "sysemu/qtest.h"
|
||||
|
||||
|
@@ -216,8 +216,10 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
|
||||
blk->shared_perm = shared_perm;
|
||||
blk_set_enable_write_cache(blk, true);
|
||||
|
||||
qemu_co_mutex_init(&blk->public.throttled_reqs_lock);
|
||||
qemu_co_queue_init(&blk->public.throttled_reqs[0]);
|
||||
qemu_co_queue_init(&blk->public.throttled_reqs[1]);
|
||||
block_acct_init(&blk->stats);
|
||||
|
||||
notifier_list_init(&blk->remove_bs_notifiers);
|
||||
notifier_list_init(&blk->insert_bs_notifiers);
|
||||
@@ -1953,7 +1955,7 @@ static void blk_root_drained_begin(BdrvChild *child)
|
||||
/* Note that blk->root may not be accessible here yet if we are just
|
||||
* attaching to a BlockDriverState that is drained. Use child instead. */
|
||||
|
||||
if (blk->public.io_limits_disabled++ == 0) {
|
||||
if (atomic_fetch_inc(&blk->public.io_limits_disabled) == 0) {
|
||||
throttle_group_restart_blk(blk);
|
||||
}
|
||||
}
|
||||
@@ -1964,7 +1966,7 @@ static void blk_root_drained_end(BdrvChild *child)
|
||||
assert(blk->quiesce_counter);
|
||||
|
||||
assert(blk->public.io_limits_disabled);
|
||||
--blk->public.io_limits_disabled;
|
||||
atomic_dec(&blk->public.io_limits_disabled);
|
||||
|
||||
if (--blk->quiesce_counter == 0) {
|
||||
if (blk->dev_ops && blk->dev_ops->drained_end) {
|
||||
|
@@ -37,6 +37,7 @@
|
||||
* or enabled. A frozen bitmap can only abdicate() or reclaim().
|
||||
*/
|
||||
struct BdrvDirtyBitmap {
|
||||
QemuMutex *mutex;
|
||||
HBitmap *bitmap; /* Dirty sector bitmap implementation */
|
||||
HBitmap *meta; /* Meta dirty bitmap */
|
||||
BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
|
||||
@@ -52,6 +53,27 @@ struct BdrvDirtyBitmapIter {
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
};
|
||||
|
||||
static inline void bdrv_dirty_bitmaps_lock(BlockDriverState *bs)
|
||||
{
|
||||
qemu_mutex_lock(&bs->dirty_bitmap_mutex);
|
||||
}
|
||||
|
||||
static inline void bdrv_dirty_bitmaps_unlock(BlockDriverState *bs)
|
||||
{
|
||||
qemu_mutex_unlock(&bs->dirty_bitmap_mutex);
|
||||
}
|
||||
|
||||
void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
qemu_mutex_lock(bitmap->mutex);
|
||||
}
|
||||
|
||||
void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
qemu_mutex_unlock(bitmap->mutex);
|
||||
}
|
||||
|
||||
/* Called with BQL or dirty_bitmap lock taken. */
|
||||
BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
|
||||
{
|
||||
BdrvDirtyBitmap *bm;
|
||||
@@ -65,6 +87,7 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Called with BQL taken. */
|
||||
void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
assert(!bdrv_dirty_bitmap_frozen(bitmap));
|
||||
@@ -72,6 +95,7 @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
|
||||
bitmap->name = NULL;
|
||||
}
|
||||
|
||||
/* Called with BQL taken. */
|
||||
BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
|
||||
uint32_t granularity,
|
||||
const char *name,
|
||||
@@ -96,11 +120,14 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
|
||||
return NULL;
|
||||
}
|
||||
bitmap = g_new0(BdrvDirtyBitmap, 1);
|
||||
bitmap->mutex = &bs->dirty_bitmap_mutex;
|
||||
bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(sector_granularity));
|
||||
bitmap->size = bitmap_size;
|
||||
bitmap->name = g_strdup(name);
|
||||
bitmap->disabled = false;
|
||||
bdrv_dirty_bitmaps_lock(bs);
|
||||
QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
|
||||
bdrv_dirty_bitmaps_unlock(bs);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@@ -119,20 +146,24 @@ void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
||||
int chunk_size)
|
||||
{
|
||||
assert(!bitmap->meta);
|
||||
qemu_mutex_lock(bitmap->mutex);
|
||||
bitmap->meta = hbitmap_create_meta(bitmap->bitmap,
|
||||
chunk_size * BITS_PER_BYTE);
|
||||
qemu_mutex_unlock(bitmap->mutex);
|
||||
}
|
||||
|
||||
void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
assert(bitmap->meta);
|
||||
qemu_mutex_lock(bitmap->mutex);
|
||||
hbitmap_free_meta(bitmap->bitmap);
|
||||
bitmap->meta = NULL;
|
||||
qemu_mutex_unlock(bitmap->mutex);
|
||||
}
|
||||
|
||||
int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
|
||||
BdrvDirtyBitmap *bitmap, int64_t sector,
|
||||
int nb_sectors)
|
||||
int bdrv_dirty_bitmap_get_meta_locked(BlockDriverState *bs,
|
||||
BdrvDirtyBitmap *bitmap, int64_t sector,
|
||||
int nb_sectors)
|
||||
{
|
||||
uint64_t i;
|
||||
int sectors_per_bit = 1 << hbitmap_granularity(bitmap->meta);
|
||||
@@ -147,11 +178,26 @@ int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
|
||||
return false;
|
||||
}
|
||||
|
||||
int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
|
||||
BdrvDirtyBitmap *bitmap, int64_t sector,
|
||||
int nb_sectors)
|
||||
{
|
||||
bool dirty;
|
||||
|
||||
qemu_mutex_lock(bitmap->mutex);
|
||||
dirty = bdrv_dirty_bitmap_get_meta_locked(bs, bitmap, sector, nb_sectors);
|
||||
qemu_mutex_unlock(bitmap->mutex);
|
||||
|
||||
return dirty;
|
||||
}
|
||||
|
||||
void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
|
||||
BdrvDirtyBitmap *bitmap, int64_t sector,
|
||||
int nb_sectors)
|
||||
{
|
||||
qemu_mutex_lock(bitmap->mutex);
|
||||
hbitmap_reset(bitmap->meta, sector, nb_sectors);
|
||||
qemu_mutex_unlock(bitmap->mutex);
|
||||
}
|
||||
|
||||
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap)
|
||||
@@ -164,16 +210,19 @@ const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap)
|
||||
return bitmap->name;
|
||||
}
|
||||
|
||||
/* Called with BQL taken. */
|
||||
bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
return bitmap->successor;
|
||||
}
|
||||
|
||||
/* Called with BQL taken. */
|
||||
bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
return !(bitmap->disabled || bitmap->successor);
|
||||
}
|
||||
|
||||
/* Called with BQL taken. */
|
||||
DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
if (bdrv_dirty_bitmap_frozen(bitmap)) {
|
||||
@@ -188,6 +237,7 @@ DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
|
||||
/**
|
||||
* Create a successor bitmap destined to replace this bitmap after an operation.
|
||||
* Requires that the bitmap is not frozen and has no successor.
|
||||
* Called with BQL taken.
|
||||
*/
|
||||
int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
|
||||
BdrvDirtyBitmap *bitmap, Error **errp)
|
||||
@@ -220,6 +270,7 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
|
||||
/**
|
||||
* For a bitmap with a successor, yield our name to the successor,
|
||||
* delete the old bitmap, and return a handle to the new bitmap.
|
||||
* Called with BQL taken.
|
||||
*/
|
||||
BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
|
||||
BdrvDirtyBitmap *bitmap,
|
||||
@@ -247,6 +298,7 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
|
||||
* In cases of failure where we can no longer safely delete the parent,
|
||||
* we may wish to re-join the parent and child/successor.
|
||||
* The merged parent will be un-frozen, but not explicitly re-enabled.
|
||||
* Called with BQL taken.
|
||||
*/
|
||||
BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
|
||||
BdrvDirtyBitmap *parent,
|
||||
@@ -271,25 +323,30 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
|
||||
|
||||
/**
|
||||
* Truncates _all_ bitmaps attached to a BDS.
|
||||
* Called with BQL taken.
|
||||
*/
|
||||
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
|
||||
{
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
uint64_t size = bdrv_nb_sectors(bs);
|
||||
|
||||
bdrv_dirty_bitmaps_lock(bs);
|
||||
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
||||
assert(!bdrv_dirty_bitmap_frozen(bitmap));
|
||||
assert(!bitmap->active_iterators);
|
||||
hbitmap_truncate(bitmap->bitmap, size);
|
||||
bitmap->size = size;
|
||||
}
|
||||
bdrv_dirty_bitmaps_unlock(bs);
|
||||
}
|
||||
|
||||
/* Called with BQL taken. */
|
||||
static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
|
||||
BdrvDirtyBitmap *bitmap,
|
||||
bool only_named)
|
||||
{
|
||||
BdrvDirtyBitmap *bm, *next;
|
||||
bdrv_dirty_bitmaps_lock(bs);
|
||||
QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
|
||||
if ((!bitmap || bm == bitmap) && (!only_named || bm->name)) {
|
||||
assert(!bm->active_iterators);
|
||||
@@ -301,15 +358,19 @@ static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
|
||||
g_free(bm);
|
||||
|
||||
if (bitmap) {
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bitmap) {
|
||||
abort();
|
||||
}
|
||||
|
||||
out:
|
||||
bdrv_dirty_bitmaps_unlock(bs);
|
||||
}
|
||||
|
||||
/* Called with BQL taken. */
|
||||
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
bdrv_do_release_matching_dirty_bitmap(bs, bitmap, false);
|
||||
@@ -318,18 +379,21 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
|
||||
/**
|
||||
* Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()).
|
||||
* There must not be any frozen bitmaps attached.
|
||||
* Called with BQL taken.
|
||||
*/
|
||||
void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_do_release_matching_dirty_bitmap(bs, NULL, true);
|
||||
}
|
||||
|
||||
/* Called with BQL taken. */
|
||||
void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
assert(!bdrv_dirty_bitmap_frozen(bitmap));
|
||||
bitmap->disabled = true;
|
||||
}
|
||||
|
||||
/* Called with BQL taken. */
|
||||
void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
assert(!bdrv_dirty_bitmap_frozen(bitmap));
|
||||
@@ -342,6 +406,7 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
|
||||
BlockDirtyInfoList *list = NULL;
|
||||
BlockDirtyInfoList **plist = &list;
|
||||
|
||||
bdrv_dirty_bitmaps_lock(bs);
|
||||
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
|
||||
BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1);
|
||||
BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1);
|
||||
@@ -354,12 +419,14 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
|
||||
*plist = entry;
|
||||
plist = &entry->next;
|
||||
}
|
||||
bdrv_dirty_bitmaps_unlock(bs);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t sector)
|
||||
/* Called within bdrv_dirty_bitmap_lock..unlock */
|
||||
int bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t sector)
|
||||
{
|
||||
if (bitmap) {
|
||||
return hbitmap_get(bitmap->bitmap, sector);
|
||||
@@ -432,23 +499,42 @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
|
||||
return hbitmap_iter_next(&iter->hbi);
|
||||
}
|
||||
|
||||
void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
||||
int64_t cur_sector, int64_t nr_sectors)
|
||||
/* Called within bdrv_dirty_bitmap_lock..unlock */
|
||||
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
|
||||
int64_t cur_sector, int64_t nr_sectors)
|
||||
{
|
||||
assert(bdrv_dirty_bitmap_enabled(bitmap));
|
||||
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
|
||||
}
|
||||
|
||||
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
||||
int64_t cur_sector, int64_t nr_sectors)
|
||||
void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
||||
int64_t cur_sector, int64_t nr_sectors)
|
||||
{
|
||||
bdrv_dirty_bitmap_lock(bitmap);
|
||||
bdrv_set_dirty_bitmap_locked(bitmap, cur_sector, nr_sectors);
|
||||
bdrv_dirty_bitmap_unlock(bitmap);
|
||||
}
|
||||
|
||||
/* Called within bdrv_dirty_bitmap_lock..unlock */
|
||||
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
|
||||
int64_t cur_sector, int64_t nr_sectors)
|
||||
{
|
||||
assert(bdrv_dirty_bitmap_enabled(bitmap));
|
||||
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
|
||||
}
|
||||
|
||||
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
||||
int64_t cur_sector, int64_t nr_sectors)
|
||||
{
|
||||
bdrv_dirty_bitmap_lock(bitmap);
|
||||
bdrv_reset_dirty_bitmap_locked(bitmap, cur_sector, nr_sectors);
|
||||
bdrv_dirty_bitmap_unlock(bitmap);
|
||||
}
|
||||
|
||||
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
|
||||
{
|
||||
assert(bdrv_dirty_bitmap_enabled(bitmap));
|
||||
bdrv_dirty_bitmap_lock(bitmap);
|
||||
if (!out) {
|
||||
hbitmap_reset_all(bitmap->bitmap);
|
||||
} else {
|
||||
@@ -457,6 +543,7 @@ void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
|
||||
hbitmap_granularity(backup));
|
||||
*out = backup;
|
||||
}
|
||||
bdrv_dirty_bitmap_unlock(bitmap);
|
||||
}
|
||||
|
||||
void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
|
||||
@@ -508,12 +595,19 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int64_t nr_sectors)
|
||||
{
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
|
||||
if (QLIST_EMPTY(&bs->dirty_bitmaps)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_dirty_bitmaps_lock(bs);
|
||||
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
||||
if (!bdrv_dirty_bitmap_enabled(bitmap)) {
|
||||
continue;
|
||||
}
|
||||
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
|
||||
}
|
||||
bdrv_dirty_bitmaps_unlock(bs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
51
block/io.c
51
block/io.c
@@ -130,13 +130,13 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
*/
|
||||
void bdrv_enable_copy_on_read(BlockDriverState *bs)
|
||||
{
|
||||
bs->copy_on_read++;
|
||||
atomic_inc(&bs->copy_on_read);
|
||||
}
|
||||
|
||||
void bdrv_disable_copy_on_read(BlockDriverState *bs)
|
||||
{
|
||||
assert(bs->copy_on_read > 0);
|
||||
bs->copy_on_read--;
|
||||
int old = atomic_fetch_dec(&bs->copy_on_read);
|
||||
assert(old >= 1);
|
||||
}
|
||||
|
||||
/* Check if any requests are in-flight (including throttled requests) */
|
||||
@@ -241,7 +241,7 @@ void bdrv_drained_begin(BlockDriverState *bs)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bs->quiesce_counter++) {
|
||||
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
|
||||
aio_disable_external(bdrv_get_aio_context(bs));
|
||||
bdrv_parent_drained_begin(bs);
|
||||
}
|
||||
@@ -252,7 +252,7 @@ void bdrv_drained_begin(BlockDriverState *bs)
|
||||
void bdrv_drained_end(BlockDriverState *bs)
|
||||
{
|
||||
assert(bs->quiesce_counter > 0);
|
||||
if (--bs->quiesce_counter > 0) {
|
||||
if (atomic_fetch_dec(&bs->quiesce_counter) > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -375,11 +375,13 @@ void bdrv_drain_all(void)
|
||||
static void tracked_request_end(BdrvTrackedRequest *req)
|
||||
{
|
||||
if (req->serialising) {
|
||||
req->bs->serialising_in_flight--;
|
||||
atomic_dec(&req->bs->serialising_in_flight);
|
||||
}
|
||||
|
||||
qemu_co_mutex_lock(&req->bs->reqs_lock);
|
||||
QLIST_REMOVE(req, list);
|
||||
qemu_co_queue_restart_all(&req->wait_queue);
|
||||
qemu_co_mutex_unlock(&req->bs->reqs_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -404,7 +406,9 @@ static void tracked_request_begin(BdrvTrackedRequest *req,
|
||||
|
||||
qemu_co_queue_init(&req->wait_queue);
|
||||
|
||||
qemu_co_mutex_lock(&bs->reqs_lock);
|
||||
QLIST_INSERT_HEAD(&bs->tracked_requests, req, list);
|
||||
qemu_co_mutex_unlock(&bs->reqs_lock);
|
||||
}
|
||||
|
||||
static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
|
||||
@@ -414,7 +418,7 @@ static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
|
||||
- overlap_offset;
|
||||
|
||||
if (!req->serialising) {
|
||||
req->bs->serialising_in_flight++;
|
||||
atomic_inc(&req->bs->serialising_in_flight);
|
||||
req->serialising = true;
|
||||
}
|
||||
|
||||
@@ -501,7 +505,8 @@ static void dummy_bh_cb(void *opaque)
|
||||
|
||||
void bdrv_wakeup(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->wakeup) {
|
||||
/* The barrier (or an atomic op) is in the caller. */
|
||||
if (atomic_read(&bs->wakeup)) {
|
||||
aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL);
|
||||
}
|
||||
}
|
||||
@@ -519,12 +524,13 @@ static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
|
||||
bool retry;
|
||||
bool waited = false;
|
||||
|
||||
if (!bs->serialising_in_flight) {
|
||||
if (!atomic_read(&bs->serialising_in_flight)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
retry = false;
|
||||
qemu_co_mutex_lock(&bs->reqs_lock);
|
||||
QLIST_FOREACH(req, &bs->tracked_requests, list) {
|
||||
if (req == self || (!req->serialising && !self->serialising)) {
|
||||
continue;
|
||||
@@ -543,7 +549,7 @@ static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
|
||||
* (instead of producing a deadlock in the former case). */
|
||||
if (!req->waiting_for) {
|
||||
self->waiting_for = req;
|
||||
qemu_co_queue_wait(&req->wait_queue, NULL);
|
||||
qemu_co_queue_wait(&req->wait_queue, &bs->reqs_lock);
|
||||
self->waiting_for = NULL;
|
||||
retry = true;
|
||||
waited = true;
|
||||
@@ -551,6 +557,7 @@ static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
|
||||
}
|
||||
}
|
||||
}
|
||||
qemu_co_mutex_unlock(&bs->reqs_lock);
|
||||
} while (retry);
|
||||
|
||||
return waited;
|
||||
@@ -1144,7 +1151,7 @@ int coroutine_fn bdrv_co_preadv(BdrvChild *child,
|
||||
bdrv_inc_in_flight(bs);
|
||||
|
||||
/* Don't do copy-on-read if we read data before write operation */
|
||||
if (bs->copy_on_read && !(flags & BDRV_REQ_NO_SERIALISING)) {
|
||||
if (atomic_read(&bs->copy_on_read) && !(flags & BDRV_REQ_NO_SERIALISING)) {
|
||||
flags |= BDRV_REQ_COPY_ON_READ;
|
||||
}
|
||||
|
||||
@@ -1401,12 +1408,10 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
|
||||
}
|
||||
bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE);
|
||||
|
||||
++bs->write_gen;
|
||||
atomic_inc(&bs->write_gen);
|
||||
bdrv_set_dirty(bs, start_sector, end_sector - start_sector);
|
||||
|
||||
if (bs->wr_highest_offset < offset + bytes) {
|
||||
bs->wr_highest_offset = offset + bytes;
|
||||
}
|
||||
stat64_max(&bs->wr_highest_offset, offset + bytes);
|
||||
|
||||
if (ret >= 0) {
|
||||
bs->total_sectors = MAX(bs->total_sectors, end_sector);
|
||||
@@ -2292,14 +2297,17 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
|
||||
goto early_exit;
|
||||
}
|
||||
|
||||
current_gen = bs->write_gen;
|
||||
qemu_co_mutex_lock(&bs->reqs_lock);
|
||||
current_gen = atomic_read(&bs->write_gen);
|
||||
|
||||
/* Wait until any previous flushes are completed */
|
||||
while (bs->active_flush_req) {
|
||||
qemu_co_queue_wait(&bs->flush_queue, NULL);
|
||||
qemu_co_queue_wait(&bs->flush_queue, &bs->reqs_lock);
|
||||
}
|
||||
|
||||
/* Flushes reach this point in nondecreasing current_gen order. */
|
||||
bs->active_flush_req = true;
|
||||
qemu_co_mutex_unlock(&bs->reqs_lock);
|
||||
|
||||
/* Write back all layers by calling one driver function */
|
||||
if (bs->drv->bdrv_co_flush) {
|
||||
@@ -2371,9 +2379,12 @@ out:
|
||||
if (ret == 0) {
|
||||
bs->flushed_gen = current_gen;
|
||||
}
|
||||
|
||||
qemu_co_mutex_lock(&bs->reqs_lock);
|
||||
bs->active_flush_req = false;
|
||||
/* Return value is ignored - it's ok if wait queue is empty */
|
||||
qemu_co_queue_next(&bs->flush_queue);
|
||||
qemu_co_mutex_unlock(&bs->reqs_lock);
|
||||
|
||||
early_exit:
|
||||
bdrv_dec_in_flight(bs);
|
||||
@@ -2517,7 +2528,7 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
++bs->write_gen;
|
||||
atomic_inc(&bs->write_gen);
|
||||
bdrv_set_dirty(bs, req.offset >> BDRV_SECTOR_BITS,
|
||||
req.bytes >> BDRV_SECTOR_BITS);
|
||||
tracked_request_end(&req);
|
||||
@@ -2644,7 +2655,7 @@ void bdrv_io_plug(BlockDriverState *bs)
|
||||
bdrv_io_plug(child->bs);
|
||||
}
|
||||
|
||||
if (bs->io_plugged++ == 0) {
|
||||
if (atomic_fetch_inc(&bs->io_plugged) == 0) {
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (drv && drv->bdrv_io_plug) {
|
||||
drv->bdrv_io_plug(bs);
|
||||
@@ -2657,7 +2668,7 @@ void bdrv_io_unplug(BlockDriverState *bs)
|
||||
BdrvChild *child;
|
||||
|
||||
assert(bs->io_plugged);
|
||||
if (--bs->io_plugged == 0) {
|
||||
if (atomic_fetch_dec(&bs->io_plugged) == 1) {
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (drv && drv->bdrv_io_unplug) {
|
||||
drv->bdrv_io_unplug(bs);
|
||||
|
@@ -1732,6 +1732,10 @@ static QemuOptsList runtime_opts = {
|
||||
.name = "timeout",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
},
|
||||
{
|
||||
.name = "filename",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@@ -1747,12 +1751,27 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
char *initiator_name = NULL;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
const char *transport_name, *portal, *target;
|
||||
const char *transport_name, *portal, *target, *filename;
|
||||
#if LIBISCSI_API_VERSION >= (20160603)
|
||||
enum iscsi_transport_type transport;
|
||||
#endif
|
||||
int i, ret = 0, timeout = 0, lun;
|
||||
|
||||
/* If we are given a filename, parse the filename, with precedence given to
|
||||
* filename encoded options */
|
||||
filename = qdict_get_try_str(options, "filename");
|
||||
if (filename) {
|
||||
error_report("Warning: 'filename' option specified. "
|
||||
"This is an unsupported option, and may be deprecated "
|
||||
"in the future");
|
||||
iscsi_parse_filename(filename, options, &local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
error_propagate(errp, local_err);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
@@ -1967,6 +1986,7 @@ out:
|
||||
}
|
||||
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||
}
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@@ -342,6 +342,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
int max_io_sectors = MAX((s->buf_size >> BDRV_SECTOR_BITS) / MAX_IN_FLIGHT,
|
||||
MAX_IO_SECTORS);
|
||||
|
||||
bdrv_dirty_bitmap_lock(s->dirty_bitmap);
|
||||
sector_num = bdrv_dirty_iter_next(s->dbi);
|
||||
if (sector_num < 0) {
|
||||
bdrv_set_dirty_iter(s->dbi, 0);
|
||||
@@ -349,6 +350,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap));
|
||||
assert(sector_num >= 0);
|
||||
}
|
||||
bdrv_dirty_bitmap_unlock(s->dirty_bitmap);
|
||||
|
||||
first_chunk = sector_num / sectors_per_chunk;
|
||||
while (test_bit(first_chunk, s->in_flight_bitmap)) {
|
||||
@@ -360,12 +362,13 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
|
||||
/* Find the number of consective dirty chunks following the first dirty
|
||||
* one, and wait for in flight requests in them. */
|
||||
bdrv_dirty_bitmap_lock(s->dirty_bitmap);
|
||||
while (nb_chunks * sectors_per_chunk < (s->buf_size >> BDRV_SECTOR_BITS)) {
|
||||
int64_t next_dirty;
|
||||
int64_t next_sector = sector_num + nb_chunks * sectors_per_chunk;
|
||||
int64_t next_chunk = next_sector / sectors_per_chunk;
|
||||
if (next_sector >= end ||
|
||||
!bdrv_get_dirty(source, s->dirty_bitmap, next_sector)) {
|
||||
!bdrv_get_dirty_locked(source, s->dirty_bitmap, next_sector)) {
|
||||
break;
|
||||
}
|
||||
if (test_bit(next_chunk, s->in_flight_bitmap)) {
|
||||
@@ -386,8 +389,10 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
* calling bdrv_get_block_status_above could yield - if some blocks are
|
||||
* marked dirty in this window, we need to know.
|
||||
*/
|
||||
bdrv_reset_dirty_bitmap(s->dirty_bitmap, sector_num,
|
||||
nb_chunks * sectors_per_chunk);
|
||||
bdrv_reset_dirty_bitmap_locked(s->dirty_bitmap, sector_num,
|
||||
nb_chunks * sectors_per_chunk);
|
||||
bdrv_dirty_bitmap_unlock(s->dirty_bitmap);
|
||||
|
||||
bitmap_set(s->in_flight_bitmap, sector_num / sectors_per_chunk, nb_chunks);
|
||||
while (nb_chunks > 0 && sector_num < end) {
|
||||
int64_t ret;
|
||||
@@ -506,6 +511,8 @@ static void mirror_exit(BlockJob *job, void *opaque)
|
||||
BlockDriverState *mirror_top_bs = s->mirror_top_bs;
|
||||
Error *local_err = NULL;
|
||||
|
||||
bdrv_release_dirty_bitmap(src, s->dirty_bitmap);
|
||||
|
||||
/* Make sure that the source BDS doesn't go away before we called
|
||||
* block_job_completed(). */
|
||||
bdrv_ref(src);
|
||||
@@ -904,7 +911,6 @@ immediate_exit:
|
||||
g_free(s->cow_bitmap);
|
||||
g_free(s->in_flight_bitmap);
|
||||
bdrv_dirty_iter_free(s->dbi);
|
||||
bdrv_release_dirty_bitmap(bs, s->dirty_bitmap);
|
||||
|
||||
data = g_malloc(sizeof(*data));
|
||||
data->ret = ret;
|
||||
|
@@ -144,8 +144,8 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
qio_channel_set_cork(s->ioc, true);
|
||||
rc = nbd_send_request(s->ioc, request);
|
||||
if (rc >= 0) {
|
||||
ret = nbd_wr_syncv(s->ioc, qiov->iov, qiov->niov, request->len,
|
||||
false, NULL);
|
||||
ret = nbd_rwv(s->ioc, qiov->iov, qiov->niov, request->len, false,
|
||||
NULL);
|
||||
if (ret != request->len) {
|
||||
rc = -EIO;
|
||||
}
|
||||
@@ -173,8 +173,8 @@ static void nbd_co_receive_reply(NBDClientSession *s,
|
||||
reply->error = EIO;
|
||||
} else {
|
||||
if (qiov && reply->error == 0) {
|
||||
ret = nbd_wr_syncv(s->ioc, qiov->iov, qiov->niov, request->len,
|
||||
true, NULL);
|
||||
ret = nbd_rwv(s->ioc, qiov->iov, qiov->niov, request->len, true,
|
||||
NULL);
|
||||
if (ret != request->len) {
|
||||
reply->error = EIO;
|
||||
}
|
||||
|
@@ -37,7 +37,6 @@
|
||||
#include "qapi/qobject-output-visitor.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
|
@@ -36,7 +36,6 @@
|
||||
#include "qemu/cutils.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
@@ -730,7 +729,9 @@ nfs_get_allocated_file_size_cb(int ret, struct nfs_context *nfs, void *data,
|
||||
if (task->ret < 0) {
|
||||
error_report("NFS Error: %s", nfs_get_error(nfs));
|
||||
}
|
||||
task->complete = 1;
|
||||
|
||||
/* Set task->complete before reading bs->wakeup. */
|
||||
atomic_mb_set(&task->complete, 1);
|
||||
bdrv_wakeup(task->bs);
|
||||
}
|
||||
|
||||
|
15
block/qapi.c
15
block/qapi.c
@@ -441,7 +441,7 @@ static BlockStats *bdrv_query_bds_stats(const BlockDriverState *bs,
|
||||
s->node_name = g_strdup(bdrv_get_node_name(bs));
|
||||
}
|
||||
|
||||
s->stats->wr_highest_offset = bs->wr_highest_offset;
|
||||
s->stats->wr_highest_offset = stat64_get(&bs->wr_highest_offset);
|
||||
|
||||
if (bs->file) {
|
||||
s->has_parent = true;
|
||||
@@ -595,9 +595,11 @@ static void dump_qobject(fprintf_function func_fprintf, void *f,
|
||||
int comp_indent, QObject *obj)
|
||||
{
|
||||
switch (qobject_type(obj)) {
|
||||
case QTYPE_QINT: {
|
||||
QInt *value = qobject_to_qint(obj);
|
||||
func_fprintf(f, "%" PRId64, qint_get_int(value));
|
||||
case QTYPE_QNUM: {
|
||||
QNum *value = qobject_to_qnum(obj);
|
||||
char *tmp = qnum_to_string(value);
|
||||
func_fprintf(f, "%s", tmp);
|
||||
g_free(tmp);
|
||||
break;
|
||||
}
|
||||
case QTYPE_QSTRING: {
|
||||
@@ -615,11 +617,6 @@ static void dump_qobject(fprintf_function func_fprintf, void *f,
|
||||
dump_qlist(func_fprintf, f, comp_indent, value);
|
||||
break;
|
||||
}
|
||||
case QTYPE_QFLOAT: {
|
||||
QFloat *value = qobject_to_qfloat(obj);
|
||||
func_fprintf(f, "%g", qfloat_get_double(value));
|
||||
break;
|
||||
}
|
||||
case QTYPE_QBOOL: {
|
||||
QBool *value = qobject_to_qbool(obj);
|
||||
func_fprintf(f, "%s", qbool_get_bool(value) ? "true" : "false");
|
||||
|
@@ -19,7 +19,6 @@
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
|
22
block/rbd.c
22
block/rbd.c
@@ -340,6 +340,10 @@ static QemuOptsList runtime_opts = {
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Legacy rados key/value option parameters",
|
||||
},
|
||||
{
|
||||
.name = "filename",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@@ -541,12 +545,27 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
{
|
||||
BDRVRBDState *s = bs->opaque;
|
||||
const char *pool, *snap, *conf, *user, *image_name, *keypairs;
|
||||
const char *secretid;
|
||||
const char *secretid, *filename;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
char *mon_host = NULL;
|
||||
int r;
|
||||
|
||||
/* If we are given a filename, parse the filename, with precedence given to
|
||||
* filename encoded options */
|
||||
filename = qdict_get_try_str(options, "filename");
|
||||
if (filename) {
|
||||
error_report("Warning: 'filename' option specified. "
|
||||
"This is an unsupported option, and may be deprecated "
|
||||
"in the future");
|
||||
qemu_rbd_parse_filename(filename, options, &local_err);
|
||||
if (local_err) {
|
||||
r = -EINVAL;
|
||||
error_propagate(errp, local_err);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
@@ -665,6 +684,7 @@ failed_shutdown:
|
||||
failed_opts:
|
||||
qemu_opts_del(opts);
|
||||
g_free(mon_host);
|
||||
exit:
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@@ -16,7 +16,6 @@
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qemu/uri.h"
|
||||
#include "qemu/error-report.h"
|
||||
@@ -698,7 +697,8 @@ out:
|
||||
|
||||
srco->co = NULL;
|
||||
srco->ret = ret;
|
||||
srco->finished = true;
|
||||
/* Set srco->finished before reading bs->wakeup. */
|
||||
atomic_mb_set(&srco->finished, true);
|
||||
if (srco->bs) {
|
||||
bdrv_wakeup(srco->bs);
|
||||
}
|
||||
|
@@ -34,7 +34,6 @@
|
||||
#include "qemu/sockets.h"
|
||||
#include "qemu/uri.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qapi/qobject-output-visitor.h"
|
||||
|
@@ -240,7 +240,7 @@ static bool throttle_group_schedule_timer(BlockBackend *blk, bool is_write)
|
||||
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
||||
bool must_wait;
|
||||
|
||||
if (blkp->io_limits_disabled) {
|
||||
if (atomic_read(&blkp->io_limits_disabled)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -260,6 +260,25 @@ static bool throttle_group_schedule_timer(BlockBackend *blk, bool is_write)
|
||||
return must_wait;
|
||||
}
|
||||
|
||||
/* Start the next pending I/O request for a BlockBackend. Return whether
|
||||
* any request was actually pending.
|
||||
*
|
||||
* @blk: the current BlockBackend
|
||||
* @is_write: the type of operation (read/write)
|
||||
*/
|
||||
static bool coroutine_fn throttle_group_co_restart_queue(BlockBackend *blk,
|
||||
bool is_write)
|
||||
{
|
||||
BlockBackendPublic *blkp = blk_get_public(blk);
|
||||
bool ret;
|
||||
|
||||
qemu_co_mutex_lock(&blkp->throttled_reqs_lock);
|
||||
ret = qemu_co_queue_next(&blkp->throttled_reqs[is_write]);
|
||||
qemu_co_mutex_unlock(&blkp->throttled_reqs_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Look for the next pending I/O request and schedule it.
|
||||
*
|
||||
* This assumes that tg->lock is held.
|
||||
@@ -287,12 +306,12 @@ static void schedule_next_request(BlockBackend *blk, bool is_write)
|
||||
if (!must_wait) {
|
||||
/* Give preference to requests from the current blk */
|
||||
if (qemu_in_coroutine() &&
|
||||
qemu_co_queue_next(&blkp->throttled_reqs[is_write])) {
|
||||
throttle_group_co_restart_queue(blk, is_write)) {
|
||||
token = blk;
|
||||
} else {
|
||||
ThrottleTimers *tt = &blk_get_public(token)->throttle_timers;
|
||||
int64_t now = qemu_clock_get_ns(tt->clock_type);
|
||||
timer_mod(tt->timers[is_write], now + 1);
|
||||
timer_mod(tt->timers[is_write], now);
|
||||
tg->any_timer_armed[is_write] = true;
|
||||
}
|
||||
tg->tokens[is_write] = token;
|
||||
@@ -326,7 +345,10 @@ void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
|
||||
if (must_wait || blkp->pending_reqs[is_write]) {
|
||||
blkp->pending_reqs[is_write]++;
|
||||
qemu_mutex_unlock(&tg->lock);
|
||||
qemu_co_queue_wait(&blkp->throttled_reqs[is_write], NULL);
|
||||
qemu_co_mutex_lock(&blkp->throttled_reqs_lock);
|
||||
qemu_co_queue_wait(&blkp->throttled_reqs[is_write],
|
||||
&blkp->throttled_reqs_lock);
|
||||
qemu_co_mutex_unlock(&blkp->throttled_reqs_lock);
|
||||
qemu_mutex_lock(&tg->lock);
|
||||
blkp->pending_reqs[is_write]--;
|
||||
}
|
||||
@@ -340,15 +362,50 @@ void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
|
||||
qemu_mutex_unlock(&tg->lock);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
BlockBackend *blk;
|
||||
bool is_write;
|
||||
} RestartData;
|
||||
|
||||
static void coroutine_fn throttle_group_restart_queue_entry(void *opaque)
|
||||
{
|
||||
RestartData *data = opaque;
|
||||
BlockBackend *blk = data->blk;
|
||||
bool is_write = data->is_write;
|
||||
BlockBackendPublic *blkp = blk_get_public(blk);
|
||||
ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
|
||||
bool empty_queue;
|
||||
|
||||
empty_queue = !throttle_group_co_restart_queue(blk, is_write);
|
||||
|
||||
/* If the request queue was empty then we have to take care of
|
||||
* scheduling the next one */
|
||||
if (empty_queue) {
|
||||
qemu_mutex_lock(&tg->lock);
|
||||
schedule_next_request(blk, is_write);
|
||||
qemu_mutex_unlock(&tg->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void throttle_group_restart_queue(BlockBackend *blk, bool is_write)
|
||||
{
|
||||
Coroutine *co;
|
||||
RestartData rd = {
|
||||
.blk = blk,
|
||||
.is_write = is_write
|
||||
};
|
||||
|
||||
co = qemu_coroutine_create(throttle_group_restart_queue_entry, &rd);
|
||||
aio_co_enter(blk_get_aio_context(blk), co);
|
||||
}
|
||||
|
||||
void throttle_group_restart_blk(BlockBackend *blk)
|
||||
{
|
||||
BlockBackendPublic *blkp = blk_get_public(blk);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
while (qemu_co_enter_next(&blkp->throttled_reqs[i])) {
|
||||
;
|
||||
}
|
||||
if (blkp->throttle_state) {
|
||||
throttle_group_restart_queue(blk, 0);
|
||||
throttle_group_restart_queue(blk, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,8 +433,7 @@ void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg)
|
||||
throttle_config(ts, tt, cfg);
|
||||
qemu_mutex_unlock(&tg->lock);
|
||||
|
||||
qemu_co_enter_next(&blkp->throttled_reqs[0]);
|
||||
qemu_co_enter_next(&blkp->throttled_reqs[1]);
|
||||
throttle_group_restart_blk(blk);
|
||||
}
|
||||
|
||||
/* Get the throttle configuration from a particular group. Similar to
|
||||
@@ -408,7 +464,6 @@ static void timer_cb(BlockBackend *blk, bool is_write)
|
||||
BlockBackendPublic *blkp = blk_get_public(blk);
|
||||
ThrottleState *ts = blkp->throttle_state;
|
||||
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
||||
bool empty_queue;
|
||||
|
||||
/* The timer has just been fired, so we can update the flag */
|
||||
qemu_mutex_lock(&tg->lock);
|
||||
@@ -416,17 +471,7 @@ static void timer_cb(BlockBackend *blk, bool is_write)
|
||||
qemu_mutex_unlock(&tg->lock);
|
||||
|
||||
/* Run the request that was waiting for this timer */
|
||||
aio_context_acquire(blk_get_aio_context(blk));
|
||||
empty_queue = !qemu_co_enter_next(&blkp->throttled_reqs[is_write]);
|
||||
aio_context_release(blk_get_aio_context(blk));
|
||||
|
||||
/* If the request queue was empty then we have to take care of
|
||||
* scheduling the next one */
|
||||
if (empty_queue) {
|
||||
qemu_mutex_lock(&tg->lock);
|
||||
schedule_next_request(blk, is_write);
|
||||
qemu_mutex_unlock(&tg->lock);
|
||||
}
|
||||
throttle_group_restart_queue(blk, is_write);
|
||||
}
|
||||
|
||||
static void read_timer_cb(void *opaque)
|
||||
|
@@ -29,7 +29,6 @@
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "migration/blocker.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
@@ -27,6 +27,10 @@ typedef struct NBDServerData {
|
||||
|
||||
static NBDServerData *nbd_server;
|
||||
|
||||
static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
|
||||
{
|
||||
nbd_client_put(client);
|
||||
}
|
||||
|
||||
static gboolean nbd_accept(QIOChannel *ioc, GIOCondition condition,
|
||||
gpointer opaque)
|
||||
@@ -46,7 +50,7 @@ static gboolean nbd_accept(QIOChannel *ioc, GIOCondition condition,
|
||||
qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
|
||||
nbd_client_new(NULL, cioc,
|
||||
nbd_server->tlscreds, NULL,
|
||||
nbd_client_put);
|
||||
nbd_blockdev_client_closed);
|
||||
object_unref(OBJECT(cioc));
|
||||
return TRUE;
|
||||
}
|
||||
|
53
blockdev.c
53
blockdev.c
@@ -334,8 +334,9 @@ static bool parse_stats_intervals(BlockAcctStats *stats, QList *intervals,
|
||||
break;
|
||||
}
|
||||
|
||||
case QTYPE_QINT: {
|
||||
int64_t length = qint_get_int(qobject_to_qint(entry->value));
|
||||
case QTYPE_QNUM: {
|
||||
int64_t length = qnum_get_int(qobject_to_qnum(entry->value));
|
||||
|
||||
if (length > 0 && length <= UINT_MAX) {
|
||||
block_acct_add_interval(stats, (unsigned) length);
|
||||
} else {
|
||||
@@ -595,7 +596,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||
autostart = 0;
|
||||
}
|
||||
|
||||
block_acct_init(blk_get_stats(blk), account_invalid, account_failed);
|
||||
block_acct_setup(blk_get_stats(blk), account_invalid, account_failed);
|
||||
|
||||
if (!parse_stats_intervals(blk_get_stats(blk), interval_list, errp)) {
|
||||
blk_unref(blk);
|
||||
@@ -1362,12 +1363,10 @@ out_aio_context:
|
||||
static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node,
|
||||
const char *name,
|
||||
BlockDriverState **pbs,
|
||||
AioContext **paio,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
AioContext *aio_context;
|
||||
|
||||
if (!node) {
|
||||
error_setg(errp, "Node cannot be NULL");
|
||||
@@ -1383,29 +1382,17 @@ static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
bitmap = bdrv_find_dirty_bitmap(bs, name);
|
||||
if (!bitmap) {
|
||||
error_setg(errp, "Dirty bitmap '%s' not found", name);
|
||||
goto fail;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pbs) {
|
||||
*pbs = bs;
|
||||
}
|
||||
if (paio) {
|
||||
*paio = aio_context;
|
||||
} else {
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
|
||||
fail:
|
||||
aio_context_release(aio_context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* New and old BlockDriverState structs for atomic group operations */
|
||||
@@ -1791,7 +1778,7 @@ static void external_snapshot_commit(BlkActionState *common)
|
||||
/* We don't need (or want) to use the transactional
|
||||
* bdrv_reopen_multiple() across all the entries at once, because we
|
||||
* don't want to abort all of them if one of them fails the reopen */
|
||||
if (!state->old_bs->copy_on_read) {
|
||||
if (!atomic_read(&state->old_bs->copy_on_read)) {
|
||||
bdrv_reopen(state->old_bs, state->old_bs->open_flags & ~BDRV_O_RDWR,
|
||||
NULL);
|
||||
}
|
||||
@@ -2025,7 +2012,6 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
|
||||
state->bitmap = block_dirty_bitmap_lookup(action->node,
|
||||
action->name,
|
||||
&state->bs,
|
||||
&state->aio_context,
|
||||
errp);
|
||||
if (!state->bitmap) {
|
||||
return;
|
||||
@@ -2733,7 +2719,6 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
|
||||
bool has_granularity, uint32_t granularity,
|
||||
Error **errp)
|
||||
{
|
||||
AioContext *aio_context;
|
||||
BlockDriverState *bs;
|
||||
|
||||
if (!name || name[0] == '\0') {
|
||||
@@ -2746,14 +2731,11 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
if (has_granularity) {
|
||||
if (granularity < 512 || !is_power_of_2(granularity)) {
|
||||
error_setg(errp, "Granularity must be power of 2 "
|
||||
"and at least 512");
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* Default to cluster size, if available: */
|
||||
@@ -2761,19 +2743,15 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
|
||||
}
|
||||
|
||||
bdrv_create_dirty_bitmap(bs, granularity, name, errp);
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
AioContext *aio_context;
|
||||
BlockDriverState *bs;
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
|
||||
bitmap = block_dirty_bitmap_lookup(node, name, &bs, &aio_context, errp);
|
||||
bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
|
||||
if (!bitmap || !bs) {
|
||||
return;
|
||||
}
|
||||
@@ -2782,13 +2760,10 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
|
||||
error_setg(errp,
|
||||
"Bitmap '%s' is currently frozen and cannot be removed",
|
||||
name);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
bdrv_dirty_bitmap_make_anon(bitmap);
|
||||
bdrv_release_dirty_bitmap(bs, bitmap);
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2798,11 +2773,10 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
|
||||
void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
AioContext *aio_context;
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
BlockDriverState *bs;
|
||||
|
||||
bitmap = block_dirty_bitmap_lookup(node, name, &bs, &aio_context, errp);
|
||||
bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
|
||||
if (!bitmap || !bs) {
|
||||
return;
|
||||
}
|
||||
@@ -2811,18 +2785,15 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
|
||||
error_setg(errp,
|
||||
"Bitmap '%s' is currently frozen and cannot be modified",
|
||||
name);
|
||||
goto out;
|
||||
return;
|
||||
} else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
|
||||
error_setg(errp,
|
||||
"Bitmap '%s' is currently disabled and cannot be cleared",
|
||||
name);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_clear_dirty_bitmap(bitmap, NULL);
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
void hmp_drive_del(Monitor *mon, const QDict *qdict)
|
||||
|
4
configure
vendored
4
configure
vendored
@@ -407,7 +407,7 @@ QEMU_CFLAGS="-fno-strict-aliasing -fno-common -fwrapv $QEMU_CFLAGS"
|
||||
QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
|
||||
QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
|
||||
QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
|
||||
QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/include"
|
||||
QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/accel/tcg -I\$(SRC_PATH)/include"
|
||||
if test "$debug_info" = "yes"; then
|
||||
CFLAGS="-g $CFLAGS"
|
||||
LDFLAGS="-g $LDFLAGS"
|
||||
@@ -6374,7 +6374,7 @@ fi
|
||||
|
||||
# build tree in object directory in case the source is not in the current directory
|
||||
DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests"
|
||||
DIRS="$DIRS docs fsdev"
|
||||
DIRS="$DIRS docs docs/interop fsdev"
|
||||
DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
|
||||
DIRS="$DIRS roms/seabios roms/vgabios"
|
||||
DIRS="$DIRS qapi-generated"
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/poll.h>
|
||||
#include <linux/vhost.h>
|
||||
#include "standard-headers/linux/virtio_ring.h"
|
||||
|
||||
@@ -192,11 +193,11 @@ typedef struct VuVirtq {
|
||||
} VuVirtq;
|
||||
|
||||
enum VuWatchCondtion {
|
||||
VU_WATCH_IN = 1 << 0,
|
||||
VU_WATCH_OUT = 1 << 1,
|
||||
VU_WATCH_PRI = 1 << 2,
|
||||
VU_WATCH_ERR = 1 << 3,
|
||||
VU_WATCH_HUP = 1 << 4,
|
||||
VU_WATCH_IN = POLLIN,
|
||||
VU_WATCH_OUT = POLLOUT,
|
||||
VU_WATCH_PRI = POLLPRI,
|
||||
VU_WATCH_ERR = POLLERR,
|
||||
VU_WATCH_HUP = POLLHUP,
|
||||
};
|
||||
|
||||
typedef void (*vu_panic_cb) (VuDev *dev, const char *err);
|
||||
|
1
contrib/vhost-user-scsi/Makefile.objs
Normal file
1
contrib/vhost-user-scsi/Makefile.objs
Normal file
@@ -0,0 +1 @@
|
||||
vhost-user-scsi-obj-y = vhost-user-scsi.o
|
886
contrib/vhost-user-scsi/vhost-user-scsi.c
Normal file
886
contrib/vhost-user-scsi/vhost-user-scsi.c
Normal file
@@ -0,0 +1,886 @@
|
||||
/*
|
||||
* vhost-user-scsi sample application
|
||||
*
|
||||
* Copyright (c) 2016 Nutanix Inc. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Felipe Franciosi <felipe@nutanix.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 only.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "contrib/libvhost-user/libvhost-user.h"
|
||||
#include "hw/virtio/virtio-scsi.h"
|
||||
#include "iscsi/iscsi.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/* Small compat shim from glib 2.32 */
|
||||
#ifndef G_SOURCE_CONTINUE
|
||||
#define G_SOURCE_CONTINUE TRUE
|
||||
#endif
|
||||
#ifndef G_SOURCE_REMOVE
|
||||
#define G_SOURCE_REMOVE FALSE
|
||||
#endif
|
||||
|
||||
/* #define VUS_DEBUG 1 */
|
||||
|
||||
/** Log helpers **/
|
||||
|
||||
#define PPRE \
|
||||
struct timespec ts; \
|
||||
char timebuf[64]; \
|
||||
struct tm tm; \
|
||||
(void)clock_gettime(CLOCK_REALTIME, &ts); \
|
||||
(void)strftime(timebuf, 64, "%Y%m%d %T", gmtime_r(&ts.tv_sec, &tm))
|
||||
|
||||
#define PEXT(lvl, msg, ...) do { \
|
||||
PPRE; \
|
||||
fprintf(stderr, "%s.%06ld " lvl ": %s:%s():%d: " msg "\n", \
|
||||
timebuf, ts.tv_nsec / 1000, \
|
||||
__FILE__, __func__, __LINE__, ## __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define PNOR(lvl, msg, ...) do { \
|
||||
PPRE; \
|
||||
fprintf(stderr, "%s.%06ld " lvl ": " msg "\n", \
|
||||
timebuf, ts.tv_nsec / 1000, ## __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#ifdef VUS_DEBUG
|
||||
#define PDBG(msg, ...) PEXT("DBG", msg, ## __VA_ARGS__)
|
||||
#define PERR(msg, ...) PEXT("ERR", msg, ## __VA_ARGS__)
|
||||
#define PLOG(msg, ...) PEXT("LOG", msg, ## __VA_ARGS__)
|
||||
#else
|
||||
#define PDBG(msg, ...) { }
|
||||
#define PERR(msg, ...) PNOR("ERR", msg, ## __VA_ARGS__)
|
||||
#define PLOG(msg, ...) PNOR("LOG", msg, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/** vhost-user-scsi specific definitions **/
|
||||
|
||||
/* Only 1 LUN and device supported today */
|
||||
#define VUS_MAX_LUNS 1
|
||||
#define VUS_MAX_DEVS 1
|
||||
|
||||
#define VUS_ISCSI_INITIATOR "iqn.2016-11.com.nutanix:vhost-user-scsi"
|
||||
|
||||
typedef struct iscsi_lun {
|
||||
struct iscsi_context *iscsi_ctx;
|
||||
int iscsi_lun;
|
||||
} iscsi_lun_t;
|
||||
|
||||
typedef struct vhost_scsi_dev {
|
||||
VuDev vu_dev;
|
||||
int server_sock;
|
||||
GMainLoop *loop;
|
||||
GTree *fdmap; /* fd -> gsource context id */
|
||||
iscsi_lun_t luns[VUS_MAX_LUNS];
|
||||
} vhost_scsi_dev_t;
|
||||
|
||||
static vhost_scsi_dev_t *vhost_scsi_devs[VUS_MAX_DEVS];
|
||||
|
||||
/** glib event loop integration for libvhost-user and misc callbacks **/
|
||||
|
||||
QEMU_BUILD_BUG_ON((int)G_IO_IN != (int)VU_WATCH_IN);
|
||||
QEMU_BUILD_BUG_ON((int)G_IO_OUT != (int)VU_WATCH_OUT);
|
||||
QEMU_BUILD_BUG_ON((int)G_IO_PRI != (int)VU_WATCH_PRI);
|
||||
QEMU_BUILD_BUG_ON((int)G_IO_ERR != (int)VU_WATCH_ERR);
|
||||
QEMU_BUILD_BUG_ON((int)G_IO_HUP != (int)VU_WATCH_HUP);
|
||||
|
||||
typedef struct vus_gsrc {
|
||||
GSource parent;
|
||||
vhost_scsi_dev_t *vdev_scsi;
|
||||
GPollFD gfd;
|
||||
vu_watch_cb vu_cb;
|
||||
} vus_gsrc_t;
|
||||
|
||||
static gint vus_fdmap_compare(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
return (b > a) - (b < a);
|
||||
}
|
||||
|
||||
static gboolean vus_gsrc_prepare(GSource *src, gint *timeout)
|
||||
{
|
||||
assert(timeout);
|
||||
|
||||
*timeout = -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean vus_gsrc_check(GSource *src)
|
||||
{
|
||||
vus_gsrc_t *vus_src = (vus_gsrc_t *)src;
|
||||
|
||||
assert(vus_src);
|
||||
|
||||
return vus_src->gfd.revents & vus_src->gfd.events;
|
||||
}
|
||||
|
||||
static gboolean vus_gsrc_dispatch(GSource *src, GSourceFunc cb, gpointer data)
|
||||
{
|
||||
vhost_scsi_dev_t *vdev_scsi;
|
||||
vus_gsrc_t *vus_src = (vus_gsrc_t *)src;
|
||||
|
||||
assert(vus_src);
|
||||
assert(!(vus_src->vu_cb && cb));
|
||||
|
||||
vdev_scsi = vus_src->vdev_scsi;
|
||||
|
||||
assert(vdev_scsi);
|
||||
|
||||
if (cb) {
|
||||
return cb(data);
|
||||
}
|
||||
if (vus_src->vu_cb) {
|
||||
vus_src->vu_cb(&vdev_scsi->vu_dev, vus_src->gfd.revents, data);
|
||||
}
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static GSourceFuncs vus_gsrc_funcs = {
|
||||
vus_gsrc_prepare,
|
||||
vus_gsrc_check,
|
||||
vus_gsrc_dispatch,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int vus_gsrc_new(vhost_scsi_dev_t *vdev_scsi, int fd, GIOCondition cond,
|
||||
vu_watch_cb vu_cb, GSourceFunc gsrc_cb, gpointer data)
|
||||
{
|
||||
GSource *vus_gsrc;
|
||||
vus_gsrc_t *vus_src;
|
||||
guint id;
|
||||
|
||||
assert(vdev_scsi);
|
||||
assert(fd >= 0);
|
||||
assert(vu_cb || gsrc_cb);
|
||||
assert(!(vu_cb && gsrc_cb));
|
||||
|
||||
vus_gsrc = g_source_new(&vus_gsrc_funcs, sizeof(vus_gsrc_t));
|
||||
if (!vus_gsrc) {
|
||||
PERR("Error creating GSource for new watch");
|
||||
return -1;
|
||||
}
|
||||
vus_src = (vus_gsrc_t *)vus_gsrc;
|
||||
|
||||
vus_src->vdev_scsi = vdev_scsi;
|
||||
vus_src->gfd.fd = fd;
|
||||
vus_src->gfd.events = cond;
|
||||
vus_src->vu_cb = vu_cb;
|
||||
|
||||
g_source_add_poll(vus_gsrc, &vus_src->gfd);
|
||||
g_source_set_callback(vus_gsrc, gsrc_cb, data, NULL);
|
||||
id = g_source_attach(vus_gsrc, NULL);
|
||||
assert(id);
|
||||
g_source_unref(vus_gsrc);
|
||||
|
||||
g_tree_insert(vdev_scsi->fdmap, (gpointer)(uintptr_t)fd,
|
||||
(gpointer)(uintptr_t)id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* from libiscsi's scsi-lowlevel.h **
|
||||
*
|
||||
* nb. We can't directly include scsi-lowlevel.h due to a namespace conflict:
|
||||
* QEMU's scsi.h also defines "SCSI_XFER_NONE".
|
||||
*/
|
||||
|
||||
#define SCSI_CDB_MAX_SIZE 16
|
||||
|
||||
struct scsi_iovector {
|
||||
struct scsi_iovec *iov;
|
||||
int niov;
|
||||
int nalloc;
|
||||
size_t offset;
|
||||
int consumed;
|
||||
};
|
||||
|
||||
struct scsi_allocated_memory {
|
||||
struct scsi_allocated_memory *next;
|
||||
char buf[0];
|
||||
};
|
||||
|
||||
struct scsi_data {
|
||||
int size;
|
||||
unsigned char *data;
|
||||
};
|
||||
|
||||
enum scsi_sense_key {
|
||||
SCSI_SENSE_NO_SENSE = 0x00,
|
||||
SCSI_SENSE_RECOVERED_ERROR = 0x01,
|
||||
SCSI_SENSE_NOT_READY = 0x02,
|
||||
SCSI_SENSE_MEDIUM_ERROR = 0x03,
|
||||
SCSI_SENSE_HARDWARE_ERROR = 0x04,
|
||||
SCSI_SENSE_ILLEGAL_REQUEST = 0x05,
|
||||
SCSI_SENSE_UNIT_ATTENTION = 0x06,
|
||||
SCSI_SENSE_DATA_PROTECTION = 0x07,
|
||||
SCSI_SENSE_BLANK_CHECK = 0x08,
|
||||
SCSI_SENSE_VENDOR_SPECIFIC = 0x09,
|
||||
SCSI_SENSE_COPY_ABORTED = 0x0a,
|
||||
SCSI_SENSE_COMMAND_ABORTED = 0x0b,
|
||||
SCSI_SENSE_OBSOLETE_ERROR_CODE = 0x0c,
|
||||
SCSI_SENSE_OVERFLOW_COMMAND = 0x0d,
|
||||
SCSI_SENSE_MISCOMPARE = 0x0e
|
||||
};
|
||||
|
||||
struct scsi_sense {
|
||||
unsigned char error_type;
|
||||
enum scsi_sense_key key;
|
||||
int ascq;
|
||||
unsigned sense_specific:1;
|
||||
unsigned ill_param_in_cdb:1;
|
||||
unsigned bit_pointer_valid:1;
|
||||
unsigned char bit_pointer;
|
||||
uint16_t field_pointer;
|
||||
};
|
||||
|
||||
enum scsi_residual {
|
||||
SCSI_RESIDUAL_NO_RESIDUAL = 0,
|
||||
SCSI_RESIDUAL_UNDERFLOW,
|
||||
SCSI_RESIDUAL_OVERFLOW
|
||||
};
|
||||
|
||||
struct scsi_task {
|
||||
int status;
|
||||
int cdb_size;
|
||||
int xfer_dir;
|
||||
int expxferlen;
|
||||
unsigned char cdb[SCSI_CDB_MAX_SIZE];
|
||||
enum scsi_residual residual_status;
|
||||
size_t residual;
|
||||
struct scsi_sense sense;
|
||||
struct scsi_data datain;
|
||||
struct scsi_allocated_memory *mem;
|
||||
void *ptr;
|
||||
|
||||
uint32_t itt;
|
||||
uint32_t cmdsn;
|
||||
uint32_t lun;
|
||||
|
||||
struct scsi_iovector iovector_in;
|
||||
struct scsi_iovector iovector_out;
|
||||
};
|
||||
|
||||
/** libiscsi integration **/
|
||||
|
||||
static int iscsi_add_lun(iscsi_lun_t *lun, char *iscsi_uri)
|
||||
{
|
||||
struct iscsi_url *iscsi_url;
|
||||
struct iscsi_context *iscsi_ctx;
|
||||
int ret = 0;
|
||||
|
||||
assert(lun);
|
||||
assert(iscsi_uri);
|
||||
|
||||
iscsi_ctx = iscsi_create_context(VUS_ISCSI_INITIATOR);
|
||||
if (!iscsi_ctx) {
|
||||
PERR("Unable to create iSCSI context");
|
||||
return -1;
|
||||
}
|
||||
|
||||
iscsi_url = iscsi_parse_full_url(iscsi_ctx, iscsi_uri);
|
||||
if (!iscsi_url) {
|
||||
PERR("Unable to parse iSCSI URL: %s", iscsi_get_error(iscsi_ctx));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
iscsi_set_session_type(iscsi_ctx, ISCSI_SESSION_NORMAL);
|
||||
iscsi_set_header_digest(iscsi_ctx, ISCSI_HEADER_DIGEST_NONE_CRC32C);
|
||||
if (iscsi_full_connect_sync(iscsi_ctx, iscsi_url->portal, iscsi_url->lun)) {
|
||||
PERR("Unable to login to iSCSI portal: %s", iscsi_get_error(iscsi_ctx));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lun->iscsi_ctx = iscsi_ctx;
|
||||
lun->iscsi_lun = iscsi_url->lun;
|
||||
|
||||
PDBG("Context %p created for lun 0: %s", iscsi_ctx, iscsi_uri);
|
||||
|
||||
out:
|
||||
if (iscsi_url) {
|
||||
iscsi_destroy_url(iscsi_url);
|
||||
}
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
(void)iscsi_destroy_context(iscsi_ctx);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static struct scsi_task *scsi_task_new(int cdb_len, uint8_t *cdb, int dir,
|
||||
int xfer_len) {
|
||||
struct scsi_task *task;
|
||||
|
||||
assert(cdb_len > 0);
|
||||
assert(cdb);
|
||||
|
||||
task = calloc(1, sizeof(struct scsi_task));
|
||||
if (!task) {
|
||||
PERR("Error allocating task: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(task->cdb, cdb, cdb_len);
|
||||
task->cdb_size = cdb_len;
|
||||
task->xfer_dir = dir;
|
||||
task->expxferlen = xfer_len;
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
static int get_cdb_len(uint8_t *cdb)
|
||||
{
|
||||
assert(cdb);
|
||||
|
||||
switch (cdb[0] >> 5) {
|
||||
case 0: return 6;
|
||||
case 1: /* fall through */
|
||||
case 2: return 10;
|
||||
case 4: return 16;
|
||||
case 5: return 12;
|
||||
}
|
||||
PERR("Unable to determine cdb len (0x%02hhX)", cdb[0] >> 5);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int handle_cmd_sync(struct iscsi_context *ctx,
|
||||
VirtIOSCSICmdReq *req,
|
||||
struct iovec *out, unsigned int out_len,
|
||||
VirtIOSCSICmdResp *rsp,
|
||||
struct iovec *in, unsigned int in_len) {
|
||||
struct scsi_task *task;
|
||||
uint32_t dir;
|
||||
uint32_t len;
|
||||
int cdb_len;
|
||||
int i;
|
||||
|
||||
assert(ctx);
|
||||
assert(req);
|
||||
assert(rsp);
|
||||
|
||||
if (!(!req->lun[1] && req->lun[2] == 0x40 && !req->lun[3])) {
|
||||
/* Ignore anything different than target=0, lun=0 */
|
||||
PDBG("Ignoring unconnected lun (0x%hhX, 0x%hhX)",
|
||||
req->lun[1], req->lun[3]);
|
||||
rsp->status = SCSI_STATUS_CHECK_CONDITION;
|
||||
memset(rsp->sense, 0, sizeof(rsp->sense));
|
||||
rsp->sense_len = 18;
|
||||
rsp->sense[0] = 0x70;
|
||||
rsp->sense[2] = SCSI_SENSE_ILLEGAL_REQUEST;
|
||||
rsp->sense[7] = 10;
|
||||
rsp->sense[12] = 0x24;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cdb_len = get_cdb_len(req->cdb);
|
||||
if (cdb_len == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
if (!out_len && !in_len) {
|
||||
dir = SCSI_XFER_NONE;
|
||||
} else if (out_len) {
|
||||
dir = SCSI_XFER_TO_DEV;
|
||||
for (i = 0; i < out_len; i++) {
|
||||
len += out[i].iov_len;
|
||||
}
|
||||
} else {
|
||||
dir = SCSI_XFER_FROM_DEV;
|
||||
for (i = 0; i < in_len; i++) {
|
||||
len += in[i].iov_len;
|
||||
}
|
||||
}
|
||||
|
||||
task = scsi_task_new(cdb_len, req->cdb, dir, len);
|
||||
if (!task) {
|
||||
PERR("Unable to create iscsi task");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dir == SCSI_XFER_TO_DEV) {
|
||||
task->iovector_out.iov = (struct scsi_iovec *)out;
|
||||
task->iovector_out.niov = out_len;
|
||||
} else if (dir == SCSI_XFER_FROM_DEV) {
|
||||
task->iovector_in.iov = (struct scsi_iovec *)in;
|
||||
task->iovector_in.niov = in_len;
|
||||
}
|
||||
|
||||
PDBG("Sending iscsi cmd (cdb_len=%d, dir=%d, task=%p)",
|
||||
cdb_len, dir, task);
|
||||
if (!iscsi_scsi_command_sync(ctx, 0, task, NULL)) {
|
||||
PERR("Error serving SCSI command");
|
||||
free(task);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(rsp, 0, sizeof(*rsp));
|
||||
|
||||
rsp->status = task->status;
|
||||
rsp->resid = task->residual;
|
||||
|
||||
if (task->status == SCSI_STATUS_CHECK_CONDITION) {
|
||||
rsp->response = VIRTIO_SCSI_S_FAILURE;
|
||||
rsp->sense_len = task->datain.size - 2;
|
||||
memcpy(rsp->sense, &task->datain.data[2], rsp->sense_len);
|
||||
}
|
||||
|
||||
free(task);
|
||||
|
||||
PDBG("Filled in rsp: status=%hhX, resid=%u, response=%hhX, sense_len=%u",
|
||||
rsp->status, rsp->resid, rsp->response, rsp->sense_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** libvhost-user callbacks **/
|
||||
|
||||
static vhost_scsi_dev_t *vdev_scsi_find_by_vu(VuDev *vu_dev);
|
||||
|
||||
static void vus_panic_cb(VuDev *vu_dev, const char *buf)
|
||||
{
|
||||
vhost_scsi_dev_t *vdev_scsi;
|
||||
|
||||
assert(vu_dev);
|
||||
|
||||
vdev_scsi = vdev_scsi_find_by_vu(vu_dev);
|
||||
|
||||
if (buf) {
|
||||
PERR("vu_panic: %s", buf);
|
||||
}
|
||||
|
||||
if (vdev_scsi) {
|
||||
assert(vdev_scsi->loop);
|
||||
g_main_loop_quit(vdev_scsi->loop);
|
||||
}
|
||||
}
|
||||
|
||||
static void vus_add_watch_cb(VuDev *vu_dev, int fd, int vu_evt, vu_watch_cb cb,
|
||||
void *pvt) {
|
||||
vhost_scsi_dev_t *vdev_scsi;
|
||||
guint id;
|
||||
|
||||
assert(vu_dev);
|
||||
assert(fd >= 0);
|
||||
assert(cb);
|
||||
|
||||
vdev_scsi = vdev_scsi_find_by_vu(vu_dev);
|
||||
if (!vdev_scsi) {
|
||||
vus_panic_cb(vu_dev, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
id = (guint)(uintptr_t)g_tree_lookup(vdev_scsi->fdmap,
|
||||
(gpointer)(uintptr_t)fd);
|
||||
if (id) {
|
||||
GSource *vus_src = g_main_context_find_source_by_id(NULL, id);
|
||||
assert(vus_src);
|
||||
g_source_destroy(vus_src);
|
||||
(void)g_tree_remove(vdev_scsi->fdmap, (gpointer)(uintptr_t)fd);
|
||||
}
|
||||
|
||||
if (vus_gsrc_new(vdev_scsi, fd, vu_evt, cb, NULL, pvt)) {
|
||||
vus_panic_cb(vu_dev, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void vus_del_watch_cb(VuDev *vu_dev, int fd)
|
||||
{
|
||||
vhost_scsi_dev_t *vdev_scsi;
|
||||
guint id;
|
||||
|
||||
assert(vu_dev);
|
||||
assert(fd >= 0);
|
||||
|
||||
vdev_scsi = vdev_scsi_find_by_vu(vu_dev);
|
||||
if (!vdev_scsi) {
|
||||
vus_panic_cb(vu_dev, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
id = (guint)(uintptr_t)g_tree_lookup(vdev_scsi->fdmap,
|
||||
(gpointer)(uintptr_t)fd);
|
||||
if (id) {
|
||||
GSource *vus_src = g_main_context_find_source_by_id(NULL, id);
|
||||
assert(vus_src);
|
||||
g_source_destroy(vus_src);
|
||||
(void)g_tree_remove(vdev_scsi->fdmap, (gpointer)(uintptr_t)fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void vus_proc_ctl(VuDev *vu_dev, int idx)
|
||||
{
|
||||
/* Control VQ not implemented */
|
||||
}
|
||||
|
||||
static void vus_proc_evt(VuDev *vu_dev, int idx)
|
||||
{
|
||||
/* Event VQ not implemented */
|
||||
}
|
||||
|
||||
static void vus_proc_req(VuDev *vu_dev, int idx)
|
||||
{
|
||||
vhost_scsi_dev_t *vdev_scsi;
|
||||
VuVirtq *vq;
|
||||
|
||||
assert(vu_dev);
|
||||
|
||||
vdev_scsi = vdev_scsi_find_by_vu(vu_dev);
|
||||
if (!vdev_scsi) {
|
||||
vus_panic_cb(vu_dev, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((idx < 0) || (idx >= VHOST_MAX_NR_VIRTQUEUE)) {
|
||||
PERR("VQ Index out of range: %d", idx);
|
||||
vus_panic_cb(vu_dev, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
vq = vu_get_queue(vu_dev, idx);
|
||||
if (!vq) {
|
||||
PERR("Error fetching VQ (dev=%p, idx=%d)", vu_dev, idx);
|
||||
vus_panic_cb(vu_dev, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
PDBG("Got kicked on vq[%d]@%p", idx, vq);
|
||||
|
||||
while (1) {
|
||||
VuVirtqElement *elem;
|
||||
VirtIOSCSICmdReq *req;
|
||||
VirtIOSCSICmdResp *rsp;
|
||||
|
||||
elem = vu_queue_pop(vu_dev, vq, sizeof(VuVirtqElement));
|
||||
if (!elem) {
|
||||
PDBG("No more elements pending on vq[%d]@%p", idx, vq);
|
||||
break;
|
||||
}
|
||||
PDBG("Popped elem@%p", elem);
|
||||
|
||||
assert(!((elem->out_num > 1) && (elem->in_num > 1)));
|
||||
assert((elem->out_num > 0) && (elem->in_num > 0));
|
||||
|
||||
if (elem->out_sg[0].iov_len < sizeof(VirtIOSCSICmdReq)) {
|
||||
PERR("Invalid virtio-scsi req header");
|
||||
vus_panic_cb(vu_dev, NULL);
|
||||
break;
|
||||
}
|
||||
req = (VirtIOSCSICmdReq *)elem->out_sg[0].iov_base;
|
||||
|
||||
if (elem->in_sg[0].iov_len < sizeof(VirtIOSCSICmdResp)) {
|
||||
PERR("Invalid virtio-scsi rsp header");
|
||||
vus_panic_cb(vu_dev, NULL);
|
||||
break;
|
||||
}
|
||||
rsp = (VirtIOSCSICmdResp *)elem->in_sg[0].iov_base;
|
||||
|
||||
if (handle_cmd_sync(vdev_scsi->luns[0].iscsi_ctx,
|
||||
req, &elem->out_sg[1], elem->out_num - 1,
|
||||
rsp, &elem->in_sg[1], elem->in_num - 1) != 0) {
|
||||
vus_panic_cb(vu_dev, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
vu_queue_push(vu_dev, vq, elem, 0);
|
||||
vu_queue_notify(vu_dev, vq);
|
||||
|
||||
free(elem);
|
||||
}
|
||||
}
|
||||
|
||||
static void vus_queue_set_started(VuDev *vu_dev, int idx, bool started)
|
||||
{
|
||||
VuVirtq *vq;
|
||||
|
||||
assert(vu_dev);
|
||||
|
||||
if ((idx < 0) || (idx >= VHOST_MAX_NR_VIRTQUEUE)) {
|
||||
PERR("VQ Index out of range: %d", idx);
|
||||
vus_panic_cb(vu_dev, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
vq = vu_get_queue(vu_dev, idx);
|
||||
|
||||
switch (idx) {
|
||||
case 0:
|
||||
vu_set_queue_handler(vu_dev, vq, started ? vus_proc_ctl : NULL);
|
||||
break;
|
||||
case 1:
|
||||
vu_set_queue_handler(vu_dev, vq, started ? vus_proc_evt : NULL);
|
||||
break;
|
||||
default:
|
||||
vu_set_queue_handler(vu_dev, vq, started ? vus_proc_req : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static const VuDevIface vus_iface = {
|
||||
.queue_set_started = vus_queue_set_started,
|
||||
};
|
||||
|
||||
static gboolean vus_vhost_cb(gpointer data)
|
||||
{
|
||||
VuDev *vu_dev = (VuDev *)data;
|
||||
|
||||
assert(vu_dev);
|
||||
|
||||
if (!vu_dispatch(vu_dev) != 0) {
|
||||
PERR("Error processing vhost message");
|
||||
vus_panic_cb(vu_dev, NULL);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
/** misc helpers **/
|
||||
|
||||
static int unix_sock_new(char *unix_fn)
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_un un;
|
||||
size_t len;
|
||||
|
||||
assert(unix_fn);
|
||||
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock <= 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
un.sun_family = AF_UNIX;
|
||||
(void)snprintf(un.sun_path, sizeof(un.sun_path), "%s", unix_fn);
|
||||
len = sizeof(un.sun_family) + strlen(un.sun_path);
|
||||
|
||||
(void)unlink(unix_fn);
|
||||
if (bind(sock, (struct sockaddr *)&un, len) < 0) {
|
||||
perror("bind");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (listen(sock, 1) < 0) {
|
||||
perror("listen");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return sock;
|
||||
|
||||
fail:
|
||||
(void)close(sock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** vhost-user-scsi **/
|
||||
|
||||
static vhost_scsi_dev_t *vdev_scsi_find_by_vu(VuDev *vu_dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(vu_dev);
|
||||
|
||||
for (i = 0; i < VUS_MAX_DEVS; i++) {
|
||||
if (&vhost_scsi_devs[i]->vu_dev == vu_dev) {
|
||||
return vhost_scsi_devs[i];
|
||||
}
|
||||
}
|
||||
|
||||
PERR("Unknown VuDev %p", vu_dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void vdev_scsi_deinit(vhost_scsi_dev_t *vdev_scsi)
|
||||
{
|
||||
if (!vdev_scsi) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (vdev_scsi->server_sock >= 0) {
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t sslen = sizeof(ss);
|
||||
|
||||
if (getsockname(vdev_scsi->server_sock, (struct sockaddr *)&ss,
|
||||
&sslen) == 0) {
|
||||
struct sockaddr_un *su = (struct sockaddr_un *)&ss;
|
||||
(void)unlink(su->sun_path);
|
||||
}
|
||||
|
||||
(void)close(vdev_scsi->server_sock);
|
||||
vdev_scsi->server_sock = -1;
|
||||
}
|
||||
|
||||
if (vdev_scsi->loop) {
|
||||
g_main_loop_unref(vdev_scsi->loop);
|
||||
vdev_scsi->loop = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static vhost_scsi_dev_t *vdev_scsi_new(char *unix_fn)
|
||||
{
|
||||
vhost_scsi_dev_t *vdev_scsi = NULL;
|
||||
|
||||
assert(unix_fn);
|
||||
|
||||
vdev_scsi = calloc(1, sizeof(vhost_scsi_dev_t));
|
||||
if (!vdev_scsi) {
|
||||
PERR("calloc: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vdev_scsi->server_sock = unix_sock_new(unix_fn);
|
||||
if (vdev_scsi->server_sock < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
vdev_scsi->loop = g_main_loop_new(NULL, FALSE);
|
||||
if (!vdev_scsi->loop) {
|
||||
PERR("Error creating glib event loop");
|
||||
goto err;
|
||||
}
|
||||
|
||||
vdev_scsi->fdmap = g_tree_new(vus_fdmap_compare);
|
||||
if (!vdev_scsi->fdmap) {
|
||||
PERR("Error creating glib tree for fdmap");
|
||||
goto err;
|
||||
}
|
||||
|
||||
return vdev_scsi;
|
||||
|
||||
err:
|
||||
vdev_scsi_deinit(vdev_scsi);
|
||||
free(vdev_scsi);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int vdev_scsi_add_iscsi_lun(vhost_scsi_dev_t *vdev_scsi,
|
||||
char *iscsi_uri, uint32_t lun) {
|
||||
assert(vdev_scsi);
|
||||
assert(iscsi_uri);
|
||||
assert(lun < VUS_MAX_LUNS);
|
||||
|
||||
if (vdev_scsi->luns[lun].iscsi_ctx) {
|
||||
PERR("Lun %d already configured", lun);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (iscsi_add_lun(&vdev_scsi->luns[lun], iscsi_uri) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vdev_scsi_run(vhost_scsi_dev_t *vdev_scsi)
|
||||
{
|
||||
int cli_sock;
|
||||
int ret = 0;
|
||||
|
||||
assert(vdev_scsi);
|
||||
assert(vdev_scsi->server_sock >= 0);
|
||||
assert(vdev_scsi->loop);
|
||||
|
||||
cli_sock = accept(vdev_scsi->server_sock, (void *)0, (void *)0);
|
||||
if (cli_sock < 0) {
|
||||
perror("accept");
|
||||
return -1;
|
||||
}
|
||||
|
||||
vu_init(&vdev_scsi->vu_dev,
|
||||
cli_sock,
|
||||
vus_panic_cb,
|
||||
vus_add_watch_cb,
|
||||
vus_del_watch_cb,
|
||||
&vus_iface);
|
||||
|
||||
if (vus_gsrc_new(vdev_scsi, cli_sock, G_IO_IN, NULL, vus_vhost_cb,
|
||||
&vdev_scsi->vu_dev)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
g_main_loop_run(vdev_scsi->loop);
|
||||
|
||||
out:
|
||||
vu_deinit(&vdev_scsi->vu_dev);
|
||||
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
vhost_scsi_dev_t *vdev_scsi = NULL;
|
||||
char *unix_fn = NULL;
|
||||
char *iscsi_uri = NULL;
|
||||
int opt, err = EXIT_SUCCESS;
|
||||
|
||||
while ((opt = getopt(argc, argv, "u:i:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
goto help;
|
||||
case 'u':
|
||||
unix_fn = strdup(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
iscsi_uri = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
goto help;
|
||||
}
|
||||
}
|
||||
if (!unix_fn || !iscsi_uri) {
|
||||
goto help;
|
||||
}
|
||||
|
||||
vdev_scsi = vdev_scsi_new(unix_fn);
|
||||
if (!vdev_scsi) {
|
||||
goto err;
|
||||
}
|
||||
vhost_scsi_devs[0] = vdev_scsi;
|
||||
|
||||
if (vdev_scsi_add_iscsi_lun(vdev_scsi, iscsi_uri, 0) != 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (vdev_scsi_run(vdev_scsi) != 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
out:
|
||||
if (vdev_scsi) {
|
||||
vdev_scsi_deinit(vdev_scsi);
|
||||
free(vdev_scsi);
|
||||
}
|
||||
if (unix_fn) {
|
||||
free(unix_fn);
|
||||
}
|
||||
if (iscsi_uri) {
|
||||
free(iscsi_uri);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
||||
err:
|
||||
err = EXIT_FAILURE;
|
||||
goto out;
|
||||
|
||||
help:
|
||||
fprintf(stderr, "Usage: %s [ -u unix_sock_path -i iscsi_uri ] | [ -h ]\n",
|
||||
argv[0]);
|
||||
fprintf(stderr, " -u path to unix socket\n");
|
||||
fprintf(stderr, " -i iscsi uri for lun 0\n");
|
||||
fprintf(stderr, " -h print help and quit\n");
|
||||
|
||||
goto err;
|
||||
}
|
@@ -43,3 +43,4 @@ CONFIG_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_IVSHMEM=$(CONFIG_EVENTFD)
|
||||
CONFIG_ROCKER=y
|
||||
CONFIG_VHOST_USER_SCSI=$(CONFIG_LINUX)
|
||||
|
@@ -1,5 +1,6 @@
|
||||
CONFIG_PCI=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_VHOST_USER_SCSI=$(CONFIG_LINUX)
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_SCLPCONSOLE=y
|
||||
CONFIG_TERMINAL3270=y
|
||||
|
116
exec.c
116
exec.c
@@ -1482,25 +1482,17 @@ static int64_t get_file_size(int fd)
|
||||
return size;
|
||||
}
|
||||
|
||||
static void *file_ram_alloc(RAMBlock *block,
|
||||
ram_addr_t memory,
|
||||
const char *path,
|
||||
Error **errp)
|
||||
static int file_ram_open(const char *path,
|
||||
const char *region_name,
|
||||
bool *created,
|
||||
Error **errp)
|
||||
{
|
||||
bool unlink_on_error = false;
|
||||
char *filename;
|
||||
char *sanitized_name;
|
||||
char *c;
|
||||
void *area = MAP_FAILED;
|
||||
int fd = -1;
|
||||
int64_t file_size;
|
||||
|
||||
if (kvm_enabled() && !kvm_has_sync_mmu()) {
|
||||
error_setg(errp,
|
||||
"host lacks kvm mmu notifiers, -mem-path unsupported");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*created = false;
|
||||
for (;;) {
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd >= 0) {
|
||||
@@ -1511,13 +1503,13 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
/* @path names a file that doesn't exist, create it */
|
||||
fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0644);
|
||||
if (fd >= 0) {
|
||||
unlink_on_error = true;
|
||||
*created = true;
|
||||
break;
|
||||
}
|
||||
} else if (errno == EISDIR) {
|
||||
/* @path names a directory, create a file there */
|
||||
/* Make name safe to use with mkstemp by replacing '/' with '_'. */
|
||||
sanitized_name = g_strdup(memory_region_name(block->mr));
|
||||
sanitized_name = g_strdup(region_name);
|
||||
for (c = sanitized_name; *c != '\0'; c++) {
|
||||
if (*c == '/') {
|
||||
*c = '_';
|
||||
@@ -1540,7 +1532,7 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
error_setg_errno(errp, errno,
|
||||
"can't open backing store %s for guest RAM",
|
||||
path);
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Try again on EINTR and EEXIST. The latter happens when
|
||||
@@ -1548,6 +1540,17 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
*/
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void *file_ram_alloc(RAMBlock *block,
|
||||
ram_addr_t memory,
|
||||
int fd,
|
||||
bool truncate,
|
||||
Error **errp)
|
||||
{
|
||||
void *area;
|
||||
|
||||
block->page_size = qemu_fd_getpagesize(fd);
|
||||
block->mr->align = block->page_size;
|
||||
#if defined(__s390x__)
|
||||
@@ -1556,20 +1559,11 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
}
|
||||
#endif
|
||||
|
||||
file_size = get_file_size(fd);
|
||||
|
||||
if (memory < block->page_size) {
|
||||
error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to "
|
||||
"or larger than page size 0x%zx",
|
||||
memory, block->page_size);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (file_size > 0 && file_size < memory) {
|
||||
error_setg(errp, "backing store %s size 0x%" PRIx64
|
||||
" does not match 'size' option 0x" RAM_ADDR_FMT,
|
||||
path, file_size, memory);
|
||||
goto error;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memory = ROUND_UP(memory, block->page_size);
|
||||
@@ -1588,7 +1582,7 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
* those labels. Therefore, extending the non-empty backend file
|
||||
* is disabled as well.
|
||||
*/
|
||||
if (!file_size && ftruncate(fd, memory)) {
|
||||
if (truncate && ftruncate(fd, memory)) {
|
||||
perror("ftruncate");
|
||||
}
|
||||
|
||||
@@ -1597,30 +1591,19 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
if (area == MAP_FAILED) {
|
||||
error_setg_errno(errp, errno,
|
||||
"unable to map backing store for guest RAM");
|
||||
goto error;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mem_prealloc) {
|
||||
os_mem_prealloc(fd, area, memory, smp_cpus, errp);
|
||||
if (errp && *errp) {
|
||||
goto error;
|
||||
qemu_ram_munmap(area, memory);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
block->fd = fd;
|
||||
return area;
|
||||
|
||||
error:
|
||||
if (area != MAP_FAILED) {
|
||||
qemu_ram_munmap(area, memory);
|
||||
}
|
||||
if (unlink_on_error) {
|
||||
unlink(path);
|
||||
}
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1931,18 +1914,25 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
|
||||
bool share, const char *mem_path,
|
||||
Error **errp)
|
||||
RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
|
||||
bool share, int fd,
|
||||
Error **errp)
|
||||
{
|
||||
RAMBlock *new_block;
|
||||
Error *local_err = NULL;
|
||||
int64_t file_size;
|
||||
|
||||
if (xen_enabled()) {
|
||||
error_setg(errp, "-mem-path not supported with Xen");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (kvm_enabled() && !kvm_has_sync_mmu()) {
|
||||
error_setg(errp,
|
||||
"host lacks kvm mmu notifiers, -mem-path unsupported");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (phys_mem_alloc != qemu_anon_ram_alloc) {
|
||||
/*
|
||||
* file_ram_alloc() needs to allocate just like
|
||||
@@ -1955,13 +1945,20 @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
|
||||
}
|
||||
|
||||
size = HOST_PAGE_ALIGN(size);
|
||||
file_size = get_file_size(fd);
|
||||
if (file_size > 0 && file_size < size) {
|
||||
error_setg(errp, "backing store %s size 0x%" PRIx64
|
||||
" does not match 'size' option 0x" RAM_ADDR_FMT,
|
||||
mem_path, file_size, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_block = g_malloc0(sizeof(*new_block));
|
||||
new_block->mr = mr;
|
||||
new_block->used_length = size;
|
||||
new_block->max_length = size;
|
||||
new_block->flags = share ? RAM_SHARED : 0;
|
||||
new_block->host = file_ram_alloc(new_block, size,
|
||||
mem_path, errp);
|
||||
new_block->host = file_ram_alloc(new_block, size, fd, !file_size, errp);
|
||||
if (!new_block->host) {
|
||||
g_free(new_block);
|
||||
return NULL;
|
||||
@@ -1974,6 +1971,33 @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
|
||||
return NULL;
|
||||
}
|
||||
return new_block;
|
||||
|
||||
}
|
||||
|
||||
|
||||
RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
|
||||
bool share, const char *mem_path,
|
||||
Error **errp)
|
||||
{
|
||||
int fd;
|
||||
bool created;
|
||||
RAMBlock *block;
|
||||
|
||||
fd = file_ram_open(mem_path, memory_region_name(mr), &created, errp);
|
||||
if (fd < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block = qemu_ram_alloc_from_fd(size, mr, share, fd, errp);
|
||||
if (!block) {
|
||||
if (created) {
|
||||
unlink(mem_path);
|
||||
}
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -111,7 +111,7 @@ float16 float16_default_nan(float_status *status)
|
||||
*----------------------------------------------------------------------------*/
|
||||
float32 float32_default_nan(float_status *status)
|
||||
{
|
||||
#if defined(TARGET_SPARC)
|
||||
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
|
||||
return const_float32(0x7FFFFFFF);
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
|
||||
defined(TARGET_XTENSA) || defined(TARGET_S390X) || defined(TARGET_TRICORE)
|
||||
@@ -136,7 +136,7 @@ float32 float32_default_nan(float_status *status)
|
||||
*----------------------------------------------------------------------------*/
|
||||
float64 float64_default_nan(float_status *status)
|
||||
{
|
||||
#if defined(TARGET_SPARC)
|
||||
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
|
||||
return const_float64(LIT64(0x7FFFFFFFFFFFFFFF));
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
|
||||
defined(TARGET_S390X)
|
||||
@@ -162,7 +162,10 @@ float64 float64_default_nan(float_status *status)
|
||||
floatx80 floatx80_default_nan(float_status *status)
|
||||
{
|
||||
floatx80 r;
|
||||
|
||||
#if defined(TARGET_M68K)
|
||||
r.low = LIT64(0xFFFFFFFFFFFFFFFF);
|
||||
r.high = 0x7FFF;
|
||||
#else
|
||||
if (status->snan_bit_is_one) {
|
||||
r.low = LIT64(0xBFFFFFFFFFFFFFFF);
|
||||
r.high = 0x7FFF;
|
||||
@@ -170,6 +173,7 @@ floatx80 floatx80_default_nan(float_status *status)
|
||||
r.low = LIT64(0xC000000000000000);
|
||||
r.high = 0xFFFF;
|
||||
}
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -502,6 +506,30 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#elif defined(TARGET_M68K)
|
||||
static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
|
||||
flag aIsLargerSignificand)
|
||||
{
|
||||
/* M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL
|
||||
* 3.4 FLOATING-POINT INSTRUCTION DETAILS
|
||||
* If either operand, but not both operands, of an operation is a
|
||||
* nonsignaling NaN, then that NaN is returned as the result. If both
|
||||
* operands are nonsignaling NaNs, then the destination operand
|
||||
* nonsignaling NaN is returned as the result.
|
||||
* If either operand to an operation is a signaling NaN (SNaN), then the
|
||||
* SNaN bit is set in the FPSR EXC byte. If the SNaN exception enable bit
|
||||
* is set in the FPCR ENABLE byte, then the exception is taken and the
|
||||
* destination is not modified. If the SNaN exception enable bit is not
|
||||
* set, setting the SNaN bit in the operand to a one converts the SNaN to
|
||||
* a nonsignaling NaN. The operation then continues as described in the
|
||||
* preceding paragraph for nonsignaling NaNs.
|
||||
*/
|
||||
if (aIsQNaN || aIsSNaN) { /* a is the destination operand */
|
||||
return 0; /* return the destination operand */
|
||||
} else {
|
||||
return 1; /* return b */
|
||||
}
|
||||
}
|
||||
#else
|
||||
static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
|
||||
flag aIsLargerSignificand)
|
||||
|
@@ -83,23 +83,25 @@ static uint64_t acpi_memory_hotplug_read(void *opaque, hwaddr addr,
|
||||
o = OBJECT(mdev->dimm);
|
||||
switch (addr) {
|
||||
case 0x0: /* Lo part of phys address where DIMM is mapped */
|
||||
val = o ? object_property_get_int(o, PC_DIMM_ADDR_PROP, NULL) : 0;
|
||||
val = o ? object_property_get_uint(o, PC_DIMM_ADDR_PROP, NULL) : 0;
|
||||
trace_mhp_acpi_read_addr_lo(mem_st->selector, val);
|
||||
break;
|
||||
case 0x4: /* Hi part of phys address where DIMM is mapped */
|
||||
val = o ? object_property_get_int(o, PC_DIMM_ADDR_PROP, NULL) >> 32 : 0;
|
||||
val =
|
||||
o ? object_property_get_uint(o, PC_DIMM_ADDR_PROP, NULL) >> 32 : 0;
|
||||
trace_mhp_acpi_read_addr_hi(mem_st->selector, val);
|
||||
break;
|
||||
case 0x8: /* Lo part of DIMM size */
|
||||
val = o ? object_property_get_int(o, PC_DIMM_SIZE_PROP, NULL) : 0;
|
||||
val = o ? object_property_get_uint(o, PC_DIMM_SIZE_PROP, NULL) : 0;
|
||||
trace_mhp_acpi_read_size_lo(mem_st->selector, val);
|
||||
break;
|
||||
case 0xc: /* Hi part of DIMM size */
|
||||
val = o ? object_property_get_int(o, PC_DIMM_SIZE_PROP, NULL) >> 32 : 0;
|
||||
val =
|
||||
o ? object_property_get_uint(o, PC_DIMM_SIZE_PROP, NULL) >> 32 : 0;
|
||||
trace_mhp_acpi_read_size_hi(mem_st->selector, val);
|
||||
break;
|
||||
case 0x10: /* node proximity for _PXM method */
|
||||
val = o ? object_property_get_int(o, PC_DIMM_NODE_PROP, NULL) : 0;
|
||||
val = o ? object_property_get_uint(o, PC_DIMM_NODE_PROP, NULL) : 0;
|
||||
trace_mhp_acpi_read_pxm(mem_st->selector, val);
|
||||
break;
|
||||
case 0x14: /* pack and return is_* fields */
|
||||
|
@@ -236,14 +236,14 @@ static void
|
||||
nvdimm_build_structure_spa(GArray *structures, DeviceState *dev)
|
||||
{
|
||||
NvdimmNfitSpa *nfit_spa;
|
||||
uint64_t addr = object_property_get_int(OBJECT(dev), PC_DIMM_ADDR_PROP,
|
||||
NULL);
|
||||
uint64_t size = object_property_get_int(OBJECT(dev), PC_DIMM_SIZE_PROP,
|
||||
NULL);
|
||||
uint32_t node = object_property_get_int(OBJECT(dev), PC_DIMM_NODE_PROP,
|
||||
NULL);
|
||||
uint64_t addr = object_property_get_uint(OBJECT(dev), PC_DIMM_ADDR_PROP,
|
||||
NULL);
|
||||
uint64_t size = object_property_get_uint(OBJECT(dev), PC_DIMM_SIZE_PROP,
|
||||
NULL);
|
||||
uint32_t node = object_property_get_uint(OBJECT(dev), PC_DIMM_NODE_PROP,
|
||||
NULL);
|
||||
int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP,
|
||||
NULL);
|
||||
NULL);
|
||||
|
||||
nfit_spa = acpi_data_push(structures, sizeof(*nfit_spa));
|
||||
|
||||
@@ -284,8 +284,8 @@ static void
|
||||
nvdimm_build_structure_memdev(GArray *structures, DeviceState *dev)
|
||||
{
|
||||
NvdimmNfitMemDev *nfit_memdev;
|
||||
uint64_t size = object_property_get_int(OBJECT(dev), PC_DIMM_SIZE_PROP,
|
||||
NULL);
|
||||
uint64_t size = object_property_get_uint(OBJECT(dev), PC_DIMM_SIZE_PROP,
|
||||
NULL);
|
||||
int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP,
|
||||
NULL);
|
||||
uint32_t handle = nvdimm_slot_to_handle(slot);
|
||||
|
@@ -37,7 +37,6 @@
|
||||
#include "hw/pci/pci_bus.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qom/qom-qobject.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
@@ -63,10 +62,10 @@ typedef struct AcpiPciHpFind {
|
||||
static int acpi_pcihp_get_bsel(PCIBus *bus)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int64_t bsel = object_property_get_int(OBJECT(bus), ACPI_PCIHP_PROP_BSEL,
|
||||
&local_err);
|
||||
uint64_t bsel = object_property_get_uint(OBJECT(bus), ACPI_PCIHP_PROP_BSEL,
|
||||
&local_err);
|
||||
|
||||
if (local_err || bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
|
||||
if (local_err || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
|
||||
if (local_err) {
|
||||
error_free(local_err);
|
||||
}
|
||||
|
@@ -180,8 +180,8 @@ static void aspeed_board_init(MachineState *machine,
|
||||
|
||||
sc = ASPEED_SOC_GET_CLASS(&bmc->soc);
|
||||
|
||||
object_property_set_int(OBJECT(&bmc->soc), ram_size, "ram-size",
|
||||
&error_abort);
|
||||
object_property_set_uint(OBJECT(&bmc->soc), ram_size, "ram-size",
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1",
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&bmc->soc), cfg->num_cs, "num-cs",
|
||||
@@ -193,8 +193,8 @@ static void aspeed_board_init(MachineState *machine,
|
||||
* Allocate RAM after the memory controller has checked the size
|
||||
* was valid. If not, a default value is used.
|
||||
*/
|
||||
ram_size = object_property_get_int(OBJECT(&bmc->soc), "ram-size",
|
||||
&error_abort);
|
||||
ram_size = object_property_get_uint(OBJECT(&bmc->soc), "ram-size",
|
||||
&error_abort);
|
||||
|
||||
memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size);
|
||||
memory_region_add_subregion(get_system_memory(), sc->info->sdram_base,
|
||||
|
@@ -125,7 +125,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
|
||||
Object *obj;
|
||||
MemoryRegion *ram;
|
||||
Error *err = NULL;
|
||||
uint32_t ram_size, vcram_size;
|
||||
uint64_t ram_size, vcram_size;
|
||||
int n;
|
||||
|
||||
obj = object_property_get_link(OBJECT(dev), "ram", &err);
|
||||
@@ -207,15 +207,14 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
|
||||
INTERRUPT_ARM_MAILBOX));
|
||||
|
||||
/* Framebuffer */
|
||||
vcram_size = (uint32_t)object_property_get_int(OBJECT(s), "vcram-size",
|
||||
&err);
|
||||
vcram_size = object_property_get_uint(OBJECT(s), "vcram-size", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_int(OBJECT(&s->fb), ram_size - vcram_size,
|
||||
"vcram-base", &err);
|
||||
object_property_set_uint(OBJECT(&s->fb), ram_size - vcram_size,
|
||||
"vcram-base", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
|
@@ -153,8 +153,8 @@ static void raspi2_init(MachineState *machine)
|
||||
qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
|
||||
object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
|
||||
|
||||
vcram_size = object_property_get_int(OBJECT(&s->soc), "vcram-size",
|
||||
&error_abort);
|
||||
vcram_size = object_property_get_uint(OBJECT(&s->soc), "vcram-size",
|
||||
&error_abort);
|
||||
setup_boot(machine, 2, machine->ram_size - vcram_size);
|
||||
}
|
||||
|
||||
|
@@ -511,7 +511,7 @@ typedef struct FloppyDrive {
|
||||
static Property floppy_drive_properties[] = {
|
||||
DEFINE_PROP_UINT32("unit", FloppyDrive, unit, -1),
|
||||
DEFINE_BLOCK_PROPERTIES(FloppyDrive, conf),
|
||||
DEFINE_PROP_DEFAULT("drive-type", FloppyDrive, type,
|
||||
DEFINE_PROP_SIGNED("drive-type", FloppyDrive, type,
|
||||
FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
|
||||
FloppyDriveType),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
@@ -2805,13 +2805,13 @@ static Property isa_fdc_properties[] = {
|
||||
DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.qdev_for_drives[1].blk),
|
||||
DEFINE_PROP_BIT("check_media_rate", FDCtrlISABus, state.check_media_rate,
|
||||
0, true),
|
||||
DEFINE_PROP_DEFAULT("fdtypeA", FDCtrlISABus, state.qdev_for_drives[0].type,
|
||||
DEFINE_PROP_SIGNED("fdtypeA", FDCtrlISABus, state.qdev_for_drives[0].type,
|
||||
FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
|
||||
FloppyDriveType),
|
||||
DEFINE_PROP_DEFAULT("fdtypeB", FDCtrlISABus, state.qdev_for_drives[1].type,
|
||||
DEFINE_PROP_SIGNED("fdtypeB", FDCtrlISABus, state.qdev_for_drives[1].type,
|
||||
FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
|
||||
FloppyDriveType),
|
||||
DEFINE_PROP_DEFAULT("fallback", FDCtrlISABus, state.fallback,
|
||||
DEFINE_PROP_SIGNED("fallback", FDCtrlISABus, state.fallback,
|
||||
FLOPPY_DRIVE_TYPE_288, qdev_prop_fdc_drive_type,
|
||||
FloppyDriveType),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
@@ -2862,13 +2862,13 @@ static const VMStateDescription vmstate_sysbus_fdc ={
|
||||
static Property sysbus_fdc_properties[] = {
|
||||
DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.qdev_for_drives[0].blk),
|
||||
DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.qdev_for_drives[1].blk),
|
||||
DEFINE_PROP_DEFAULT("fdtypeA", FDCtrlSysBus, state.qdev_for_drives[0].type,
|
||||
DEFINE_PROP_SIGNED("fdtypeA", FDCtrlSysBus, state.qdev_for_drives[0].type,
|
||||
FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
|
||||
FloppyDriveType),
|
||||
DEFINE_PROP_DEFAULT("fdtypeB", FDCtrlSysBus, state.qdev_for_drives[1].type,
|
||||
DEFINE_PROP_SIGNED("fdtypeB", FDCtrlSysBus, state.qdev_for_drives[1].type,
|
||||
FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
|
||||
FloppyDriveType),
|
||||
DEFINE_PROP_DEFAULT("fallback", FDCtrlISABus, state.fallback,
|
||||
DEFINE_PROP_SIGNED("fallback", FDCtrlISABus, state.fallback,
|
||||
FLOPPY_DRIVE_TYPE_144, qdev_prop_fdc_drive_type,
|
||||
FloppyDriveType),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
@@ -2891,10 +2891,10 @@ static const TypeInfo sysbus_fdc_info = {
|
||||
|
||||
static Property sun4m_fdc_properties[] = {
|
||||
DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.qdev_for_drives[0].blk),
|
||||
DEFINE_PROP_DEFAULT("fdtype", FDCtrlSysBus, state.qdev_for_drives[0].type,
|
||||
DEFINE_PROP_SIGNED("fdtype", FDCtrlSysBus, state.qdev_for_drives[0].type,
|
||||
FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
|
||||
FloppyDriveType),
|
||||
DEFINE_PROP_DEFAULT("fallback", FDCtrlISABus, state.fallback,
|
||||
DEFINE_PROP_SIGNED("fallback", FDCtrlISABus, state.fallback,
|
||||
FLOPPY_DRIVE_TYPE_144, qdev_prop_fdc_drive_type,
|
||||
FloppyDriveType),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
|
@@ -71,7 +71,7 @@ hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
||||
return -1;
|
||||
}
|
||||
|
||||
return object_property_get_int(OBJECT(sbdev_mr), "addr", NULL);
|
||||
return object_property_get_uint(OBJECT(sbdev_mr), "addr", NULL);
|
||||
}
|
||||
|
||||
static void platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque)
|
||||
|
@@ -69,6 +69,12 @@ static void set_enum(Object *obj, Visitor *v, const char *name, void *opaque,
|
||||
visit_type_enum(v, prop->name, ptr, prop->info->enum_table, errp);
|
||||
}
|
||||
|
||||
static void set_default_value_enum(Object *obj, const Property *prop)
|
||||
{
|
||||
object_property_set_str(obj, prop->info->enum_table[prop->defval.i],
|
||||
prop->name, &error_abort);
|
||||
}
|
||||
|
||||
/* Bit */
|
||||
|
||||
static uint32_t qdev_get_prop_mask(Property *prop)
|
||||
@@ -120,11 +126,17 @@ static void prop_set_bit(Object *obj, Visitor *v, const char *name,
|
||||
bit_prop_set(dev, prop, value);
|
||||
}
|
||||
|
||||
static void set_default_value_bool(Object *obj, const Property *prop)
|
||||
{
|
||||
object_property_set_bool(obj, prop->defval.u, prop->name, &error_abort);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_bit = {
|
||||
.name = "bool",
|
||||
.description = "on/off",
|
||||
.get = prop_get_bit,
|
||||
.set = prop_set_bit,
|
||||
.set_default_value = set_default_value_bool,
|
||||
};
|
||||
|
||||
/* Bit64 */
|
||||
@@ -183,6 +195,7 @@ PropertyInfo qdev_prop_bit64 = {
|
||||
.description = "on/off",
|
||||
.get = prop_get_bit64,
|
||||
.set = prop_set_bit64,
|
||||
.set_default_value = set_default_value_bool,
|
||||
};
|
||||
|
||||
/* --- bool --- */
|
||||
@@ -216,6 +229,7 @@ PropertyInfo qdev_prop_bool = {
|
||||
.name = "bool",
|
||||
.get = get_bool,
|
||||
.set = set_bool,
|
||||
.set_default_value = set_default_value_bool,
|
||||
};
|
||||
|
||||
/* --- 8bit integer --- */
|
||||
@@ -245,10 +259,21 @@ static void set_uint8(Object *obj, Visitor *v, const char *name, void *opaque,
|
||||
visit_type_uint8(v, name, ptr, errp);
|
||||
}
|
||||
|
||||
static void set_default_value_int(Object *obj, const Property *prop)
|
||||
{
|
||||
object_property_set_int(obj, prop->defval.i, prop->name, &error_abort);
|
||||
}
|
||||
|
||||
static void set_default_value_uint(Object *obj, const Property *prop)
|
||||
{
|
||||
object_property_set_uint(obj, prop->defval.u, prop->name, &error_abort);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_uint8 = {
|
||||
.name = "uint8",
|
||||
.get = get_uint8,
|
||||
.set = set_uint8,
|
||||
.set_default_value = set_default_value_uint,
|
||||
};
|
||||
|
||||
/* --- 16bit integer --- */
|
||||
@@ -282,6 +307,7 @@ PropertyInfo qdev_prop_uint16 = {
|
||||
.name = "uint16",
|
||||
.get = get_uint16,
|
||||
.set = set_uint16,
|
||||
.set_default_value = set_default_value_uint,
|
||||
};
|
||||
|
||||
/* --- 32bit integer --- */
|
||||
@@ -340,12 +366,14 @@ PropertyInfo qdev_prop_uint32 = {
|
||||
.name = "uint32",
|
||||
.get = get_uint32,
|
||||
.set = set_uint32,
|
||||
.set_default_value = set_default_value_uint,
|
||||
};
|
||||
|
||||
PropertyInfo qdev_prop_int32 = {
|
||||
.name = "int32",
|
||||
.get = get_int32,
|
||||
.set = set_int32,
|
||||
.set_default_value = set_default_value_int,
|
||||
};
|
||||
|
||||
/* --- 64bit integer --- */
|
||||
@@ -379,6 +407,7 @@ PropertyInfo qdev_prop_uint64 = {
|
||||
.name = "uint64",
|
||||
.get = get_uint64,
|
||||
.set = set_uint64,
|
||||
.set_default_value = set_default_value_uint,
|
||||
};
|
||||
|
||||
/* --- string --- */
|
||||
@@ -526,6 +555,7 @@ PropertyInfo qdev_prop_on_off_auto = {
|
||||
.enum_table = OnOffAuto_lookup,
|
||||
.get = get_enum,
|
||||
.set = set_enum,
|
||||
.set_default_value = set_default_value_enum,
|
||||
};
|
||||
|
||||
/* --- lost tick policy --- */
|
||||
@@ -537,6 +567,7 @@ PropertyInfo qdev_prop_losttickpolicy = {
|
||||
.enum_table = LostTickPolicy_lookup,
|
||||
.get = get_enum,
|
||||
.set = set_enum,
|
||||
.set_default_value = set_default_value_enum,
|
||||
};
|
||||
|
||||
/* --- Block device error handling policy --- */
|
||||
@@ -550,6 +581,7 @@ PropertyInfo qdev_prop_blockdev_on_error = {
|
||||
.enum_table = BlockdevOnError_lookup,
|
||||
.get = get_enum,
|
||||
.set = set_enum,
|
||||
.set_default_value = set_default_value_enum,
|
||||
};
|
||||
|
||||
/* --- BIOS CHS translation */
|
||||
@@ -563,6 +595,7 @@ PropertyInfo qdev_prop_bios_chs_trans = {
|
||||
.enum_table = BiosAtaTranslation_lookup,
|
||||
.get = get_enum,
|
||||
.set = set_enum,
|
||||
.set_default_value = set_default_value_enum,
|
||||
};
|
||||
|
||||
/* --- FDC default drive types */
|
||||
@@ -573,7 +606,8 @@ PropertyInfo qdev_prop_fdc_drive_type = {
|
||||
"144/288/120/none/auto",
|
||||
.enum_table = FloppyDriveType_lookup,
|
||||
.get = get_enum,
|
||||
.set = set_enum
|
||||
.set = set_enum,
|
||||
.set_default_value = set_default_value_enum,
|
||||
};
|
||||
|
||||
/* --- pci address --- */
|
||||
@@ -648,6 +682,7 @@ PropertyInfo qdev_prop_pci_devfn = {
|
||||
.print = print_pci_devfn,
|
||||
.get = get_int32,
|
||||
.set = set_pci_devfn,
|
||||
.set_default_value = set_default_value_int,
|
||||
};
|
||||
|
||||
/* --- blocksize --- */
|
||||
@@ -695,6 +730,7 @@ PropertyInfo qdev_prop_blocksize = {
|
||||
.description = "A power of two between 512 and 32768",
|
||||
.get = get_uint16,
|
||||
.set = set_blocksize,
|
||||
.set_default_value = set_default_value_uint,
|
||||
};
|
||||
|
||||
/* --- pci host address --- */
|
||||
@@ -917,6 +953,7 @@ PropertyInfo qdev_prop_arraylen = {
|
||||
.name = "uint32",
|
||||
.get = get_uint32,
|
||||
.set = set_prop_arraylen,
|
||||
.set_default_value = set_default_value_uint,
|
||||
};
|
||||
|
||||
/* --- public helpers --- */
|
||||
@@ -1153,4 +1190,5 @@ PropertyInfo qdev_prop_size = {
|
||||
.name = "size",
|
||||
.get = get_size,
|
||||
.set = set_size,
|
||||
.set_default_value = set_default_value_uint,
|
||||
};
|
||||
|
@@ -793,17 +793,8 @@ void qdev_property_add_static(DeviceState *dev, Property *prop,
|
||||
prop->info->description,
|
||||
&error_abort);
|
||||
|
||||
if (prop->qtype == QTYPE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop->qtype == QTYPE_QBOOL) {
|
||||
object_property_set_bool(obj, prop->defval, prop->name, &error_abort);
|
||||
} else if (prop->info->enum_table) {
|
||||
object_property_set_str(obj, prop->info->enum_table[prop->defval],
|
||||
prop->name, &error_abort);
|
||||
} else if (prop->qtype == QTYPE_QINT) {
|
||||
object_property_set_int(obj, prop->defval, prop->name, &error_abort);
|
||||
if (prop->info->set_default_value) {
|
||||
prop->info->set_default_value(obj, prop);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -57,7 +57,6 @@
|
||||
|
||||
#include "hw/acpi/aml-build.h"
|
||||
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qom/qom-qobject.h"
|
||||
#include "hw/i386/amd_iommu.h"
|
||||
#include "hw/i386/intel_iommu.h"
|
||||
@@ -137,9 +136,9 @@ static void acpi_get_pm_info(AcpiPmInfo *pm)
|
||||
obj = piix;
|
||||
pm->cpu_hp_io_base = PIIX4_CPU_HOTPLUG_IO_BASE;
|
||||
pm->pcihp_io_base =
|
||||
object_property_get_int(obj, ACPI_PCIHP_IO_BASE_PROP, NULL);
|
||||
object_property_get_uint(obj, ACPI_PCIHP_IO_BASE_PROP, NULL);
|
||||
pm->pcihp_io_len =
|
||||
object_property_get_int(obj, ACPI_PCIHP_IO_LEN_PROP, NULL);
|
||||
object_property_get_uint(obj, ACPI_PCIHP_IO_LEN_PROP, NULL);
|
||||
}
|
||||
if (lpc) {
|
||||
obj = lpc;
|
||||
@@ -150,41 +149,42 @@ static void acpi_get_pm_info(AcpiPmInfo *pm)
|
||||
/* Fill in optional s3/s4 related properties */
|
||||
o = object_property_get_qobject(obj, ACPI_PM_PROP_S3_DISABLED, NULL);
|
||||
if (o) {
|
||||
pm->s3_disabled = qint_get_int(qobject_to_qint(o));
|
||||
pm->s3_disabled = qnum_get_uint(qobject_to_qnum(o));
|
||||
} else {
|
||||
pm->s3_disabled = false;
|
||||
}
|
||||
qobject_decref(o);
|
||||
o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_DISABLED, NULL);
|
||||
if (o) {
|
||||
pm->s4_disabled = qint_get_int(qobject_to_qint(o));
|
||||
pm->s4_disabled = qnum_get_uint(qobject_to_qnum(o));
|
||||
} else {
|
||||
pm->s4_disabled = false;
|
||||
}
|
||||
qobject_decref(o);
|
||||
o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_VAL, NULL);
|
||||
if (o) {
|
||||
pm->s4_val = qint_get_int(qobject_to_qint(o));
|
||||
pm->s4_val = qnum_get_uint(qobject_to_qnum(o));
|
||||
} else {
|
||||
pm->s4_val = false;
|
||||
}
|
||||
qobject_decref(o);
|
||||
|
||||
/* Fill in mandatory properties */
|
||||
pm->sci_int = object_property_get_int(obj, ACPI_PM_PROP_SCI_INT, NULL);
|
||||
pm->sci_int = object_property_get_uint(obj, ACPI_PM_PROP_SCI_INT, NULL);
|
||||
|
||||
pm->acpi_enable_cmd = object_property_get_int(obj,
|
||||
ACPI_PM_PROP_ACPI_ENABLE_CMD,
|
||||
NULL);
|
||||
pm->acpi_disable_cmd = object_property_get_int(obj,
|
||||
ACPI_PM_PROP_ACPI_DISABLE_CMD,
|
||||
NULL);
|
||||
pm->io_base = object_property_get_int(obj, ACPI_PM_PROP_PM_IO_BASE,
|
||||
NULL);
|
||||
pm->gpe0_blk = object_property_get_int(obj, ACPI_PM_PROP_GPE0_BLK,
|
||||
pm->acpi_enable_cmd = object_property_get_uint(obj,
|
||||
ACPI_PM_PROP_ACPI_ENABLE_CMD,
|
||||
NULL);
|
||||
pm->acpi_disable_cmd =
|
||||
object_property_get_uint(obj,
|
||||
ACPI_PM_PROP_ACPI_DISABLE_CMD,
|
||||
NULL);
|
||||
pm->io_base = object_property_get_uint(obj, ACPI_PM_PROP_PM_IO_BASE,
|
||||
NULL);
|
||||
pm->gpe0_blk_len = object_property_get_int(obj, ACPI_PM_PROP_GPE0_BLK_LEN,
|
||||
NULL);
|
||||
pm->gpe0_blk = object_property_get_uint(obj, ACPI_PM_PROP_GPE0_BLK,
|
||||
NULL);
|
||||
pm->gpe0_blk_len = object_property_get_uint(obj, ACPI_PM_PROP_GPE0_BLK_LEN,
|
||||
NULL);
|
||||
pm->pcihp_bridge_en =
|
||||
object_property_get_bool(obj, "acpi-pci-hotplug-with-bridge-support",
|
||||
NULL);
|
||||
@@ -237,19 +237,19 @@ static void acpi_get_pci_holes(Range *hole, Range *hole64)
|
||||
g_assert(pci_host);
|
||||
|
||||
range_set_bounds1(hole,
|
||||
object_property_get_int(pci_host,
|
||||
PCI_HOST_PROP_PCI_HOLE_START,
|
||||
NULL),
|
||||
object_property_get_int(pci_host,
|
||||
PCI_HOST_PROP_PCI_HOLE_END,
|
||||
NULL));
|
||||
object_property_get_uint(pci_host,
|
||||
PCI_HOST_PROP_PCI_HOLE_START,
|
||||
NULL),
|
||||
object_property_get_uint(pci_host,
|
||||
PCI_HOST_PROP_PCI_HOLE_END,
|
||||
NULL));
|
||||
range_set_bounds1(hole64,
|
||||
object_property_get_int(pci_host,
|
||||
PCI_HOST_PROP_PCI_HOLE64_START,
|
||||
NULL),
|
||||
object_property_get_int(pci_host,
|
||||
PCI_HOST_PROP_PCI_HOLE64_END,
|
||||
NULL));
|
||||
object_property_get_uint(pci_host,
|
||||
PCI_HOST_PROP_PCI_HOLE64_START,
|
||||
NULL),
|
||||
object_property_get_uint(pci_host,
|
||||
PCI_HOST_PROP_PCI_HOLE64_END,
|
||||
NULL));
|
||||
}
|
||||
|
||||
#define ACPI_PORT_SMI_CMD 0x00b2 /* TODO: this is APM_CNT_IOPORT */
|
||||
@@ -529,7 +529,7 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
|
||||
|
||||
bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
|
||||
if (bsel) {
|
||||
int64_t bsel_val = qint_get_int(qobject_to_qint(bsel));
|
||||
uint64_t bsel_val = qnum_get_uint(qobject_to_qnum(bsel));
|
||||
|
||||
aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val)));
|
||||
notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED);
|
||||
@@ -639,7 +639,8 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
|
||||
|
||||
/* If bus supports hotplug select it and notify about local events */
|
||||
if (bsel) {
|
||||
int64_t bsel_val = qint_get_int(qobject_to_qint(bsel));
|
||||
uint64_t bsel_val = qnum_get_uint(qobject_to_qnum(bsel));
|
||||
|
||||
aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM")));
|
||||
aml_append(method,
|
||||
aml_call2("DVNT", aml_name("PCIU"), aml_int(1) /* Device Check */)
|
||||
@@ -2614,12 +2615,12 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg)
|
||||
if (!o) {
|
||||
return false;
|
||||
}
|
||||
mcfg->mcfg_base = qint_get_int(qobject_to_qint(o));
|
||||
mcfg->mcfg_base = qnum_get_uint(qobject_to_qnum(o));
|
||||
qobject_decref(o);
|
||||
|
||||
o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_SIZE, NULL);
|
||||
assert(o);
|
||||
mcfg->mcfg_size = qint_get_int(qobject_to_qint(o));
|
||||
mcfg->mcfg_size = qnum_get_uint(qobject_to_qnum(o));
|
||||
qobject_decref(o);
|
||||
return true;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -384,6 +384,7 @@ typedef struct VTDIOTLBPageInvInfo VTDIOTLBPageInvInfo;
|
||||
/* Pagesize of VTD paging structures, including root and context tables */
|
||||
#define VTD_PAGE_SHIFT 12
|
||||
#define VTD_PAGE_SIZE (1ULL << VTD_PAGE_SHIFT)
|
||||
#define VTD_PAGE_MASK (VTD_PAGE_SIZE - 1)
|
||||
|
||||
#define VTD_PAGE_SHIFT_4K 12
|
||||
#define VTD_PAGE_MASK_4K (~((1ULL << VTD_PAGE_SHIFT_4K) - 1))
|
||||
|
20
hw/i386/pc.c
20
hw/i386/pc.c
@@ -347,7 +347,7 @@ static int check_fdc(Object *obj, void *opaque)
|
||||
return 0;
|
||||
}
|
||||
|
||||
iobase = object_property_get_int(obj, "iobase", &local_err);
|
||||
iobase = object_property_get_uint(obj, "iobase", &local_err);
|
||||
if (local_err || iobase != 0x3f0) {
|
||||
error_free(local_err);
|
||||
return 0;
|
||||
@@ -1098,7 +1098,7 @@ static void pc_new_cpu(const char *typename, int64_t apic_id, Error **errp)
|
||||
|
||||
cpu = object_new(typename);
|
||||
|
||||
object_property_set_int(cpu, apic_id, "apic-id", &local_err);
|
||||
object_property_set_uint(cpu, apic_id, "apic-id", &local_err);
|
||||
object_property_set_bool(cpu, true, "realized", &local_err);
|
||||
|
||||
object_unref(cpu);
|
||||
@@ -1558,7 +1558,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
* and earlier, use IRQ2 for compat. Otherwise, use IRQ16~23,
|
||||
* IRQ8 and IRQ2.
|
||||
*/
|
||||
uint8_t compat = object_property_get_int(OBJECT(hpet),
|
||||
uint8_t compat = object_property_get_uint(OBJECT(hpet),
|
||||
HPET_INTCAP, NULL);
|
||||
if (!compat) {
|
||||
qdev_prop_set_uint32(hpet, HPET_INTCAP, hpet_irqs);
|
||||
@@ -1692,6 +1692,7 @@ static void pc_dimm_plug(HotplugHandler *hotplug_dev,
|
||||
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
|
||||
MemoryRegion *mr = ddc->get_memory_region(dimm);
|
||||
uint64_t align = TARGET_PAGE_SIZE;
|
||||
bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
|
||||
|
||||
if (memory_region_get_alignment(mr) && pcmc->enforce_aligned_dimm) {
|
||||
align = memory_region_get_alignment(mr);
|
||||
@@ -1703,17 +1704,18 @@ static void pc_dimm_plug(HotplugHandler *hotplug_dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (is_nvdimm && !pcms->acpi_nvdimm_state.is_enabled) {
|
||||
error_setg(&local_err,
|
||||
"nvdimm is not enabled: missing 'nvdimm' in '-M'");
|
||||
goto out;
|
||||
}
|
||||
|
||||
pc_dimm_memory_plug(dev, &pcms->hotplug_memory, mr, align, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
|
||||
if (!pcms->acpi_nvdimm_state.is_enabled) {
|
||||
error_setg(&local_err,
|
||||
"nvdimm is not enabled: missing 'nvdimm' in '-M'");
|
||||
goto out;
|
||||
}
|
||||
if (is_nvdimm) {
|
||||
nvdimm_plug(&pcms->acpi_nvdimm_state);
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,13 @@ vtd_inv_desc_wait_sw(uint64_t addr, uint32_t data) "wait invalidate status write
|
||||
vtd_inv_desc_wait_irq(const char *msg) "%s"
|
||||
vtd_inv_desc_wait_invalid(uint64_t hi, uint64_t lo) "invalid wait desc hi 0x%"PRIx64" lo 0x%"PRIx64
|
||||
vtd_inv_desc_wait_write_fail(uint64_t hi, uint64_t lo) "write fail for wait desc hi 0x%"PRIx64" lo 0x%"PRIx64
|
||||
vtd_inv_desc_iec(uint32_t granularity, uint32_t index, uint32_t mask) "granularity 0x%"PRIx32" index 0x%"PRIx32" mask 0x%"PRIx32
|
||||
vtd_inv_qi_enable(bool enable) "enabled %d"
|
||||
vtd_inv_qi_setup(uint64_t addr, int size) "addr 0x%"PRIx64" size %d"
|
||||
vtd_inv_qi_head(uint16_t head) "read head %d"
|
||||
vtd_inv_qi_tail(uint16_t head) "write tail %d"
|
||||
vtd_inv_qi_fetch(void) ""
|
||||
vtd_context_cache_reset(void) ""
|
||||
vtd_re_not_present(uint8_t bus) "Root entry bus %"PRIu8" not present"
|
||||
vtd_re_invalid(uint64_t hi, uint64_t lo) "invalid root entry hi 0x%"PRIx64" lo 0x%"PRIx64
|
||||
vtd_ce_not_present(uint8_t bus, uint8_t devfn) "Context entry bus %"PRIu8" devfn %"PRIu8" not present"
|
||||
@@ -40,6 +47,43 @@ vtd_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device
|
||||
vtd_as_unmap_whole(uint8_t bus, uint8_t slot, uint8_t fn, uint64_t iova, uint64_t size) "Device %02x:%02x.%x start 0x%"PRIx64" size 0x%"PRIx64
|
||||
vtd_translate_pt(uint16_t sid, uint64_t addr) "source id 0x%"PRIu16", iova 0x%"PRIx64
|
||||
vtd_pt_enable_fast_path(uint16_t sid, bool success) "sid 0x%"PRIu16" %d"
|
||||
vtd_irq_generate(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PRIx64
|
||||
vtd_reg_read(uint64_t addr, uint64_t size) "addr 0x%"PRIx64" size 0x%"PRIx64
|
||||
vtd_reg_write(uint64_t addr, uint64_t size, uint64_t val) "addr 0x%"PRIx64" size 0x%"PRIx64" value 0x%"PRIx64
|
||||
vtd_reg_dmar_root(uint64_t addr, bool extended) "addr 0x%"PRIx64" extended %d"
|
||||
vtd_reg_ir_root(uint64_t addr, uint32_t size) "addr 0x%"PRIx64" size 0x%"PRIx32
|
||||
vtd_reg_write_gcmd(uint32_t status, uint32_t val) "status 0x%"PRIx32" value 0x%"PRIx32
|
||||
vtd_reg_write_fectl(uint32_t value) "value 0x%"PRIx32
|
||||
vtd_reg_write_iectl(uint32_t value) "value 0x%"PRIx32
|
||||
vtd_reg_ics_clear_ip(void) ""
|
||||
vtd_dmar_translate(uint8_t bus, uint8_t slot, uint8_t func, uint64_t iova, uint64_t gpa, uint64_t mask) "dev %02x:%02x.%02x iova 0x%"PRIx64" -> gpa 0x%"PRIx64" mask 0x%"PRIx64
|
||||
vtd_dmar_enable(bool en) "enable %d"
|
||||
vtd_dmar_fault(uint16_t sid, int fault, uint64_t addr, bool is_write) "sid 0x%"PRIx16" fault %d addr 0x%"PRIx64" write %d"
|
||||
vtd_ir_enable(bool en) "enable %d"
|
||||
vtd_ir_irte_get(int index, uint64_t lo, uint64_t hi) "index %d low 0x%"PRIx64" high 0x%"PRIx64
|
||||
vtd_ir_remap(int index, int tri, int vec, int deliver, uint32_t dest, int dest_mode) "index %d trigger %d vector %d deliver %d dest 0x%"PRIx32" mode %d"
|
||||
vtd_ir_remap_type(const char *type) "%s"
|
||||
vtd_ir_remap_msi(uint64_t addr, uint64_t data, uint64_t addr2, uint64_t data2) "(addr 0x%"PRIx64", data 0x%"PRIx64") -> (addr 0x%"PRIx64", data 0x%"PRIx64")"
|
||||
vtd_ir_remap_msi_req(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PRIx64
|
||||
vtd_fsts_ppf(bool set) "FSTS PPF bit set to %d"
|
||||
vtd_fsts_clear_ip(void) ""
|
||||
vtd_frr_new(int index, uint64_t hi, uint64_t lo) "index %d high 0x%"PRIx64" low 0x%"PRIx64
|
||||
vtd_err(const char *str) "%s"
|
||||
vtd_err_dmar_iova_overflow(uint64_t iova) "iova 0x%"PRIx64
|
||||
vtd_err_dmar_slpte_read_error(uint64_t iova, int level) "iova 0x%"PRIx64" level %d"
|
||||
vtd_err_dmar_slpte_perm_error(uint64_t iova, int level, uint64_t slpte, bool is_write) "iova 0x%"PRIx64" level %d slpte 0x%"PRIx64" write %d"
|
||||
vtd_err_dmar_slpte_resv_error(uint64_t iova, int level, uint64_t slpte) "iova 0x%"PRIx64" level %d slpte 0x%"PRIx64
|
||||
vtd_err_dmar_translate(uint8_t bus, uint8_t slot, uint8_t func, uint64_t iova) "dev %02x:%02x.%02x iova 0x%"PRIx64
|
||||
vtd_err_qi_enable(uint16_t tail) "tail 0x%"PRIx16
|
||||
vtd_err_qi_disable(uint16_t head, uint16_t tail, int type) "head 0x%"PRIx16" tail 0x%"PRIx16" last_desc_type %d"
|
||||
vtd_err_qi_tail(uint16_t tail, uint16_t size) "tail 0x%"PRIx16" size 0x%"PRIx16
|
||||
vtd_err_irte(int index, uint64_t lo, uint64_t hi) "index %d low 0x%"PRIx64" high 0x%"PRIx64
|
||||
vtd_err_irte_sid(int index, uint16_t req, uint16_t target) "index %d SVT_ALL sid 0x%"PRIx16" (should be: 0x%"PRIx16")"
|
||||
vtd_err_irte_sid_bus(int index, uint8_t bus, uint8_t min, uint8_t max) "index %d SVT_BUS bus 0x%"PRIx8" (should be: 0x%"PRIx8"-0x%"PRIx8")"
|
||||
vtd_err_irte_svt(int index, int type) "index %d SVT type %d"
|
||||
vtd_err_ir_msi_invalid(uint16_t sid, uint64_t addr, uint64_t data) "sid 0x%"PRIx16" addr 0x%"PRIx64" data 0x%"PRIx64
|
||||
vtd_warn_ir_vector(uint16_t sid, int index, int vec, int target) "sid 0x%"PRIx16" index %d vec %d (should be: %d)"
|
||||
vtd_warn_ir_trigger(uint16_t sid, int index, int trig, int target) "sid 0x%"PRIx16" index %d trigger %d (should be: %d)"
|
||||
|
||||
# hw/i386/amd_iommu.c
|
||||
amdvi_evntlog_fail(uint64_t addr, uint32_t head) "error: fail to write at addr 0x%"PRIx64" + offset 0x%"PRIx32
|
||||
|
@@ -182,9 +182,9 @@ static void xen_ram_init(PCMachineState *pcms,
|
||||
{
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
ram_addr_t block_len;
|
||||
uint64_t user_lowmem = object_property_get_int(qdev_get_machine(),
|
||||
PC_MACHINE_MAX_RAM_BELOW_4G,
|
||||
&error_abort);
|
||||
uint64_t user_lowmem = object_property_get_uint(qdev_get_machine(),
|
||||
PC_MACHINE_MAX_RAM_BELOW_4G,
|
||||
&error_abort);
|
||||
|
||||
/* Handle the machine opt max-ram-below-4g. It is basically doing
|
||||
* min(xen limit, user limit).
|
||||
|
@@ -487,6 +487,7 @@ void hid_reset(HIDState *hs)
|
||||
memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
|
||||
memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
|
||||
hs->kbd.keys = 0;
|
||||
hs->kbd.modifiers = 0;
|
||||
break;
|
||||
case HID_MOUSE:
|
||||
case HID_TABLET:
|
||||
|
@@ -85,12 +85,12 @@ typedef struct {
|
||||
int rptr, wptr, count;
|
||||
} PS2Queue;
|
||||
|
||||
typedef struct {
|
||||
struct PS2State {
|
||||
PS2Queue queue;
|
||||
int32_t write_cmd;
|
||||
void (*update_irq)(void *, int);
|
||||
void *update_arg;
|
||||
} PS2State;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
PS2State common;
|
||||
@@ -551,9 +551,17 @@ static uint8_t translate_table[256] = {
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||
};
|
||||
|
||||
void ps2_queue(void *opaque, int b)
|
||||
static void ps2_reset_queue(PS2State *s)
|
||||
{
|
||||
PS2Queue *q = &s->queue;
|
||||
|
||||
q->rptr = 0;
|
||||
q->wptr = 0;
|
||||
q->count = 0;
|
||||
}
|
||||
|
||||
void ps2_queue(PS2State *s, int b)
|
||||
{
|
||||
PS2State *s = (PS2State *)opaque;
|
||||
PS2Queue *q = &s->queue;
|
||||
|
||||
if (q->count >= PS2_QUEUE_SIZE - 1)
|
||||
@@ -692,13 +700,12 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ps2_read_data(void *opaque)
|
||||
uint32_t ps2_read_data(PS2State *s)
|
||||
{
|
||||
PS2State *s = (PS2State *)opaque;
|
||||
PS2Queue *q;
|
||||
int val, index;
|
||||
|
||||
trace_ps2_read_data(opaque);
|
||||
trace_ps2_read_data(s);
|
||||
q = &s->queue;
|
||||
if (q->count == 0) {
|
||||
/* NOTE: if no data left, we return the last keyboard one
|
||||
@@ -733,6 +740,7 @@ static void ps2_reset_keyboard(PS2KbdState *s)
|
||||
trace_ps2_reset_keyboard(s);
|
||||
s->scan_enabled = 1;
|
||||
s->scancode_set = 2;
|
||||
ps2_reset_queue(&s->common);
|
||||
ps2_set_ledstate(s, 0);
|
||||
}
|
||||
|
||||
@@ -1081,12 +1089,8 @@ void ps2_write_mouse(void *opaque, int val)
|
||||
|
||||
static void ps2_common_reset(PS2State *s)
|
||||
{
|
||||
PS2Queue *q;
|
||||
s->write_cmd = -1;
|
||||
q = &s->queue;
|
||||
q->rptr = 0;
|
||||
q->wptr = 0;
|
||||
q->count = 0;
|
||||
ps2_reset_queue(s);
|
||||
s->update_irq(s->update_arg, 0);
|
||||
}
|
||||
|
||||
|
@@ -450,10 +450,10 @@ static void apic_common_get_id(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
APICCommonState *s = APIC_COMMON(obj);
|
||||
int64_t value;
|
||||
uint32_t value;
|
||||
|
||||
value = s->apicbase & MSR_IA32_APICBASE_EXTD ? s->initial_apic_id : s->id;
|
||||
visit_type_int(v, name, &value, errp);
|
||||
visit_type_uint32(v, name, &value, errp);
|
||||
}
|
||||
|
||||
static void apic_common_set_id(Object *obj, Visitor *v, const char *name,
|
||||
@@ -462,14 +462,14 @@ static void apic_common_set_id(Object *obj, Visitor *v, const char *name,
|
||||
APICCommonState *s = APIC_COMMON(obj);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Error *local_err = NULL;
|
||||
int64_t value;
|
||||
uint32_t value;
|
||||
|
||||
if (dev->realized) {
|
||||
qdev_prop_set_after_realize(dev, name, errp);
|
||||
return;
|
||||
}
|
||||
|
||||
visit_type_int(v, name, &value, &local_err);
|
||||
visit_type_uint32(v, name, &value, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
@@ -484,7 +484,7 @@ static void apic_common_initfn(Object *obj)
|
||||
APICCommonState *s = APIC_COMMON(obj);
|
||||
|
||||
s->id = s->initial_apic_id = -1;
|
||||
object_property_add(obj, "id", "int",
|
||||
object_property_add(obj, "id", "uint32",
|
||||
apic_common_get_id,
|
||||
apic_common_set_id, NULL, NULL, NULL);
|
||||
}
|
||||
|
@@ -268,7 +268,7 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
|
||||
* VLPIS == 0 (virtual LPIs not supported)
|
||||
* PLPIS == 0 (physical LPIs not supported)
|
||||
*/
|
||||
cpu_affid = object_property_get_int(OBJECT(cpu), "mp-affinity", NULL);
|
||||
cpu_affid = object_property_get_uint(OBJECT(cpu), "mp-affinity", NULL);
|
||||
last = (i == s->num_cpu - 1);
|
||||
|
||||
/* The CPU mp-affinity property is in MPIDR register format; squash
|
||||
|
@@ -46,7 +46,8 @@ void pc_dimm_memory_plug(DeviceState *dev, MemoryHotplugState *hpms,
|
||||
uint64_t existing_dimms_capacity = 0;
|
||||
uint64_t addr;
|
||||
|
||||
addr = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP, &local_err);
|
||||
addr = object_property_get_uint(OBJECT(dimm),
|
||||
PC_DIMM_ADDR_PROP, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
@@ -73,7 +74,7 @@ void pc_dimm_memory_plug(DeviceState *dev, MemoryHotplugState *hpms,
|
||||
goto out;
|
||||
}
|
||||
|
||||
object_property_set_int(OBJECT(dev), addr, PC_DIMM_ADDR_PROP, &local_err);
|
||||
object_property_set_uint(OBJECT(dev), addr, PC_DIMM_ADDR_PROP, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
@@ -135,7 +136,7 @@ static int pc_existing_dimms_capacity_internal(Object *obj, void *opaque)
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
|
||||
if (dev->realized) {
|
||||
(*size) += object_property_get_int(obj, PC_DIMM_SIZE_PROP,
|
||||
(*size) += object_property_get_uint(obj, PC_DIMM_SIZE_PROP,
|
||||
cap->errp);
|
||||
}
|
||||
|
||||
@@ -181,8 +182,8 @@ int qmp_pc_dimm_device_list(Object *obj, void *opaque)
|
||||
di->addr = dimm->addr;
|
||||
di->slot = dimm->slot;
|
||||
di->node = dimm->node;
|
||||
di->size = object_property_get_int(OBJECT(dimm), PC_DIMM_SIZE_PROP,
|
||||
NULL);
|
||||
di->size = object_property_get_uint(OBJECT(dimm), PC_DIMM_SIZE_PROP,
|
||||
NULL);
|
||||
di->memdev = object_get_canonical_path(OBJECT(dimm->hostmem));
|
||||
|
||||
info->u.dimm.data = di;
|
||||
@@ -313,9 +314,9 @@ uint64_t pc_dimm_get_free_addr(uint64_t address_space_start,
|
||||
/* find address range that will fit new DIMM */
|
||||
for (item = list; item; item = g_slist_next(item)) {
|
||||
PCDIMMDevice *dimm = item->data;
|
||||
uint64_t dimm_size = object_property_get_int(OBJECT(dimm),
|
||||
PC_DIMM_SIZE_PROP,
|
||||
errp);
|
||||
uint64_t dimm_size = object_property_get_uint(OBJECT(dimm),
|
||||
PC_DIMM_SIZE_PROP,
|
||||
errp);
|
||||
if (errp && *errp) {
|
||||
goto out;
|
||||
}
|
||||
@@ -355,7 +356,7 @@ static Property pc_dimm_properties[] = {
|
||||
static void pc_dimm_get_size(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
int64_t value;
|
||||
uint64_t value;
|
||||
MemoryRegion *mr;
|
||||
PCDIMMDevice *dimm = PC_DIMM(obj);
|
||||
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(obj);
|
||||
@@ -363,7 +364,7 @@ static void pc_dimm_get_size(Object *obj, Visitor *v, const char *name,
|
||||
mr = ddc->get_memory_region(dimm);
|
||||
value = memory_region_size(mr);
|
||||
|
||||
visit_type_int(v, name, &value, errp);
|
||||
visit_type_uint64(v, name, &value, errp);
|
||||
}
|
||||
|
||||
static void pc_dimm_check_memdev_is_busy(Object *obj, const char *name,
|
||||
@@ -386,7 +387,7 @@ static void pc_dimm_init(Object *obj)
|
||||
{
|
||||
PCDIMMDevice *dimm = PC_DIMM(obj);
|
||||
|
||||
object_property_add(obj, PC_DIMM_SIZE_PROP, "int", pc_dimm_get_size,
|
||||
object_property_add(obj, PC_DIMM_SIZE_PROP, "uint64", pc_dimm_get_size,
|
||||
NULL, NULL, NULL, &error_abort);
|
||||
object_property_add_link(obj, PC_DIMM_MEMDEV_PROP, TYPE_MEMORY_BACKEND,
|
||||
(Object **)&dimm->hostmem,
|
||||
|
@@ -244,7 +244,7 @@ static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent)
|
||||
|
||||
monitor_printf(mon, "%*smemory " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
|
||||
indent, "",
|
||||
object_property_get_int(OBJECT(s->mmio), "addr", NULL),
|
||||
object_property_get_uint(OBJECT(s->mmio), "addr", NULL),
|
||||
memory_region_size(s->mmio));
|
||||
}
|
||||
|
||||
|
@@ -491,9 +491,9 @@ static void setup_interrupt(IVShmemState *s, int vector, Error **errp)
|
||||
|
||||
static void process_msg_shmem(IVShmemState *s, int fd, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
struct stat buf;
|
||||
size_t size;
|
||||
void *ptr;
|
||||
|
||||
if (s->ivshmem_bar2) {
|
||||
error_setg(errp, "server sent unexpected shared memory message");
|
||||
@@ -522,15 +522,13 @@ static void process_msg_shmem(IVShmemState *s, int fd, Error **errp)
|
||||
}
|
||||
|
||||
/* mmap the region and map into the BAR2 */
|
||||
ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (ptr == MAP_FAILED) {
|
||||
error_setg_errno(errp, errno, "Failed to mmap shared memory");
|
||||
close(fd);
|
||||
memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s),
|
||||
"ivshmem.bar2", size, true, fd, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
memory_region_init_ram_ptr(&s->server_bar2, OBJECT(s),
|
||||
"ivshmem.bar2", size, ptr);
|
||||
memory_region_set_fd(&s->server_bar2, fd);
|
||||
|
||||
s->ivshmem_bar2 = &s->server_bar2;
|
||||
}
|
||||
|
||||
|
@@ -111,7 +111,7 @@ uint16_t pvpanic_port(void)
|
||||
if (!o) {
|
||||
return 0;
|
||||
}
|
||||
return object_property_get_int(o, PVPANIC_IOPORT_PROP, NULL);
|
||||
return object_property_get_uint(o, PVPANIC_IOPORT_PROP, NULL);
|
||||
}
|
||||
|
||||
static Property pvpanic_isa_properties[] = {
|
||||
|
@@ -645,12 +645,12 @@ static PropertyInfo e1000e_prop_disable_vnet,
|
||||
|
||||
static Property e1000e_properties[] = {
|
||||
DEFINE_NIC_PROPERTIES(E1000EState, conf),
|
||||
DEFINE_PROP_DEFAULT("disable_vnet_hdr", E1000EState, disable_vnet, false,
|
||||
DEFINE_PROP_SIGNED("disable_vnet_hdr", E1000EState, disable_vnet, false,
|
||||
e1000e_prop_disable_vnet, bool),
|
||||
DEFINE_PROP_DEFAULT("subsys_ven", E1000EState, subsys_ven,
|
||||
DEFINE_PROP_SIGNED("subsys_ven", E1000EState, subsys_ven,
|
||||
PCI_VENDOR_ID_INTEL,
|
||||
e1000e_prop_subsys_ven, uint16_t),
|
||||
DEFINE_PROP_DEFAULT("subsys", E1000EState, subsys, 0,
|
||||
DEFINE_PROP_SIGNED("subsys", E1000EState, subsys, 0,
|
||||
e1000e_prop_subsys, uint16_t),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
@@ -94,7 +94,7 @@ static void gpex_host_initfn(Object *obj)
|
||||
|
||||
object_initialize(root, sizeof(*root), TYPE_GPEX_ROOT_DEVICE);
|
||||
object_property_add_child(obj, "gpex_root", OBJECT(root), NULL);
|
||||
qdev_prop_set_uint32(DEVICE(root), "addr", PCI_DEVFN(0, 0));
|
||||
qdev_prop_set_int32(DEVICE(root), "addr", PCI_DEVFN(0, 0));
|
||||
qdev_prop_set_bit(DEVICE(root), "multifunction", false);
|
||||
}
|
||||
|
||||
|
@@ -273,19 +273,19 @@ static void i440fx_pcihost_initfn(Object *obj)
|
||||
memory_region_init_io(&s->data_mem, obj, &pci_host_data_le_ops, s,
|
||||
"pci-conf-data", 4);
|
||||
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "int",
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "uint32",
|
||||
i440fx_pcihost_get_pci_hole_start,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_END, "int",
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_END, "uint32",
|
||||
i440fx_pcihost_get_pci_hole_end,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_START, "int",
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_START, "uint64",
|
||||
i440fx_pcihost_get_pci_hole64_start,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "int",
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "uint64",
|
||||
i440fx_pcihost_get_pci_hole64_end,
|
||||
NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
@@ -129,12 +129,11 @@ static void q35_host_get_mmcfg_size(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
PCIExpressHost *e = PCIE_HOST_BRIDGE(obj);
|
||||
uint32_t value = e->size;
|
||||
|
||||
visit_type_uint32(v, name, &value, errp);
|
||||
visit_type_uint64(v, name, &e->size, errp);
|
||||
}
|
||||
|
||||
static Property mch_props[] = {
|
||||
static Property q35_host_props[] = {
|
||||
DEFINE_PROP_UINT64(PCIE_HOST_MCFG_BASE, Q35PCIHost, parent_obj.base_addr,
|
||||
MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
|
||||
DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, Q35PCIHost,
|
||||
@@ -154,7 +153,7 @@ static void q35_host_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
hc->root_bus_path = q35_host_root_bus_path;
|
||||
dc->realize = q35_host_realize;
|
||||
dc->props = mch_props;
|
||||
dc->props = q35_host_props;
|
||||
/* Reason: needs to be wired up by pc_q35_init */
|
||||
dc->user_creatable = false;
|
||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||
@@ -173,26 +172,26 @@ static void q35_host_initfn(Object *obj)
|
||||
|
||||
object_initialize(&s->mch, sizeof(s->mch), TYPE_MCH_PCI_DEVICE);
|
||||
object_property_add_child(OBJECT(s), "mch", OBJECT(&s->mch), NULL);
|
||||
qdev_prop_set_uint32(DEVICE(&s->mch), "addr", PCI_DEVFN(0, 0));
|
||||
qdev_prop_set_int32(DEVICE(&s->mch), "addr", PCI_DEVFN(0, 0));
|
||||
qdev_prop_set_bit(DEVICE(&s->mch), "multifunction", false);
|
||||
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "int",
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "uint32",
|
||||
q35_host_get_pci_hole_start,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_END, "int",
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_END, "uint32",
|
||||
q35_host_get_pci_hole_end,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_START, "int",
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_START, "uint64",
|
||||
q35_host_get_pci_hole64_start,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "int",
|
||||
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "uint64",
|
||||
q35_host_get_pci_hole64_end,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
object_property_add(obj, PCIE_HOST_MCFG_SIZE, "int",
|
||||
object_property_add(obj, PCIE_HOST_MCFG_SIZE, "uint64",
|
||||
q35_host_get_mmcfg_size,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
@@ -369,7 +368,7 @@ static void mch_update_smram(MCHPCIState *mch)
|
||||
tseg_size = 1024 * 1024 * 8;
|
||||
break;
|
||||
default:
|
||||
tseg_size = 0;
|
||||
tseg_size = 1024 * 1024 * (uint32_t)mch->ext_tseg_mbytes;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -392,6 +391,17 @@ static void mch_update_smram(MCHPCIState *mch)
|
||||
memory_region_transaction_commit();
|
||||
}
|
||||
|
||||
static void mch_update_ext_tseg_mbytes(MCHPCIState *mch)
|
||||
{
|
||||
PCIDevice *pd = PCI_DEVICE(mch);
|
||||
uint8_t *reg = pd->config + MCH_HOST_BRIDGE_EXT_TSEG_MBYTES;
|
||||
|
||||
if (mch->ext_tseg_mbytes > 0 &&
|
||||
pci_get_word(reg) == MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_QUERY) {
|
||||
pci_set_word(reg, mch->ext_tseg_mbytes);
|
||||
}
|
||||
}
|
||||
|
||||
static void mch_write_config(PCIDevice *d,
|
||||
uint32_t address, uint32_t val, int len)
|
||||
{
|
||||
@@ -413,6 +423,11 @@ static void mch_write_config(PCIDevice *d,
|
||||
MCH_HOST_BRIDGE_SMRAM_SIZE)) {
|
||||
mch_update_smram(mch);
|
||||
}
|
||||
|
||||
if (ranges_overlap(address, len, MCH_HOST_BRIDGE_EXT_TSEG_MBYTES,
|
||||
MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_SIZE)) {
|
||||
mch_update_ext_tseg_mbytes(mch);
|
||||
}
|
||||
}
|
||||
|
||||
static void mch_update(MCHPCIState *mch)
|
||||
@@ -420,6 +435,7 @@ static void mch_update(MCHPCIState *mch)
|
||||
mch_update_pciexbar(mch);
|
||||
mch_update_pam(mch);
|
||||
mch_update_smram(mch);
|
||||
mch_update_ext_tseg_mbytes(mch);
|
||||
}
|
||||
|
||||
static int mch_post_load(void *opaque, int version_id)
|
||||
@@ -457,6 +473,11 @@ static void mch_reset(DeviceState *qdev)
|
||||
d->wmask[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_WMASK;
|
||||
d->wmask[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_WMASK;
|
||||
|
||||
if (mch->ext_tseg_mbytes > 0) {
|
||||
pci_set_word(d->config + MCH_HOST_BRIDGE_EXT_TSEG_MBYTES,
|
||||
MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_QUERY);
|
||||
}
|
||||
|
||||
mch_update(mch);
|
||||
}
|
||||
|
||||
@@ -465,6 +486,12 @@ static void mch_realize(PCIDevice *d, Error **errp)
|
||||
int i;
|
||||
MCHPCIState *mch = MCH_PCI_DEVICE(d);
|
||||
|
||||
if (mch->ext_tseg_mbytes > MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_MAX) {
|
||||
error_setg(errp, "invalid extended-tseg-mbytes value: %" PRIu16,
|
||||
mch->ext_tseg_mbytes);
|
||||
return;
|
||||
}
|
||||
|
||||
/* setup pci memory mapping */
|
||||
pc_pci_as_mapping_init(OBJECT(mch), mch->system_memory,
|
||||
mch->pci_address_space);
|
||||
@@ -530,6 +557,12 @@ uint64_t mch_mcfg_base(void)
|
||||
return MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT;
|
||||
}
|
||||
|
||||
static Property mch_props[] = {
|
||||
DEFINE_PROP_UINT16("extended-tseg-mbytes", MCHPCIState, ext_tseg_mbytes,
|
||||
16),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void mch_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
@@ -538,6 +571,7 @@ static void mch_class_init(ObjectClass *klass, void *data)
|
||||
k->realize = mch_realize;
|
||||
k->config_write = mch_write_config;
|
||||
dc->reset = mch_reset;
|
||||
dc->props = mch_props;
|
||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||
dc->desc = "Host bridge";
|
||||
dc->vmsd = &vmstate_mch;
|
||||
|
@@ -150,7 +150,7 @@ static void xilinx_pcie_host_init(Object *obj)
|
||||
|
||||
object_initialize(root, sizeof(*root), TYPE_XILINX_PCIE_ROOT);
|
||||
object_property_add_child(obj, "root", OBJECT(root), NULL);
|
||||
qdev_prop_set_uint32(DEVICE(root), "addr", PCI_DEVFN(0, 0));
|
||||
qdev_prop_set_int32(DEVICE(root), "addr", PCI_DEVFN(0, 0));
|
||||
qdev_prop_set_bit(DEVICE(root), "multifunction", false);
|
||||
}
|
||||
|
||||
|
@@ -1111,7 +1111,7 @@ static void powernv_machine_initfn(Object *obj)
|
||||
|
||||
static void powernv_machine_class_props_init(ObjectClass *oc)
|
||||
{
|
||||
object_class_property_add(oc, "num-chips", "uint32_t",
|
||||
object_class_property_add(oc, "num-chips", "uint32",
|
||||
pnv_get_num_chips, pnv_set_num_chips,
|
||||
NULL, NULL, NULL);
|
||||
object_class_property_set_description(oc, "num-chips",
|
||||
|
@@ -51,7 +51,7 @@ static void powernv_cpu_init(PowerPCCPU *cpu, Error **errp)
|
||||
int thread_index = 0; /* TODO: TCG supports only one thread */
|
||||
ppc_spr_t *pir = &env->spr_cb[SPR_PIR];
|
||||
|
||||
core_pir = object_property_get_int(OBJECT(cpu), "core-pir", &error_abort);
|
||||
core_pir = object_property_get_uint(OBJECT(cpu), "core-pir", &error_abort);
|
||||
|
||||
/*
|
||||
* The PIR of a thread is the core PIR + the thread index. We will
|
||||
|
@@ -2589,7 +2589,8 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
addr = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP, &local_err);
|
||||
addr = object_property_get_uint(OBJECT(dimm),
|
||||
PC_DIMM_ADDR_PROP, &local_err);
|
||||
if (local_err) {
|
||||
pc_dimm_memory_unplug(dev, &ms->hotplug_memory, mr);
|
||||
goto out;
|
||||
@@ -2751,7 +2752,7 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
|
||||
sPAPRDRConnector *drc;
|
||||
sPAPRDIMMState *ds;
|
||||
|
||||
addr_start = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP,
|
||||
addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
@@ -2986,7 +2987,7 @@ static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
|
||||
error_setg(errp, "Memory hotplug not supported for this machine");
|
||||
return;
|
||||
}
|
||||
node = object_property_get_int(OBJECT(dev), PC_DIMM_NODE_PROP, errp);
|
||||
node = object_property_get_uint(OBJECT(dev), PC_DIMM_NODE_PROP, errp);
|
||||
if (*errp) {
|
||||
return;
|
||||
}
|
||||
|
@@ -11,4 +11,5 @@ obj-$(CONFIG_PSERIES) += spapr_vscsi.o
|
||||
ifeq ($(CONFIG_VIRTIO),y)
|
||||
obj-y += virtio-scsi.o virtio-scsi-dataplane.o
|
||||
obj-$(CONFIG_VHOST_SCSI) += vhost-scsi-common.o vhost-scsi.o
|
||||
obj-$(CONFIG_VHOST_USER_SCSI) += vhost-scsi-common.o vhost-user-scsi.o
|
||||
endif
|
||||
|
@@ -63,6 +63,7 @@ typedef struct MegasasCmd {
|
||||
|
||||
hwaddr pa;
|
||||
hwaddr pa_size;
|
||||
uint32_t dcmd_opcode;
|
||||
union mfi_frame *frame;
|
||||
SCSIRequest *req;
|
||||
QEMUSGList qsg;
|
||||
@@ -309,9 +310,11 @@ static int megasas_build_sense(MegasasCmd *cmd, uint8_t *sense_ptr,
|
||||
PCIDevice *pcid = PCI_DEVICE(cmd->state);
|
||||
uint32_t pa_hi = 0, pa_lo;
|
||||
hwaddr pa;
|
||||
int frame_sense_len;
|
||||
|
||||
if (sense_len > cmd->frame->header.sense_len) {
|
||||
sense_len = cmd->frame->header.sense_len;
|
||||
frame_sense_len = cmd->frame->header.sense_len;
|
||||
if (sense_len > frame_sense_len) {
|
||||
sense_len = frame_sense_len;
|
||||
}
|
||||
if (sense_len) {
|
||||
pa_lo = le32_to_cpu(cmd->frame->pass.sense_addr_lo);
|
||||
@@ -511,6 +514,7 @@ static MegasasCmd *megasas_enqueue_frame(MegasasState *s,
|
||||
cmd->context &= (uint64_t)0xFFFFFFFF;
|
||||
}
|
||||
cmd->count = count;
|
||||
cmd->dcmd_opcode = -1;
|
||||
s->busy++;
|
||||
|
||||
if (s->consumer_pa) {
|
||||
@@ -605,6 +609,9 @@ static void megasas_reset_frames(MegasasState *s)
|
||||
static void megasas_abort_command(MegasasCmd *cmd)
|
||||
{
|
||||
/* Never abort internal commands. */
|
||||
if (cmd->dcmd_opcode != -1) {
|
||||
return;
|
||||
}
|
||||
if (cmd->req != NULL) {
|
||||
scsi_req_cancel(cmd->req);
|
||||
}
|
||||
@@ -673,15 +680,16 @@ out:
|
||||
static int megasas_map_dcmd(MegasasState *s, MegasasCmd *cmd)
|
||||
{
|
||||
dma_addr_t iov_pa, iov_size;
|
||||
int iov_count;
|
||||
|
||||
cmd->flags = le16_to_cpu(cmd->frame->header.flags);
|
||||
if (!cmd->frame->header.sge_count) {
|
||||
iov_count = cmd->frame->header.sge_count;
|
||||
if (!iov_count) {
|
||||
trace_megasas_dcmd_zero_sge(cmd->index);
|
||||
cmd->iov_size = 0;
|
||||
return 0;
|
||||
} else if (cmd->frame->header.sge_count > 1) {
|
||||
trace_megasas_dcmd_invalid_sge(cmd->index,
|
||||
cmd->frame->header.sge_count);
|
||||
} else if (iov_count > 1) {
|
||||
trace_megasas_dcmd_invalid_sge(cmd->index, iov_count);
|
||||
cmd->iov_size = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1012,7 +1020,6 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
uint64_t pd_size;
|
||||
uint16_t pd_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
|
||||
uint8_t cmdbuf[6];
|
||||
SCSIRequest *req;
|
||||
size_t len, resid;
|
||||
|
||||
if (!cmd->iov_buf) {
|
||||
@@ -1021,8 +1028,8 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */
|
||||
info->vpd_page83[0] = 0x7f;
|
||||
megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data));
|
||||
req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
|
||||
if (!req) {
|
||||
cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
|
||||
if (!cmd->req) {
|
||||
trace_megasas_dcmd_req_alloc_failed(cmd->index,
|
||||
"PD get info std inquiry");
|
||||
g_free(cmd->iov_buf);
|
||||
@@ -1031,26 +1038,26 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
}
|
||||
trace_megasas_dcmd_internal_submit(cmd->index,
|
||||
"PD get info std inquiry", lun);
|
||||
len = scsi_req_enqueue(req);
|
||||
len = scsi_req_enqueue(cmd->req);
|
||||
if (len > 0) {
|
||||
cmd->iov_size = len;
|
||||
scsi_req_continue(req);
|
||||
scsi_req_continue(cmd->req);
|
||||
}
|
||||
return MFI_STAT_INVALID_STATUS;
|
||||
} else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) {
|
||||
megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83));
|
||||
req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
|
||||
if (!req) {
|
||||
cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
|
||||
if (!cmd->req) {
|
||||
trace_megasas_dcmd_req_alloc_failed(cmd->index,
|
||||
"PD get info vpd inquiry");
|
||||
return MFI_STAT_FLASH_ALLOC_FAIL;
|
||||
}
|
||||
trace_megasas_dcmd_internal_submit(cmd->index,
|
||||
"PD get info vpd inquiry", lun);
|
||||
len = scsi_req_enqueue(req);
|
||||
len = scsi_req_enqueue(cmd->req);
|
||||
if (len > 0) {
|
||||
cmd->iov_size = len;
|
||||
scsi_req_continue(req);
|
||||
scsi_req_continue(cmd->req);
|
||||
}
|
||||
return MFI_STAT_INVALID_STATUS;
|
||||
}
|
||||
@@ -1212,7 +1219,6 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
struct mfi_ld_info *info = cmd->iov_buf;
|
||||
size_t dcmd_size = sizeof(struct mfi_ld_info);
|
||||
uint8_t cdb[6];
|
||||
SCSIRequest *req;
|
||||
ssize_t len, resid;
|
||||
uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
|
||||
uint64_t ld_size;
|
||||
@@ -1221,8 +1227,8 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
cmd->iov_buf = g_malloc0(dcmd_size);
|
||||
info = cmd->iov_buf;
|
||||
megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83));
|
||||
req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
|
||||
if (!req) {
|
||||
cmd->req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
|
||||
if (!cmd->req) {
|
||||
trace_megasas_dcmd_req_alloc_failed(cmd->index,
|
||||
"LD get info vpd inquiry");
|
||||
g_free(cmd->iov_buf);
|
||||
@@ -1231,10 +1237,10 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
}
|
||||
trace_megasas_dcmd_internal_submit(cmd->index,
|
||||
"LD get info vpd inquiry", lun);
|
||||
len = scsi_req_enqueue(req);
|
||||
len = scsi_req_enqueue(cmd->req);
|
||||
if (len > 0) {
|
||||
cmd->iov_size = len;
|
||||
scsi_req_continue(req);
|
||||
scsi_req_continue(cmd->req);
|
||||
}
|
||||
return MFI_STAT_INVALID_STATUS;
|
||||
}
|
||||
@@ -1559,22 +1565,21 @@ static const struct dcmd_cmd_tbl_t {
|
||||
|
||||
static int megasas_handle_dcmd(MegasasState *s, MegasasCmd *cmd)
|
||||
{
|
||||
int opcode;
|
||||
int retval = 0;
|
||||
size_t len;
|
||||
const struct dcmd_cmd_tbl_t *cmdptr = dcmd_cmd_tbl;
|
||||
|
||||
opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
|
||||
trace_megasas_handle_dcmd(cmd->index, opcode);
|
||||
cmd->dcmd_opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
|
||||
trace_megasas_handle_dcmd(cmd->index, cmd->dcmd_opcode);
|
||||
if (megasas_map_dcmd(s, cmd) < 0) {
|
||||
return MFI_STAT_MEMORY_NOT_AVAILABLE;
|
||||
}
|
||||
while (cmdptr->opcode != -1 && cmdptr->opcode != opcode) {
|
||||
while (cmdptr->opcode != -1 && cmdptr->opcode != cmd->dcmd_opcode) {
|
||||
cmdptr++;
|
||||
}
|
||||
len = cmd->iov_size;
|
||||
if (cmdptr->opcode == -1) {
|
||||
trace_megasas_dcmd_unhandled(cmd->index, opcode, len);
|
||||
trace_megasas_dcmd_unhandled(cmd->index, cmd->dcmd_opcode, len);
|
||||
retval = megasas_dcmd_dummy(s, cmd);
|
||||
} else {
|
||||
trace_megasas_dcmd_enter(cmd->index, cmdptr->desc, len);
|
||||
@@ -1587,15 +1592,14 @@ static int megasas_handle_dcmd(MegasasState *s, MegasasCmd *cmd)
|
||||
}
|
||||
|
||||
static int megasas_finish_internal_dcmd(MegasasCmd *cmd,
|
||||
SCSIRequest *req)
|
||||
SCSIRequest *req, size_t resid)
|
||||
{
|
||||
int opcode;
|
||||
int retval = MFI_STAT_OK;
|
||||
int lun = req->lun;
|
||||
|
||||
opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
|
||||
trace_megasas_dcmd_internal_finish(cmd->index, opcode, lun);
|
||||
switch (opcode) {
|
||||
trace_megasas_dcmd_internal_finish(cmd->index, cmd->dcmd_opcode, lun);
|
||||
cmd->iov_size -= resid;
|
||||
switch (cmd->dcmd_opcode) {
|
||||
case MFI_DCMD_PD_GET_INFO:
|
||||
retval = megasas_pd_get_info_submit(req->dev, lun, cmd);
|
||||
break;
|
||||
@@ -1603,7 +1607,7 @@ static int megasas_finish_internal_dcmd(MegasasCmd *cmd,
|
||||
retval = megasas_ld_get_info_submit(req->dev, lun, cmd);
|
||||
break;
|
||||
default:
|
||||
trace_megasas_dcmd_internal_invalid(cmd->index, opcode);
|
||||
trace_megasas_dcmd_internal_invalid(cmd->index, cmd->dcmd_opcode);
|
||||
retval = MFI_STAT_INVALID_DCMD;
|
||||
break;
|
||||
}
|
||||
@@ -1647,43 +1651,42 @@ static int megasas_enqueue_req(MegasasCmd *cmd, bool is_write)
|
||||
}
|
||||
|
||||
static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd,
|
||||
bool is_logical)
|
||||
int frame_cmd)
|
||||
{
|
||||
uint8_t *cdb;
|
||||
int target_id, lun_id, cdb_len;
|
||||
bool is_write;
|
||||
struct SCSIDevice *sdev = NULL;
|
||||
bool is_logical = (frame_cmd == MFI_CMD_LD_SCSI_IO);
|
||||
|
||||
cdb = cmd->frame->pass.cdb;
|
||||
target_id = cmd->frame->header.target_id;
|
||||
lun_id = cmd->frame->header.lun_id;
|
||||
cdb_len = cmd->frame->header.cdb_len;
|
||||
|
||||
if (is_logical) {
|
||||
if (cmd->frame->header.target_id >= MFI_MAX_LD ||
|
||||
cmd->frame->header.lun_id != 0) {
|
||||
if (target_id >= MFI_MAX_LD || lun_id != 0) {
|
||||
trace_megasas_scsi_target_not_present(
|
||||
mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical,
|
||||
cmd->frame->header.target_id, cmd->frame->header.lun_id);
|
||||
mfi_frame_desc[frame_cmd], is_logical, target_id, lun_id);
|
||||
return MFI_STAT_DEVICE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
|
||||
cmd->frame->header.lun_id);
|
||||
sdev = scsi_device_find(&s->bus, 0, target_id, lun_id);
|
||||
|
||||
cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len);
|
||||
trace_megasas_handle_scsi(mfi_frame_desc[cmd->frame->header.frame_cmd],
|
||||
is_logical, cmd->frame->header.target_id,
|
||||
cmd->frame->header.lun_id, sdev, cmd->iov_size);
|
||||
trace_megasas_handle_scsi(mfi_frame_desc[frame_cmd], is_logical,
|
||||
target_id, lun_id, sdev, cmd->iov_size);
|
||||
|
||||
if (!sdev || (megasas_is_jbod(s) && is_logical)) {
|
||||
trace_megasas_scsi_target_not_present(
|
||||
mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical,
|
||||
cmd->frame->header.target_id, cmd->frame->header.lun_id);
|
||||
mfi_frame_desc[frame_cmd], is_logical, target_id, lun_id);
|
||||
return MFI_STAT_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (cmd->frame->header.cdb_len > 16) {
|
||||
if (cdb_len > 16) {
|
||||
trace_megasas_scsi_invalid_cdb_len(
|
||||
mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical,
|
||||
cmd->frame->header.target_id, cmd->frame->header.lun_id,
|
||||
cmd->frame->header.cdb_len);
|
||||
mfi_frame_desc[frame_cmd], is_logical,
|
||||
target_id, lun_id, cdb_len);
|
||||
megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE));
|
||||
cmd->frame->header.scsi_status = CHECK_CONDITION;
|
||||
s->event_count++;
|
||||
@@ -1697,12 +1700,10 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd,
|
||||
return MFI_STAT_SCSI_DONE_WITH_ERROR;
|
||||
}
|
||||
|
||||
cmd->req = scsi_req_new(sdev, cmd->index,
|
||||
cmd->frame->header.lun_id, cdb, cmd);
|
||||
cmd->req = scsi_req_new(sdev, cmd->index, lun_id, cdb, cmd);
|
||||
if (!cmd->req) {
|
||||
trace_megasas_scsi_req_alloc_failed(
|
||||
mfi_frame_desc[cmd->frame->header.frame_cmd],
|
||||
cmd->frame->header.target_id, cmd->frame->header.lun_id);
|
||||
mfi_frame_desc[frame_cmd], target_id, lun_id);
|
||||
megasas_write_sense(cmd, SENSE_CODE(NO_SENSE));
|
||||
cmd->frame->header.scsi_status = BUSY;
|
||||
s->event_count++;
|
||||
@@ -1723,43 +1724,41 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd,
|
||||
return MFI_STAT_INVALID_STATUS;
|
||||
}
|
||||
|
||||
static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd)
|
||||
static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd)
|
||||
{
|
||||
uint32_t lba_count, lba_start_hi, lba_start_lo;
|
||||
uint64_t lba_start;
|
||||
bool is_write = (cmd->frame->header.frame_cmd == MFI_CMD_LD_WRITE);
|
||||
bool is_write = (frame_cmd == MFI_CMD_LD_WRITE);
|
||||
uint8_t cdb[16];
|
||||
int len;
|
||||
struct SCSIDevice *sdev = NULL;
|
||||
int target_id, lun_id, cdb_len;
|
||||
|
||||
lba_count = le32_to_cpu(cmd->frame->io.header.data_len);
|
||||
lba_start_lo = le32_to_cpu(cmd->frame->io.lba_lo);
|
||||
lba_start_hi = le32_to_cpu(cmd->frame->io.lba_hi);
|
||||
lba_start = ((uint64_t)lba_start_hi << 32) | lba_start_lo;
|
||||
|
||||
if (cmd->frame->header.target_id < MFI_MAX_LD &&
|
||||
cmd->frame->header.lun_id == 0) {
|
||||
sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
|
||||
cmd->frame->header.lun_id);
|
||||
target_id = cmd->frame->header.target_id;
|
||||
lun_id = cmd->frame->header.lun_id;
|
||||
cdb_len = cmd->frame->header.cdb_len;
|
||||
|
||||
if (target_id < MFI_MAX_LD && lun_id == 0) {
|
||||
sdev = scsi_device_find(&s->bus, 0, target_id, lun_id);
|
||||
}
|
||||
|
||||
trace_megasas_handle_io(cmd->index,
|
||||
mfi_frame_desc[cmd->frame->header.frame_cmd],
|
||||
cmd->frame->header.target_id,
|
||||
cmd->frame->header.lun_id,
|
||||
mfi_frame_desc[frame_cmd], target_id, lun_id,
|
||||
(unsigned long)lba_start, (unsigned long)lba_count);
|
||||
if (!sdev) {
|
||||
trace_megasas_io_target_not_present(cmd->index,
|
||||
mfi_frame_desc[cmd->frame->header.frame_cmd],
|
||||
cmd->frame->header.target_id, cmd->frame->header.lun_id);
|
||||
mfi_frame_desc[frame_cmd], target_id, lun_id);
|
||||
return MFI_STAT_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (cmd->frame->header.cdb_len > 16) {
|
||||
if (cdb_len > 16) {
|
||||
trace_megasas_scsi_invalid_cdb_len(
|
||||
mfi_frame_desc[cmd->frame->header.frame_cmd], 1,
|
||||
cmd->frame->header.target_id, cmd->frame->header.lun_id,
|
||||
cmd->frame->header.cdb_len);
|
||||
mfi_frame_desc[frame_cmd], 1, target_id, lun_id, cdb_len);
|
||||
megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE));
|
||||
cmd->frame->header.scsi_status = CHECK_CONDITION;
|
||||
s->event_count++;
|
||||
@@ -1776,11 +1775,10 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd)
|
||||
|
||||
megasas_encode_lba(cdb, lba_start, lba_count, is_write);
|
||||
cmd->req = scsi_req_new(sdev, cmd->index,
|
||||
cmd->frame->header.lun_id, cdb, cmd);
|
||||
lun_id, cdb, cmd);
|
||||
if (!cmd->req) {
|
||||
trace_megasas_scsi_req_alloc_failed(
|
||||
mfi_frame_desc[cmd->frame->header.frame_cmd],
|
||||
cmd->frame->header.target_id, cmd->frame->header.lun_id);
|
||||
mfi_frame_desc[frame_cmd], target_id, lun_id);
|
||||
megasas_write_sense(cmd, SENSE_CODE(NO_SENSE));
|
||||
cmd->frame->header.scsi_status = BUSY;
|
||||
s->event_count++;
|
||||
@@ -1797,23 +1795,11 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd)
|
||||
return MFI_STAT_INVALID_STATUS;
|
||||
}
|
||||
|
||||
static int megasas_finish_internal_command(MegasasCmd *cmd,
|
||||
SCSIRequest *req, size_t resid)
|
||||
{
|
||||
int retval = MFI_STAT_INVALID_CMD;
|
||||
|
||||
if (cmd->frame->header.frame_cmd == MFI_CMD_DCMD) {
|
||||
cmd->iov_size -= resid;
|
||||
retval = megasas_finish_internal_dcmd(cmd, req);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static QEMUSGList *megasas_get_sg_list(SCSIRequest *req)
|
||||
{
|
||||
MegasasCmd *cmd = req->hba_private;
|
||||
|
||||
if (cmd->frame->header.frame_cmd == MFI_CMD_DCMD) {
|
||||
if (cmd->dcmd_opcode != -1) {
|
||||
return NULL;
|
||||
} else {
|
||||
return &cmd->qsg;
|
||||
@@ -1824,18 +1810,16 @@ static void megasas_xfer_complete(SCSIRequest *req, uint32_t len)
|
||||
{
|
||||
MegasasCmd *cmd = req->hba_private;
|
||||
uint8_t *buf;
|
||||
uint32_t opcode;
|
||||
|
||||
trace_megasas_io_complete(cmd->index, len);
|
||||
|
||||
if (cmd->frame->header.frame_cmd != MFI_CMD_DCMD) {
|
||||
if (cmd->dcmd_opcode != -1) {
|
||||
scsi_req_continue(req);
|
||||
return;
|
||||
}
|
||||
|
||||
buf = scsi_req_get_buf(req);
|
||||
opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
|
||||
if (opcode == MFI_DCMD_PD_GET_INFO && cmd->iov_buf) {
|
||||
if (cmd->dcmd_opcode == MFI_DCMD_PD_GET_INFO && cmd->iov_buf) {
|
||||
struct mfi_pd_info *info = cmd->iov_buf;
|
||||
|
||||
if (info->inquiry_data[0] == 0x7f) {
|
||||
@@ -1846,7 +1830,7 @@ static void megasas_xfer_complete(SCSIRequest *req, uint32_t len)
|
||||
memcpy(info->vpd_page83, buf, len);
|
||||
}
|
||||
scsi_req_continue(req);
|
||||
} else if (opcode == MFI_DCMD_LD_GET_INFO) {
|
||||
} else if (cmd->dcmd_opcode == MFI_DCMD_LD_GET_INFO) {
|
||||
struct mfi_ld_info *info = cmd->iov_buf;
|
||||
|
||||
if (cmd->iov_buf) {
|
||||
@@ -1868,11 +1852,11 @@ static void megasas_command_complete(SCSIRequest *req, uint32_t status,
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd->req == NULL) {
|
||||
if (cmd->dcmd_opcode != -1) {
|
||||
/*
|
||||
* Internal command complete
|
||||
*/
|
||||
cmd_status = megasas_finish_internal_command(cmd, req, resid);
|
||||
cmd_status = megasas_finish_internal_dcmd(cmd, req, resid);
|
||||
if (cmd_status == MFI_STAT_INVALID_STATUS) {
|
||||
return;
|
||||
}
|
||||
@@ -1943,6 +1927,7 @@ static void megasas_handle_frame(MegasasState *s, uint64_t frame_addr,
|
||||
{
|
||||
uint8_t frame_status = MFI_STAT_INVALID_CMD;
|
||||
uint64_t frame_context;
|
||||
int frame_cmd;
|
||||
MegasasCmd *cmd;
|
||||
|
||||
/*
|
||||
@@ -1961,7 +1946,8 @@ static void megasas_handle_frame(MegasasState *s, uint64_t frame_addr,
|
||||
s->event_count++;
|
||||
return;
|
||||
}
|
||||
switch (cmd->frame->header.frame_cmd) {
|
||||
frame_cmd = cmd->frame->header.frame_cmd;
|
||||
switch (frame_cmd) {
|
||||
case MFI_CMD_INIT:
|
||||
frame_status = megasas_init_firmware(s, cmd);
|
||||
break;
|
||||
@@ -1972,18 +1958,15 @@ static void megasas_handle_frame(MegasasState *s, uint64_t frame_addr,
|
||||
frame_status = megasas_handle_abort(s, cmd);
|
||||
break;
|
||||
case MFI_CMD_PD_SCSI_IO:
|
||||
frame_status = megasas_handle_scsi(s, cmd, 0);
|
||||
break;
|
||||
case MFI_CMD_LD_SCSI_IO:
|
||||
frame_status = megasas_handle_scsi(s, cmd, 1);
|
||||
frame_status = megasas_handle_scsi(s, cmd, frame_cmd);
|
||||
break;
|
||||
case MFI_CMD_LD_READ:
|
||||
case MFI_CMD_LD_WRITE:
|
||||
frame_status = megasas_handle_io(s, cmd);
|
||||
frame_status = megasas_handle_io(s, cmd, frame_cmd);
|
||||
break;
|
||||
default:
|
||||
trace_megasas_unhandled_frame_cmd(cmd->index,
|
||||
cmd->frame->header.frame_cmd);
|
||||
trace_megasas_unhandled_frame_cmd(cmd->index, frame_cmd);
|
||||
s->event_count++;
|
||||
break;
|
||||
}
|
||||
|
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <linux/vhost.h>
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "migration/migration.h"
|
||||
|
205
hw/scsi/vhost-user-scsi.c
Normal file
205
hw/scsi/vhost-user-scsi.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* vhost-user-scsi host device
|
||||
*
|
||||
* Copyright (c) 2016 Nutanix Inc. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Felipe Franciosi <felipe@nutanix.com>
|
||||
*
|
||||
* This work is largely based on the "vhost-scsi" implementation by:
|
||||
* Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
|
||||
* Nicholas Bellinger <nab@risingtidesystems.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/typedefs.h"
|
||||
#include "qom/object.h"
|
||||
#include "hw/fw-path-provider.h"
|
||||
#include "hw/qdev-core.h"
|
||||
#include "hw/virtio/vhost.h"
|
||||
#include "hw/virtio/vhost-backend.h"
|
||||
#include "hw/virtio/vhost-user-scsi.h"
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
#include "chardev/char-fe.h"
|
||||
|
||||
/* Features supported by the host application */
|
||||
static const int user_feature_bits[] = {
|
||||
VIRTIO_F_NOTIFY_ON_EMPTY,
|
||||
VIRTIO_RING_F_INDIRECT_DESC,
|
||||
VIRTIO_RING_F_EVENT_IDX,
|
||||
VIRTIO_SCSI_F_HOTPLUG,
|
||||
VHOST_INVALID_FEATURE_BIT
|
||||
};
|
||||
|
||||
static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status)
|
||||
{
|
||||
VHostUserSCSI *s = (VHostUserSCSI *)vdev;
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
|
||||
bool start = (status & VIRTIO_CONFIG_S_DRIVER_OK) && vdev->vm_running;
|
||||
|
||||
if (vsc->dev.started == start) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (start) {
|
||||
int ret;
|
||||
|
||||
ret = vhost_scsi_common_start(vsc);
|
||||
if (ret < 0) {
|
||||
error_report("unable to start vhost-user-scsi: %s", strerror(-ret));
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
vhost_scsi_common_stop(vsc);
|
||||
}
|
||||
}
|
||||
|
||||
static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
}
|
||||
|
||||
static void vhost_user_scsi_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
|
||||
VHostUserSCSI *s = VHOST_USER_SCSI(dev);
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
|
||||
Error *err = NULL;
|
||||
int ret;
|
||||
|
||||
if (!vs->conf.chardev.chr) {
|
||||
error_setg(errp, "vhost-user-scsi: missing chardev");
|
||||
return;
|
||||
}
|
||||
|
||||
virtio_scsi_common_realize(dev, vhost_dummy_handle_output,
|
||||
vhost_dummy_handle_output,
|
||||
vhost_dummy_handle_output, &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
vsc->dev.nvqs = 2 + vs->conf.num_queues;
|
||||
vsc->dev.vqs = g_new(struct vhost_virtqueue, vsc->dev.nvqs);
|
||||
vsc->dev.vq_index = 0;
|
||||
vsc->dev.backend_features = 0;
|
||||
|
||||
ret = vhost_dev_init(&vsc->dev, (void *)&vs->conf.chardev,
|
||||
VHOST_BACKEND_TYPE_USER, 0);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "vhost-user-scsi: vhost initialization failed: %s",
|
||||
strerror(-ret));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Channel and lun both are 0 for bootable vhost-user-scsi disk */
|
||||
vsc->channel = 0;
|
||||
vsc->lun = 0;
|
||||
vsc->target = vs->conf.boot_tpgt;
|
||||
}
|
||||
|
||||
static void vhost_user_scsi_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VHostUserSCSI *s = VHOST_USER_SCSI(dev);
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
|
||||
|
||||
/* This will stop the vhost backend. */
|
||||
vhost_user_scsi_set_status(vdev, 0);
|
||||
|
||||
vhost_dev_cleanup(&vsc->dev);
|
||||
g_free(vsc->dev.vqs);
|
||||
|
||||
virtio_scsi_common_unrealize(dev, errp);
|
||||
}
|
||||
|
||||
static uint64_t vhost_user_scsi_get_features(VirtIODevice *vdev,
|
||||
uint64_t features, Error **errp)
|
||||
{
|
||||
VHostUserSCSI *s = VHOST_USER_SCSI(vdev);
|
||||
|
||||
/* Turn on predefined features supported by this device */
|
||||
features |= s->host_features;
|
||||
|
||||
return vhost_scsi_common_get_features(vdev, features, errp);
|
||||
}
|
||||
|
||||
static Property vhost_user_scsi_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", VirtIOSCSICommon, conf.chardev),
|
||||
DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0),
|
||||
DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues, 1),
|
||||
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
|
||||
0xFFFF),
|
||||
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),
|
||||
DEFINE_PROP_BIT64("hotplug", VHostUserSCSI, host_features,
|
||||
VIRTIO_SCSI_F_HOTPLUG,
|
||||
true),
|
||||
DEFINE_PROP_BIT64("param_change", VHostUserSCSI, host_features,
|
||||
VIRTIO_SCSI_F_CHANGE,
|
||||
true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_vhost_scsi = {
|
||||
.name = "virtio-scsi",
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VIRTIO_DEVICE,
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static void vhost_user_scsi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(klass);
|
||||
|
||||
dc->props = vhost_user_scsi_properties;
|
||||
dc->vmsd = &vmstate_vhost_scsi;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
vdc->realize = vhost_user_scsi_realize;
|
||||
vdc->unrealize = vhost_user_scsi_unrealize;
|
||||
vdc->get_features = vhost_user_scsi_get_features;
|
||||
vdc->set_config = vhost_scsi_common_set_config;
|
||||
vdc->set_status = vhost_user_scsi_set_status;
|
||||
fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path;
|
||||
}
|
||||
|
||||
static void vhost_user_scsi_instance_init(Object *obj)
|
||||
{
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(obj);
|
||||
|
||||
vsc->feature_bits = user_feature_bits;
|
||||
|
||||
/* Add the bootindex property for this object */
|
||||
device_add_bootindex_property(obj, &vsc->bootindex, "bootindex", NULL,
|
||||
DEVICE(vsc), NULL);
|
||||
}
|
||||
|
||||
static const TypeInfo vhost_user_scsi_info = {
|
||||
.name = TYPE_VHOST_USER_SCSI,
|
||||
.parent = TYPE_VHOST_SCSI_COMMON,
|
||||
.instance_size = sizeof(VHostUserSCSI),
|
||||
.class_init = vhost_user_scsi_class_init,
|
||||
.instance_init = vhost_user_scsi_instance_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_FW_PATH_PROVIDER },
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static void virtio_register_types(void)
|
||||
{
|
||||
type_register_static(&vhost_user_scsi_info);
|
||||
}
|
||||
|
||||
type_init(virtio_register_types)
|
@@ -2241,6 +2241,11 @@ static void ehci_work_bh(void *opaque)
|
||||
uint64_t uframes, skipped_uframes;
|
||||
int i;
|
||||
|
||||
if (ehci->working) {
|
||||
return;
|
||||
}
|
||||
ehci->working = true;
|
||||
|
||||
t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
ns_elapsed = t_now - ehci->last_run_ns;
|
||||
uframes = ns_elapsed / UFRAME_TIMER_NS;
|
||||
@@ -2322,6 +2327,8 @@ static void ehci_work_bh(void *opaque)
|
||||
}
|
||||
timer_mod(ehci->frame_timer, expire_time);
|
||||
}
|
||||
|
||||
ehci->working = false;
|
||||
}
|
||||
|
||||
static void ehci_work_timer(void *opaque)
|
||||
|
@@ -297,6 +297,7 @@ struct EHCIState {
|
||||
*/
|
||||
QEMUTimer *frame_timer;
|
||||
QEMUBH *async_bh;
|
||||
bool working;
|
||||
uint32_t astate; /* Current state in asynchronous schedule */
|
||||
uint32_t pstate; /* Current state in periodic schedule */
|
||||
USBPort ports[NB_PORTS];
|
||||
|
@@ -1912,6 +1912,8 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
|
||||
}
|
||||
assert(!xfer->running_retry);
|
||||
if (xfer->complete) {
|
||||
/* update ring dequeue ptr */
|
||||
xhci_set_ep_state(xhci, epctx, stctx, epctx->state);
|
||||
xhci_ep_free_xfer(epctx->retry);
|
||||
}
|
||||
epctx->retry = NULL;
|
||||
@@ -1962,6 +1964,8 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
|
||||
xhci_fire_transfer(xhci, xfer, epctx);
|
||||
}
|
||||
if (xfer->complete) {
|
||||
/* update ring dequeue ptr */
|
||||
xhci_set_ep_state(xhci, epctx, stctx, epctx->state);
|
||||
xhci_ep_free_xfer(xfer);
|
||||
xfer = NULL;
|
||||
}
|
||||
@@ -1979,8 +1983,6 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* update ring dequeue ptr */
|
||||
xhci_set_ep_state(xhci, epctx, stctx, epctx->state);
|
||||
epctx->kick_active--;
|
||||
|
||||
ep = xhci_epid_to_usbep(epctx);
|
||||
|
@@ -1107,7 +1107,7 @@ static void usb_host_detach_kernel(USBHostDevice *s)
|
||||
if (rc != 0) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < conf->bNumInterfaces; i++) {
|
||||
for (i = 0; i < USB_MAX_INTERFACES; i++) {
|
||||
rc = libusb_kernel_driver_active(s->dh, i);
|
||||
usb_host_libusb_error("libusb_kernel_driver_active", rc);
|
||||
if (rc != 1) {
|
||||
@@ -1130,7 +1130,7 @@ static void usb_host_attach_kernel(USBHostDevice *s)
|
||||
if (rc != 0) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < conf->bNumInterfaces; i++) {
|
||||
for (i = 0; i < USB_MAX_INTERFACES; i++) {
|
||||
if (!s->ifs[i].detached) {
|
||||
continue;
|
||||
}
|
||||
@@ -1145,7 +1145,7 @@ static int usb_host_claim_interfaces(USBHostDevice *s, int configuration)
|
||||
{
|
||||
USBDevice *udev = USB_DEVICE(s);
|
||||
struct libusb_config_descriptor *conf;
|
||||
int rc, i;
|
||||
int rc, i, claimed;
|
||||
|
||||
for (i = 0; i < USB_MAX_INTERFACES; i++) {
|
||||
udev->altsetting[i] = 0;
|
||||
@@ -1164,14 +1164,19 @@ static int usb_host_claim_interfaces(USBHostDevice *s, int configuration)
|
||||
return USB_RET_STALL;
|
||||
}
|
||||
|
||||
for (i = 0; i < conf->bNumInterfaces; i++) {
|
||||
claimed = 0;
|
||||
for (i = 0; i < USB_MAX_INTERFACES; i++) {
|
||||
trace_usb_host_claim_interface(s->bus_num, s->addr, configuration, i);
|
||||
rc = libusb_claim_interface(s->dh, i);
|
||||
usb_host_libusb_error("libusb_claim_interface", rc);
|
||||
if (rc != 0) {
|
||||
return USB_RET_STALL;
|
||||
if (rc == 0) {
|
||||
s->ifs[i].claimed = true;
|
||||
if (++claimed == conf->bNumInterfaces) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
s->ifs[i].claimed = true;
|
||||
}
|
||||
if (claimed != conf->bNumInterfaces) {
|
||||
return USB_RET_STALL;
|
||||
}
|
||||
|
||||
udev->ninterfaces = conf->bNumInterfaces;
|
||||
@@ -1183,10 +1188,9 @@ static int usb_host_claim_interfaces(USBHostDevice *s, int configuration)
|
||||
|
||||
static void usb_host_release_interfaces(USBHostDevice *s)
|
||||
{
|
||||
USBDevice *udev = USB_DEVICE(s);
|
||||
int i, rc;
|
||||
|
||||
for (i = 0; i < udev->ninterfaces; i++) {
|
||||
for (i = 0; i < USB_MAX_INTERFACES; i++) {
|
||||
if (!s->ifs[i].claimed) {
|
||||
continue;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user