Compare commits
119 Commits
pull-conso
...
v2.0.2
Author | SHA1 | Date | |
---|---|---|---|
|
f053f6b83d | ||
|
3d79eb5b30 | ||
|
6ec48b09b7 | ||
|
543347215c | ||
|
3c548f6700 | ||
|
d0d83e8fe7 | ||
|
98103fa736 | ||
|
e5f0eb06a8 | ||
|
43ac708d4c | ||
|
8e09e2013d | ||
|
520b341264 | ||
|
e0efb023c0 | ||
|
d56b0b85c8 | ||
|
750f169519 | ||
|
046e357379 | ||
|
b1251db258 | ||
|
29cffd368a | ||
|
5a782bbcae | ||
|
ad0d183175 | ||
|
210ec8f757 | ||
|
55103ab3b4 | ||
|
3bb84a6c98 | ||
|
48935f029f | ||
|
3477445077 | ||
|
7be09afb61 | ||
|
cab7dfcb06 | ||
|
b5706a74b1 | ||
|
41971817a6 | ||
|
3f977a5be8 | ||
|
80cfe4a43f | ||
|
01083f16de | ||
|
9221efd775 | ||
|
4ce91be0c3 | ||
|
b2f0e9240b | ||
|
f9ac1dc507 | ||
|
a1d82075ab | ||
|
e4b3a2b349 | ||
|
84461c74b7 | ||
|
552e70d844 | ||
|
6ef0b7a992 | ||
|
aa69eda237 | ||
|
8dedaf0f70 | ||
|
eb3eb3dd36 | ||
|
88efef64db | ||
|
ab139bf9d2 | ||
|
d728dafe5a | ||
|
0f00455b4c | ||
|
6ea6bd5d75 | ||
|
86cfc10440 | ||
|
fe7e98c46e | ||
|
ba980a52d6 | ||
|
df54f5efed | ||
|
0d38666664 | ||
|
27fb65dd1b | ||
|
6ea80edc01 | ||
|
f99329cd82 | ||
|
207f61dc28 | ||
|
d1567e2980 | ||
|
5e3322eec3 | ||
|
5a0913f782 | ||
|
40a3fb54b2 | ||
|
98646a11d0 | ||
|
53bdfb5b62 | ||
|
a3e3f0964d | ||
|
7812cbe580 | ||
|
12d5fc6ab4 | ||
|
b203bba0ce | ||
|
91148decd2 | ||
|
ae2e18e0ca | ||
|
2dbd09ff5c | ||
|
3d5acbeb71 | ||
|
a4b73ed3f3 | ||
|
a3967c74de | ||
|
5c85998739 | ||
|
d234c8f1f6 | ||
|
3ba1e617e7 | ||
|
96e7f7a911 | ||
|
c230ab2ba2 | ||
|
274c96e4e1 | ||
|
32c113c182 | ||
|
912d9cc089 | ||
|
074f673a9a | ||
|
83b1dc162c | ||
|
c2d37222ae | ||
|
e40585f8f1 | ||
|
837e02ef07 | ||
|
46a1b0e489 | ||
|
a14d42919f | ||
|
2ac9549453 | ||
|
2f18e44b0c | ||
|
4c1e06408d | ||
|
4a7a497509 | ||
|
7dfa87e9cb | ||
|
7b0387ad90 | ||
|
1624861997 | ||
|
fb039011ff | ||
|
5ad12b3235 | ||
|
15c35dfd92 | ||
|
e7ff13929f | ||
|
894f179e8d | ||
|
2265c71b35 | ||
|
95d9149ed3 | ||
|
eb55958e18 | ||
|
1124696193 | ||
|
4e48018ae9 | ||
|
7297dba271 | ||
|
9c01a91c7b | ||
|
7cf5f5d087 | ||
|
f7ef3baa49 | ||
|
3c6066172f | ||
|
d4c9095900 | ||
|
331c549b2d | ||
|
b24cfb0f1e | ||
|
7872f3e77e | ||
|
390252193c | ||
|
49e8918a4d | ||
|
6067df7a5d | ||
|
9ee8ab5503 | ||
|
c8723d46c1 |
19
.gitignore
vendored
19
.gitignore
vendored
@@ -4,7 +4,6 @@
|
||||
/config-host.*
|
||||
/config-target.*
|
||||
/config.status
|
||||
/config-temp
|
||||
/trace/generated-tracers.h
|
||||
/trace/generated-tracers.c
|
||||
/trace/generated-tracers-dtrace.h
|
||||
@@ -19,8 +18,8 @@
|
||||
/*-darwin-user
|
||||
/*-linux-user
|
||||
/*-bsd-user
|
||||
/libdis*
|
||||
/libuser
|
||||
libdis*
|
||||
libuser
|
||||
/linux-headers/asm
|
||||
/qga/qapi-generated
|
||||
/qapi-generated
|
||||
@@ -50,9 +49,19 @@
|
||||
/qemu-monitor.texi
|
||||
/qmp-commands.txt
|
||||
/vscclient
|
||||
/test-bitops
|
||||
/test-coroutine
|
||||
/test-int128
|
||||
/test-opts-visitor
|
||||
/test-qmp-input-visitor
|
||||
/test-qmp-output-visitor
|
||||
/test-string-input-visitor
|
||||
/test-string-output-visitor
|
||||
/test-visitor-serialization
|
||||
/fsdev/virtfs-proxy-helper
|
||||
/fsdev/virtfs-proxy-helper.1
|
||||
/fsdev/virtfs-proxy-helper.pod
|
||||
/.gdbinit
|
||||
*.a
|
||||
*.aux
|
||||
*.cp
|
||||
@@ -81,8 +90,12 @@
|
||||
*.pc
|
||||
.libs
|
||||
.sdk
|
||||
*.swp
|
||||
*.orig
|
||||
.pc
|
||||
*.gcda
|
||||
*.gcno
|
||||
patches
|
||||
/pc-bios/bios-pq/status
|
||||
/pc-bios/vgabios-pq/status
|
||||
/pc-bios/optionrom/linuxboot.asm
|
||||
|
@@ -66,16 +66,16 @@ matrix:
|
||||
compiler: gcc
|
||||
# All the trace backends (apart from dtrace)
|
||||
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
||||
EXTRA_CONFIG="--enable-trace-backends=stderr"
|
||||
EXTRA_CONFIG="--enable-trace-backend=stderr"
|
||||
compiler: gcc
|
||||
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
||||
EXTRA_CONFIG="--enable-trace-backends=simple"
|
||||
EXTRA_CONFIG="--enable-trace-backend=simple"
|
||||
compiler: gcc
|
||||
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
||||
EXTRA_CONFIG="--enable-trace-backends=ftrace"
|
||||
EXTRA_CONFIG="--enable-trace-backend=ftrace"
|
||||
TEST_CMD=""
|
||||
compiler: gcc
|
||||
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
||||
EXTRA_PKGS="liblttng-ust-dev liburcu-dev"
|
||||
EXTRA_CONFIG="--enable-trace-backends=ust"
|
||||
EXTRA_CONFIG="--enable-trace-backend=ust"
|
||||
compiler: gcc
|
||||
|
34
MAINTAINERS
34
MAINTAINERS
@@ -52,13 +52,6 @@ General Project Administration
|
||||
------------------------------
|
||||
M: Anthony Liguori <aliguori@amazon.com>
|
||||
|
||||
Responsible Disclosure, Reporting Security Issues
|
||||
------------------------------
|
||||
W: http://wiki.qemu.org/SecurityProcess
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
M: Anthony Liguori <aliguori@amazon.com>
|
||||
L: secalert@redhat.com
|
||||
|
||||
Guest CPU cores (TCG):
|
||||
----------------------
|
||||
Alpha
|
||||
@@ -243,8 +236,8 @@ S: Maintained
|
||||
F: hw/*/exynos*
|
||||
|
||||
Calxeda Highbank
|
||||
M: Rob Herring <robh@kernel.org>
|
||||
S: Maintained
|
||||
M: Mark Langsdorf <mark.langsdorf@calxeda.com>
|
||||
S: Supported
|
||||
F: hw/arm/highbank.c
|
||||
F: hw/net/xgmac.c
|
||||
|
||||
@@ -608,7 +601,6 @@ USB
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Maintained
|
||||
F: hw/usb/*
|
||||
F: tests/usb-hcd-ehci-test.c
|
||||
|
||||
VFIO
|
||||
M: Alex Williamson <alex.williamson@redhat.com>
|
||||
@@ -659,12 +651,6 @@ S: Supported
|
||||
F: hw/block/nvme*
|
||||
F: tests/nvme-test.c
|
||||
|
||||
megasas
|
||||
M: Hannes Reinecke <hare@suse.de>
|
||||
S: Supported
|
||||
F: hw/scsi/megasas.c
|
||||
F: hw/scsi/mfi.h
|
||||
|
||||
Xilinx EDK
|
||||
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
@@ -680,9 +666,6 @@ M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Maintained
|
||||
F: audio/
|
||||
F: hw/audio/
|
||||
F: tests/ac97-test.c
|
||||
F: tests/es1370-test.c
|
||||
F: tests/intel-hda-test.c
|
||||
|
||||
Block
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
@@ -691,8 +674,6 @@ S: Supported
|
||||
F: block*
|
||||
F: block/
|
||||
F: hw/block/
|
||||
F: qemu-img*
|
||||
F: qemu-io*
|
||||
T: git git://repo.or.cz/qemu/kevin.git block
|
||||
T: git git://github.com/stefanha/qemu.git block
|
||||
|
||||
@@ -797,17 +778,6 @@ S: Supported
|
||||
F: qapi-schema.json
|
||||
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
|
||||
|
||||
QOM
|
||||
M: Anthony Liguori <aliguori@amazon.com>
|
||||
M: Andreas Färber <afaerber@suse.de>
|
||||
S: Supported
|
||||
T: git git://github.com/afaerber/qemu-cpu.git qom-next
|
||||
F: include/qom/
|
||||
X: include/qom/cpu.h
|
||||
F: qom/
|
||||
X: qom/cpu.c
|
||||
F: tests/qom-test.c
|
||||
|
||||
QMP
|
||||
M: Luiz Capitulino <lcapitulino@redhat.com>
|
||||
S: Maintained
|
||||
|
50
Makefile
50
Makefile
@@ -52,12 +52,12 @@ GENERATED_HEADERS += trace/generated-events.h
|
||||
GENERATED_SOURCES += trace/generated-events.c
|
||||
|
||||
GENERATED_HEADERS += trace/generated-tracers.h
|
||||
ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace)
|
||||
ifeq ($(TRACE_BACKEND),dtrace)
|
||||
GENERATED_HEADERS += trace/generated-tracers-dtrace.h
|
||||
endif
|
||||
GENERATED_SOURCES += trace/generated-tracers.c
|
||||
|
||||
ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust)
|
||||
ifeq ($(TRACE_BACKEND),ust)
|
||||
GENERATED_HEADERS += trace/generated-ust-provider.h
|
||||
GENERATED_SOURCES += trace/generated-ust.c
|
||||
endif
|
||||
@@ -148,6 +148,10 @@ endif
|
||||
|
||||
all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
|
||||
|
||||
config-host.h: config-host.h-timestamp
|
||||
config-host.h-timestamp: config-host.mak
|
||||
qemu-options.def: $(SRC_PATH)/qemu-options.hx
|
||||
@@ -191,6 +195,8 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
|
||||
|
||||
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
|
||||
|
||||
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
|
||||
|
||||
$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h | $(BUILD_DIR)/version.lo
|
||||
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.o")
|
||||
$(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h
|
||||
@@ -232,35 +238,23 @@ qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
|
||||
|
||||
qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
|
||||
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
|
||||
$(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \
|
||||
" GEN $@")
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
|
||||
qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
|
||||
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
|
||||
$(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \
|
||||
" GEN $@")
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
|
||||
qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
|
||||
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
|
||||
$(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \
|
||||
" GEN $@")
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
|
||||
|
||||
qapi-types.c qapi-types.h :\
|
||||
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
|
||||
$(gen-out-type) -o "." -b -i $<, \
|
||||
" GEN $@")
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." -b < $<, " GEN $@")
|
||||
qapi-visit.c qapi-visit.h :\
|
||||
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
|
||||
$(gen-out-type) -o "." -b -i $<, \
|
||||
" GEN $@")
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "." -b < $<, " GEN $@")
|
||||
qmp-commands.h qmp-marshal.c :\
|
||||
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
|
||||
$(gen-out-type) -o "." -m -i $<, \
|
||||
" GEN $@")
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, " GEN $@")
|
||||
|
||||
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
|
||||
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
|
||||
@@ -378,25 +372,17 @@ install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig \
|
||||
install-datadir install-localstatedir
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
|
||||
ifneq ($(TOOLS),)
|
||||
$(INSTALL_PROG) $(TOOLS) "$(DESTDIR)$(bindir)"
|
||||
ifneq ($(STRIP),)
|
||||
$(STRIP) $(TOOLS:%="$(DESTDIR)$(bindir)/%")
|
||||
endif
|
||||
$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
|
||||
endif
|
||||
ifneq ($(CONFIG_MODULES),)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_moddir)"
|
||||
for s in $(modules-m:.mo=$(DSOSUF)); do \
|
||||
t="$(DESTDIR)$(qemu_moddir)/$$(echo $$s | tr / -)"; \
|
||||
$(INSTALL_LIB) $$s "$$t"; \
|
||||
test -z "$(STRIP)" || $(STRIP) "$$t"; \
|
||||
for s in $(patsubst %.mo,%$(DSOSUF),$(modules-m)); do \
|
||||
$(INSTALL_PROG) $(STRIP_OPT) $$s "$(DESTDIR)$(qemu_moddir)/$$(echo $$s | tr / -)"; \
|
||||
done
|
||||
endif
|
||||
ifneq ($(HELPERS-y),)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(libexecdir)"
|
||||
$(INSTALL_PROG) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
|
||||
ifneq ($(STRIP),)
|
||||
$(STRIP) $(HELPERS-y:%="$(DESTDIR)$(libexecdir)/%")
|
||||
endif
|
||||
$(INSTALL_PROG) $(STRIP_OPT) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
|
||||
endif
|
||||
ifneq ($(BLOBS),)
|
||||
set -e; for x in $(BLOBS); do \
|
||||
|
@@ -31,8 +31,6 @@ libcacard-y += libcacard/vcard_emul_nss.o
|
||||
libcacard-y += libcacard/vcard_emul_type.o
|
||||
libcacard-y += libcacard/card_7816.o
|
||||
libcacard-y += libcacard/vcardt.o
|
||||
libcacard/vcard_emul_nss.o-cflags := $(NSS_CFLAGS)
|
||||
libcacard/vcard_emul_nss.o-libs := $(NSS_LIBS)
|
||||
|
||||
######################################################################
|
||||
# Target independent part of system emulation. The long term path is to
|
||||
@@ -66,11 +64,9 @@ common-obj-y += hw/
|
||||
|
||||
common-obj-y += ui/
|
||||
common-obj-y += bt-host.o bt-vhci.o
|
||||
bt-host.o-cflags := $(BLUEZ_CFLAGS)
|
||||
|
||||
common-obj-y += dma-helpers.o
|
||||
common-obj-y += vl.o
|
||||
vl.o-cflags := $(GPROF_CFLAGS) $(SDL_CFLAGS)
|
||||
common-obj-y += tpm.o
|
||||
|
||||
common-obj-$(CONFIG_SLIRP) += slirp/
|
||||
|
@@ -16,22 +16,19 @@ QEMU_CFLAGS+=-I$(SRC_PATH)/include
|
||||
ifdef CONFIG_USER_ONLY
|
||||
# user emulator name
|
||||
QEMU_PROG=qemu-$(TARGET_NAME)
|
||||
QEMU_PROG_BUILD = $(QEMU_PROG)
|
||||
else
|
||||
# system emulator name
|
||||
QEMU_PROG=qemu-system-$(TARGET_NAME)$(EXESUF)
|
||||
ifneq (,$(findstring -mwindows,$(libs_softmmu)))
|
||||
# Terminate program name with a 'w' because the linker builds a windows executable.
|
||||
QEMU_PROGW=qemu-system-$(TARGET_NAME)w$(EXESUF)
|
||||
$(QEMU_PROG): $(QEMU_PROGW)
|
||||
$(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)")
|
||||
QEMU_PROG_BUILD = $(QEMU_PROGW)
|
||||
else
|
||||
QEMU_PROG_BUILD = $(QEMU_PROG)
|
||||
endif
|
||||
endif # windows executable
|
||||
QEMU_PROG=qemu-system-$(TARGET_NAME)$(EXESUF)
|
||||
endif
|
||||
|
||||
PROGS=$(QEMU_PROG) $(QEMU_PROGW)
|
||||
PROGS=$(QEMU_PROG)
|
||||
ifdef QEMU_PROGW
|
||||
PROGS+=$(QEMU_PROGW)
|
||||
endif
|
||||
STPFILES=
|
||||
|
||||
config-target.h: config-target.h-timestamp
|
||||
@@ -49,7 +46,7 @@ endif
|
||||
$(QEMU_PROG).stp-installed: $(SRC_PATH)/trace-events
|
||||
$(call quiet-command,$(TRACETOOL) \
|
||||
--format=stap \
|
||||
--backends=$(TRACE_BACKENDS) \
|
||||
--backend=$(TRACE_BACKEND) \
|
||||
--binary=$(bindir)/$(QEMU_PROG) \
|
||||
--target-name=$(TARGET_NAME) \
|
||||
--target-type=$(TARGET_TYPE) \
|
||||
@@ -58,7 +55,7 @@ $(QEMU_PROG).stp-installed: $(SRC_PATH)/trace-events
|
||||
$(QEMU_PROG).stp: $(SRC_PATH)/trace-events
|
||||
$(call quiet-command,$(TRACETOOL) \
|
||||
--format=stap \
|
||||
--backends=$(TRACE_BACKENDS) \
|
||||
--backend=$(TRACE_BACKEND) \
|
||||
--binary=$(realpath .)/$(QEMU_PROG) \
|
||||
--target-name=$(TARGET_NAME) \
|
||||
--target-type=$(TARGET_TYPE) \
|
||||
@@ -123,10 +120,8 @@ obj-y += dump.o
|
||||
LIBS+=$(libs_softmmu)
|
||||
|
||||
# xen support
|
||||
obj-$(CONFIG_XEN) += xen-common.o
|
||||
obj-$(CONFIG_XEN_I386) += xen-hvm.o xen-mapcache.o
|
||||
obj-$(call lnot,$(CONFIG_XEN)) += xen-common-stub.o
|
||||
obj-$(call lnot,$(CONFIG_XEN_I386)) += xen-hvm-stub.o
|
||||
obj-$(CONFIG_XEN) += xen-all.o xen-mapcache.o
|
||||
obj-$(call lnot,$(CONFIG_XEN)) += xen-stub.o
|
||||
|
||||
# Hardware support
|
||||
ifeq ($(TARGET_NAME), sparc64)
|
||||
@@ -143,7 +138,10 @@ endif # CONFIG_SOFTMMU
|
||||
%/translate.o: QEMU_CFLAGS += $(TRANSLATE_OPT_CFLAGS)
|
||||
|
||||
dummy := $(call unnest-vars,,obj-y)
|
||||
all-obj-y := $(obj-y)
|
||||
|
||||
# we are making another call to unnest-vars with different vars, protect obj-y,
|
||||
# it can be overriden in subdir Makefile.objs
|
||||
obj-y-save := $(obj-y)
|
||||
|
||||
block-obj-y :=
|
||||
common-obj-y :=
|
||||
@@ -153,16 +151,27 @@ dummy := $(call unnest-vars,.., \
|
||||
block-obj-m \
|
||||
common-obj-y \
|
||||
common-obj-m)
|
||||
all-obj-y += $(common-obj-y)
|
||||
|
||||
# Now restore obj-y
|
||||
obj-y := $(obj-y-save)
|
||||
|
||||
all-obj-y = $(obj-y) $(common-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y)
|
||||
|
||||
ifndef CONFIG_HAIKU
|
||||
LIBS+=-lm
|
||||
endif
|
||||
|
||||
# build either PROG or PROGW
|
||||
$(QEMU_PROG_BUILD): $(all-obj-y) ../libqemuutil.a ../libqemustub.a
|
||||
ifdef QEMU_PROGW
|
||||
# The linker builds a windows executable. Make also a console executable.
|
||||
$(QEMU_PROGW): $(all-obj-y) ../libqemuutil.a ../libqemustub.a
|
||||
$(call LINK,$^)
|
||||
$(QEMU_PROG): $(QEMU_PROGW)
|
||||
$(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)")
|
||||
else
|
||||
$(QEMU_PROG): $(all-obj-y) ../libqemuutil.a ../libqemustub.a
|
||||
$(call LINK,$^)
|
||||
endif
|
||||
|
||||
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
|
||||
$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@")
|
||||
@@ -183,9 +192,9 @@ endif
|
||||
|
||||
install: all
|
||||
ifneq ($(PROGS),)
|
||||
$(INSTALL_PROG) $(PROGS) "$(DESTDIR)$(bindir)"
|
||||
$(INSTALL) -m 755 $(PROGS) "$(DESTDIR)$(bindir)"
|
||||
ifneq ($(STRIP),)
|
||||
$(STRIP) $(PROGS:%="$(DESTDIR)$(bindir)/%")
|
||||
$(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS))
|
||||
endif
|
||||
endif
|
||||
ifdef CONFIG_TRACE_SYSTEMTAP
|
||||
|
365
arch_init.c
365
arch_init.c
@@ -45,7 +45,6 @@
|
||||
#include "hw/audio/pcspk.h"
|
||||
#include "migration/page_cache.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "trace.h"
|
||||
#include "exec/cpu-all.h"
|
||||
@@ -111,8 +110,6 @@ static bool mig_throttle_on;
|
||||
static int dirty_rate_high_cnt;
|
||||
static void check_guest_throttling(void);
|
||||
|
||||
static uint64_t bitmap_sync_count;
|
||||
|
||||
/***********************************************************/
|
||||
/* ram save/restore */
|
||||
|
||||
@@ -170,8 +167,11 @@ static struct {
|
||||
/* Cache for XBZRLE, Protected by lock. */
|
||||
PageCache *cache;
|
||||
QemuMutex lock;
|
||||
} XBZRLE;
|
||||
|
||||
} XBZRLE = {
|
||||
.encoded_buf = NULL,
|
||||
.current_buf = NULL,
|
||||
.cache = NULL,
|
||||
};
|
||||
/* buffer used for XBZRLE decoding */
|
||||
static uint8_t *xbzrle_decoded_buf;
|
||||
|
||||
@@ -187,44 +187,41 @@ static void XBZRLE_cache_unlock(void)
|
||||
qemu_mutex_unlock(&XBZRLE.lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* called from qmp_migrate_set_cache_size in main thread, possibly while
|
||||
* a migration is in progress.
|
||||
* A running migration maybe using the cache and might finish during this
|
||||
* call, hence changes to the cache are protected by XBZRLE.lock().
|
||||
*/
|
||||
int64_t xbzrle_cache_resize(int64_t new_size)
|
||||
{
|
||||
PageCache *new_cache;
|
||||
int64_t ret;
|
||||
PageCache *new_cache, *cache_to_free;
|
||||
|
||||
if (new_size < TARGET_PAGE_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
XBZRLE_cache_lock();
|
||||
|
||||
/* no need to lock, the current thread holds qemu big lock */
|
||||
if (XBZRLE.cache != NULL) {
|
||||
/* check XBZRLE.cache again later */
|
||||
if (pow2floor(new_size) == migrate_xbzrle_cache_size()) {
|
||||
goto out_new_size;
|
||||
return pow2floor(new_size);
|
||||
}
|
||||
new_cache = cache_init(new_size / TARGET_PAGE_SIZE,
|
||||
TARGET_PAGE_SIZE);
|
||||
if (!new_cache) {
|
||||
error_report("Error creating cache");
|
||||
ret = -1;
|
||||
goto out;
|
||||
DPRINTF("Error creating cache\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cache_fini(XBZRLE.cache);
|
||||
XBZRLE.cache = new_cache;
|
||||
XBZRLE_cache_lock();
|
||||
/* the XBZRLE.cache may have be destroyed, check it again */
|
||||
if (XBZRLE.cache != NULL) {
|
||||
cache_to_free = XBZRLE.cache;
|
||||
XBZRLE.cache = new_cache;
|
||||
} else {
|
||||
cache_to_free = new_cache;
|
||||
}
|
||||
XBZRLE_cache_unlock();
|
||||
|
||||
cache_fini(cache_to_free);
|
||||
}
|
||||
|
||||
out_new_size:
|
||||
ret = pow2floor(new_size);
|
||||
out:
|
||||
XBZRLE_cache_unlock();
|
||||
return ret;
|
||||
return pow2floor(new_size);
|
||||
}
|
||||
|
||||
/* accounting for migration statistics */
|
||||
@@ -236,7 +233,6 @@ typedef struct AccountingInfo {
|
||||
uint64_t xbzrle_bytes;
|
||||
uint64_t xbzrle_pages;
|
||||
uint64_t xbzrle_cache_miss;
|
||||
double xbzrle_cache_miss_rate;
|
||||
uint64_t xbzrle_overflows;
|
||||
} AccountingInfo;
|
||||
|
||||
@@ -292,11 +288,6 @@ uint64_t xbzrle_mig_pages_cache_miss(void)
|
||||
return acct_info.xbzrle_cache_miss;
|
||||
}
|
||||
|
||||
double xbzrle_mig_cache_miss_rate(void)
|
||||
{
|
||||
return acct_info.xbzrle_cache_miss_rate;
|
||||
}
|
||||
|
||||
uint64_t xbzrle_mig_pages_overflow(void)
|
||||
{
|
||||
return acct_info.xbzrle_overflows;
|
||||
@@ -349,7 +340,7 @@ static void xbzrle_cache_zero_page(ram_addr_t current_addr)
|
||||
|
||||
#define ENCODING_FLAG_XBZRLE 0x1
|
||||
|
||||
static int save_xbzrle_page(QEMUFile *f, uint8_t **current_data,
|
||||
static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
|
||||
ram_addr_t current_addr, RAMBlock *block,
|
||||
ram_addr_t offset, int cont, bool last_stage)
|
||||
{
|
||||
@@ -357,23 +348,19 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t **current_data,
|
||||
uint8_t *prev_cached_page;
|
||||
|
||||
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
|
||||
acct_info.xbzrle_cache_miss++;
|
||||
if (!last_stage) {
|
||||
if (cache_insert(XBZRLE.cache, current_addr, *current_data) == -1) {
|
||||
if (cache_insert(XBZRLE.cache, current_addr, current_data) == -1) {
|
||||
return -1;
|
||||
} else {
|
||||
/* update *current_data when the page has been
|
||||
inserted into cache */
|
||||
*current_data = get_cached_data(XBZRLE.cache, current_addr);
|
||||
}
|
||||
}
|
||||
acct_info.xbzrle_cache_miss++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
prev_cached_page = get_cached_data(XBZRLE.cache, current_addr);
|
||||
|
||||
/* save current buffer into memory */
|
||||
memcpy(XBZRLE.current_buf, *current_data, TARGET_PAGE_SIZE);
|
||||
memcpy(XBZRLE.current_buf, current_data, TARGET_PAGE_SIZE);
|
||||
|
||||
/* XBZRLE encoding (if there is no overflow) */
|
||||
encoded_len = xbzrle_encode_buffer(prev_cached_page, XBZRLE.current_buf,
|
||||
@@ -386,10 +373,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t **current_data,
|
||||
DPRINTF("Overflow\n");
|
||||
acct_info.xbzrle_overflows++;
|
||||
/* update data in the cache */
|
||||
if (!last_stage) {
|
||||
memcpy(prev_cached_page, *current_data, TARGET_PAGE_SIZE);
|
||||
*current_data = prev_cached_page;
|
||||
}
|
||||
memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -495,10 +479,6 @@ static void migration_bitmap_sync(void)
|
||||
static int64_t num_dirty_pages_period;
|
||||
int64_t end_time;
|
||||
int64_t bytes_xfer_now;
|
||||
static uint64_t xbzrle_cache_miss_prev;
|
||||
static uint64_t iterations_prev;
|
||||
|
||||
bitmap_sync_count++;
|
||||
|
||||
if (!bytes_xfer_prev) {
|
||||
bytes_xfer_prev = ram_bytes_transferred();
|
||||
@@ -540,113 +520,29 @@ static void migration_bitmap_sync(void)
|
||||
} else {
|
||||
mig_throttle_on = false;
|
||||
}
|
||||
if (migrate_use_xbzrle()) {
|
||||
if (iterations_prev != 0) {
|
||||
acct_info.xbzrle_cache_miss_rate =
|
||||
(double)(acct_info.xbzrle_cache_miss -
|
||||
xbzrle_cache_miss_prev) /
|
||||
(acct_info.iterations - iterations_prev);
|
||||
}
|
||||
iterations_prev = acct_info.iterations;
|
||||
xbzrle_cache_miss_prev = acct_info.xbzrle_cache_miss;
|
||||
}
|
||||
s->dirty_pages_rate = num_dirty_pages_period * 1000
|
||||
/ (end_time - start_time);
|
||||
s->dirty_bytes_rate = s->dirty_pages_rate * TARGET_PAGE_SIZE;
|
||||
start_time = end_time;
|
||||
num_dirty_pages_period = 0;
|
||||
s->dirty_sync_count = bitmap_sync_count;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ram_save_page: Send the given page to the stream
|
||||
*
|
||||
* Returns: Number of bytes written.
|
||||
*/
|
||||
static int ram_save_page(QEMUFile *f, RAMBlock* block, ram_addr_t offset,
|
||||
bool last_stage)
|
||||
{
|
||||
int bytes_sent;
|
||||
int cont;
|
||||
ram_addr_t current_addr;
|
||||
MemoryRegion *mr = block->mr;
|
||||
uint8_t *p;
|
||||
int ret;
|
||||
bool send_async = true;
|
||||
|
||||
cont = (block == last_sent_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
|
||||
|
||||
p = memory_region_get_ram_ptr(mr) + offset;
|
||||
|
||||
/* In doubt sent page as normal */
|
||||
bytes_sent = -1;
|
||||
ret = ram_control_save_page(f, block->offset,
|
||||
offset, TARGET_PAGE_SIZE, &bytes_sent);
|
||||
|
||||
XBZRLE_cache_lock();
|
||||
|
||||
current_addr = block->offset + offset;
|
||||
if (ret != RAM_SAVE_CONTROL_NOT_SUPP) {
|
||||
if (ret != RAM_SAVE_CONTROL_DELAYED) {
|
||||
if (bytes_sent > 0) {
|
||||
acct_info.norm_pages++;
|
||||
} else if (bytes_sent == 0) {
|
||||
acct_info.dup_pages++;
|
||||
}
|
||||
}
|
||||
} else if (is_zero_range(p, TARGET_PAGE_SIZE)) {
|
||||
acct_info.dup_pages++;
|
||||
bytes_sent = save_block_hdr(f, block, offset, cont,
|
||||
RAM_SAVE_FLAG_COMPRESS);
|
||||
qemu_put_byte(f, 0);
|
||||
bytes_sent++;
|
||||
/* Must let xbzrle know, otherwise a previous (now 0'd) cached
|
||||
* page would be stale
|
||||
*/
|
||||
xbzrle_cache_zero_page(current_addr);
|
||||
} else if (!ram_bulk_stage && migrate_use_xbzrle()) {
|
||||
bytes_sent = save_xbzrle_page(f, &p, current_addr, block,
|
||||
offset, cont, last_stage);
|
||||
if (!last_stage) {
|
||||
/* Can't send this cached data async, since the cache page
|
||||
* might get updated before it gets to the wire
|
||||
*/
|
||||
send_async = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* XBZRLE overflow or normal page */
|
||||
if (bytes_sent == -1) {
|
||||
bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
|
||||
if (send_async) {
|
||||
qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE);
|
||||
} else {
|
||||
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
|
||||
}
|
||||
bytes_sent += TARGET_PAGE_SIZE;
|
||||
acct_info.norm_pages++;
|
||||
}
|
||||
|
||||
XBZRLE_cache_unlock();
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
/*
|
||||
* ram_find_and_save_block: Finds a page to send and sends it to f
|
||||
* ram_save_block: Writes a page of memory to the stream f
|
||||
*
|
||||
* Returns: The number of bytes written.
|
||||
* 0 means no dirty pages
|
||||
*/
|
||||
|
||||
static int ram_find_and_save_block(QEMUFile *f, bool last_stage)
|
||||
static int ram_save_block(QEMUFile *f, bool last_stage)
|
||||
{
|
||||
RAMBlock *block = last_seen_block;
|
||||
ram_addr_t offset = last_offset;
|
||||
bool complete_round = false;
|
||||
int bytes_sent = 0;
|
||||
MemoryRegion *mr;
|
||||
ram_addr_t current_addr;
|
||||
|
||||
if (!block)
|
||||
block = QTAILQ_FIRST(&ram_list.blocks);
|
||||
@@ -667,8 +563,70 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage)
|
||||
ram_bulk_stage = false;
|
||||
}
|
||||
} else {
|
||||
bytes_sent = ram_save_page(f, block, offset, last_stage);
|
||||
int ret;
|
||||
uint8_t *p;
|
||||
bool send_async = true;
|
||||
int cont = (block == last_sent_block) ?
|
||||
RAM_SAVE_FLAG_CONTINUE : 0;
|
||||
|
||||
p = memory_region_get_ram_ptr(mr) + offset;
|
||||
|
||||
/* In doubt sent page as normal */
|
||||
bytes_sent = -1;
|
||||
ret = ram_control_save_page(f, block->offset,
|
||||
offset, TARGET_PAGE_SIZE, &bytes_sent);
|
||||
|
||||
XBZRLE_cache_lock();
|
||||
|
||||
current_addr = block->offset + offset;
|
||||
if (ret != RAM_SAVE_CONTROL_NOT_SUPP) {
|
||||
if (ret != RAM_SAVE_CONTROL_DELAYED) {
|
||||
if (bytes_sent > 0) {
|
||||
acct_info.norm_pages++;
|
||||
} else if (bytes_sent == 0) {
|
||||
acct_info.dup_pages++;
|
||||
}
|
||||
}
|
||||
} else if (is_zero_range(p, TARGET_PAGE_SIZE)) {
|
||||
acct_info.dup_pages++;
|
||||
bytes_sent = save_block_hdr(f, block, offset, cont,
|
||||
RAM_SAVE_FLAG_COMPRESS);
|
||||
qemu_put_byte(f, 0);
|
||||
bytes_sent++;
|
||||
/* Must let xbzrle know, otherwise a previous (now 0'd) cached
|
||||
* page would be stale
|
||||
*/
|
||||
xbzrle_cache_zero_page(current_addr);
|
||||
} else if (!ram_bulk_stage && migrate_use_xbzrle()) {
|
||||
bytes_sent = save_xbzrle_page(f, p, current_addr, block,
|
||||
offset, cont, last_stage);
|
||||
if (!last_stage) {
|
||||
/* We must send exactly what's in the xbzrle cache
|
||||
* even if the page wasn't xbzrle compressed, so that
|
||||
* it's right next time.
|
||||
*/
|
||||
p = get_cached_data(XBZRLE.cache, current_addr);
|
||||
|
||||
/* Can't send this cached data async, since the cache page
|
||||
* might get updated before it gets to the wire
|
||||
*/
|
||||
send_async = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* XBZRLE overflow or normal page */
|
||||
if (bytes_sent == -1) {
|
||||
bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
|
||||
if (send_async) {
|
||||
qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE);
|
||||
} else {
|
||||
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
|
||||
}
|
||||
bytes_sent += TARGET_PAGE_SIZE;
|
||||
acct_info.norm_pages++;
|
||||
}
|
||||
|
||||
XBZRLE_cache_unlock();
|
||||
/* if page is unmodified, continue to the next */
|
||||
if (bytes_sent > 0) {
|
||||
last_sent_block = block;
|
||||
@@ -768,34 +726,37 @@ static void reset_ram_globals(void)
|
||||
static int ram_save_setup(QEMUFile *f, void *opaque)
|
||||
{
|
||||
RAMBlock *block;
|
||||
int64_t ram_bitmap_pages; /* Size of bitmap in pages, including gaps */
|
||||
int64_t ram_pages = last_ram_offset() >> TARGET_PAGE_BITS;
|
||||
|
||||
migration_bitmap = bitmap_new(ram_pages);
|
||||
bitmap_set(migration_bitmap, 0, ram_pages);
|
||||
migration_dirty_pages = ram_pages;
|
||||
mig_throttle_on = false;
|
||||
dirty_rate_high_cnt = 0;
|
||||
bitmap_sync_count = 0;
|
||||
|
||||
if (migrate_use_xbzrle()) {
|
||||
XBZRLE_cache_lock();
|
||||
qemu_mutex_lock_iothread();
|
||||
XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
|
||||
TARGET_PAGE_SIZE,
|
||||
TARGET_PAGE_SIZE);
|
||||
if (!XBZRLE.cache) {
|
||||
XBZRLE_cache_unlock();
|
||||
error_report("Error creating cache");
|
||||
qemu_mutex_unlock_iothread();
|
||||
DPRINTF("Error creating cache\n");
|
||||
return -1;
|
||||
}
|
||||
XBZRLE_cache_unlock();
|
||||
qemu_mutex_init(&XBZRLE.lock);
|
||||
qemu_mutex_unlock_iothread();
|
||||
|
||||
/* We prefer not to abort if there is no memory */
|
||||
XBZRLE.encoded_buf = g_try_malloc0(TARGET_PAGE_SIZE);
|
||||
if (!XBZRLE.encoded_buf) {
|
||||
error_report("Error allocating encoded_buf");
|
||||
DPRINTF("Error allocating encoded_buf\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
XBZRLE.current_buf = g_try_malloc(TARGET_PAGE_SIZE);
|
||||
if (!XBZRLE.current_buf) {
|
||||
error_report("Error allocating current_buf");
|
||||
DPRINTF("Error allocating current_buf\n");
|
||||
g_free(XBZRLE.encoded_buf);
|
||||
XBZRLE.encoded_buf = NULL;
|
||||
return -1;
|
||||
@@ -809,22 +770,6 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
|
||||
bytes_transferred = 0;
|
||||
reset_ram_globals();
|
||||
|
||||
ram_bitmap_pages = last_ram_offset() >> TARGET_PAGE_BITS;
|
||||
migration_bitmap = bitmap_new(ram_bitmap_pages);
|
||||
bitmap_set(migration_bitmap, 0, ram_bitmap_pages);
|
||||
|
||||
/*
|
||||
* Count the total number of pages used by ram blocks not including any
|
||||
* gaps due to alignment or unplugs.
|
||||
*/
|
||||
migration_dirty_pages = 0;
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
uint64_t block_pages;
|
||||
|
||||
block_pages = block->length >> TARGET_PAGE_BITS;
|
||||
migration_dirty_pages += block_pages;
|
||||
}
|
||||
|
||||
memory_global_dirty_log_start();
|
||||
migration_bitmap_sync();
|
||||
qemu_mutex_unlock_iothread();
|
||||
@@ -867,7 +812,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
|
||||
while ((ret = qemu_file_rate_limit(f)) == 0) {
|
||||
int bytes_sent;
|
||||
|
||||
bytes_sent = ram_find_and_save_block(f, false);
|
||||
bytes_sent = ram_save_block(f, false);
|
||||
/* no more blocks to sent */
|
||||
if (bytes_sent == 0) {
|
||||
break;
|
||||
@@ -929,7 +874,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
|
||||
while (true) {
|
||||
int bytes_sent;
|
||||
|
||||
bytes_sent = ram_find_and_save_block(f, true);
|
||||
bytes_sent = ram_save_block(f, true);
|
||||
/* no more blocks to sent */
|
||||
if (bytes_sent == 0) {
|
||||
break;
|
||||
@@ -963,6 +908,7 @@ static uint64_t ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
|
||||
|
||||
static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
|
||||
{
|
||||
int ret, rc = 0;
|
||||
unsigned int xh_len;
|
||||
int xh_flags;
|
||||
|
||||
@@ -975,25 +921,30 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
|
||||
xh_len = qemu_get_be16(f);
|
||||
|
||||
if (xh_flags != ENCODING_FLAG_XBZRLE) {
|
||||
error_report("Failed to load XBZRLE page - wrong compression!");
|
||||
fprintf(stderr, "Failed to load XBZRLE page - wrong compression!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (xh_len > TARGET_PAGE_SIZE) {
|
||||
error_report("Failed to load XBZRLE page - len overflow!");
|
||||
fprintf(stderr, "Failed to load XBZRLE page - len overflow!\n");
|
||||
return -1;
|
||||
}
|
||||
/* load data and decode */
|
||||
qemu_get_buffer(f, xbzrle_decoded_buf, xh_len);
|
||||
|
||||
/* decode RLE */
|
||||
if (xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host,
|
||||
TARGET_PAGE_SIZE) == -1) {
|
||||
error_report("Failed to load XBZRLE page - decode error!");
|
||||
return -1;
|
||||
ret = xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host,
|
||||
TARGET_PAGE_SIZE);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");
|
||||
rc = -1;
|
||||
} else if (ret > TARGET_PAGE_SIZE) {
|
||||
fprintf(stderr, "Failed to load XBZRLE page - size %d exceeds %d!\n",
|
||||
ret, TARGET_PAGE_SIZE);
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline void *host_from_stream_offset(QEMUFile *f,
|
||||
@@ -1006,7 +957,7 @@ static inline void *host_from_stream_offset(QEMUFile *f,
|
||||
|
||||
if (flags & RAM_SAVE_FLAG_CONTINUE) {
|
||||
if (!block) {
|
||||
error_report("Ack, bad migration stream!");
|
||||
fprintf(stderr, "Ack, bad migration stream!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1022,7 +973,7 @@ static inline void *host_from_stream_offset(QEMUFile *f,
|
||||
return memory_region_get_ram_ptr(block->mr) + offset;
|
||||
}
|
||||
|
||||
error_report("Can't find block %s!", id);
|
||||
fprintf(stderr, "Can't find block %s!\n", id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1041,17 +992,15 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
ram_addr_t addr;
|
||||
int flags, ret = 0;
|
||||
int error;
|
||||
static uint64_t seq_iter;
|
||||
|
||||
seq_iter++;
|
||||
|
||||
if (version_id != 4) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
do {
|
||||
while (!ret) {
|
||||
addr = qemu_get_be64(f);
|
||||
|
||||
flags = addr & ~TARGET_PAGE_MASK;
|
||||
@@ -1075,35 +1024,36 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
if (!strncmp(id, block->idstr, sizeof(id))) {
|
||||
if (block->length != length) {
|
||||
error_report("Length mismatch: %s: " RAM_ADDR_FMT
|
||||
" in != " RAM_ADDR_FMT, id, length,
|
||||
block->length);
|
||||
fprintf(stderr,
|
||||
"Length mismatch: %s: " RAM_ADDR_FMT
|
||||
" in != " RAM_ADDR_FMT "\n", id, length,
|
||||
block->length);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!block) {
|
||||
error_report("Unknown ramblock \"%s\", cannot "
|
||||
"accept migration", id);
|
||||
fprintf(stderr, "Unknown ramblock \"%s\", cannot "
|
||||
"accept migration\n", id);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (ret) {
|
||||
break;
|
||||
}
|
||||
|
||||
total_ram_bytes -= length;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & RAM_SAVE_FLAG_COMPRESS) {
|
||||
} else if (flags & RAM_SAVE_FLAG_COMPRESS) {
|
||||
void *host;
|
||||
uint8_t ch;
|
||||
|
||||
host = host_from_stream_offset(f, addr, flags);
|
||||
if (!host) {
|
||||
error_report("Illegal RAM offset " RAM_ADDR_FMT, addr);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
||||
ch = qemu_get_byte(f);
|
||||
@@ -1113,39 +1063,45 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
|
||||
host = host_from_stream_offset(f, addr, flags);
|
||||
if (!host) {
|
||||
error_report("Illegal RAM offset " RAM_ADDR_FMT, addr);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
||||
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
|
||||
} else if (flags & RAM_SAVE_FLAG_XBZRLE) {
|
||||
void *host = host_from_stream_offset(f, addr, flags);
|
||||
if (!host) {
|
||||
error_report("Illegal RAM offset " RAM_ADDR_FMT, addr);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
||||
if (load_xbzrle(f, addr, host) < 0) {
|
||||
error_report("Failed to decompress XBZRLE page at "
|
||||
RAM_ADDR_FMT, addr);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
} else if (flags & RAM_SAVE_FLAG_HOOK) {
|
||||
ram_control_load_hook(f, flags);
|
||||
} else if (flags & RAM_SAVE_FLAG_EOS) {
|
||||
/* normal exit */
|
||||
break;
|
||||
} else {
|
||||
error_report("Unknown migration flags: %#x", flags);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
error = qemu_file_get_error(f);
|
||||
if (error) {
|
||||
ret = error;
|
||||
goto done;
|
||||
}
|
||||
} while (!(flags & RAM_SAVE_FLAG_EOS));
|
||||
ret = qemu_file_get_error(f);
|
||||
}
|
||||
|
||||
done:
|
||||
DPRINTF("Completed load of VM with exit code %d seq iteration "
|
||||
"%" PRIu64 "\n", ret, seq_iter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static SaveVMHandlers savevm_ram_handlers = {
|
||||
SaveVMHandlers savevm_ram_handlers = {
|
||||
.save_live_setup = ram_save_setup,
|
||||
.save_live_iterate = ram_save_iterate,
|
||||
.save_live_complete = ram_save_complete,
|
||||
@@ -1154,12 +1110,6 @@ static SaveVMHandlers savevm_ram_handlers = {
|
||||
.cancel = ram_migration_cancel,
|
||||
};
|
||||
|
||||
void ram_mig_init(void)
|
||||
{
|
||||
qemu_mutex_init(&XBZRLE.lock);
|
||||
register_savevm_live(NULL, "ram", 0, 4, &savevm_ram_handlers, NULL);
|
||||
}
|
||||
|
||||
struct soundhw {
|
||||
const char *name;
|
||||
const char *descr;
|
||||
@@ -1242,11 +1192,12 @@ void select_soundhw(const char *optarg)
|
||||
|
||||
if (!c->name) {
|
||||
if (l > 80) {
|
||||
error_report("Unknown sound card name (too big to show)");
|
||||
fprintf(stderr,
|
||||
"Unknown sound card name (too big to show)\n");
|
||||
}
|
||||
else {
|
||||
error_report("Unknown sound card name `%.*s'",
|
||||
(int) l, p);
|
||||
fprintf(stderr, "Unknown sound card name `%.*s'\n",
|
||||
(int) l, p);
|
||||
}
|
||||
bad_card = 1;
|
||||
}
|
||||
@@ -1269,13 +1220,13 @@ void audio_init(void)
|
||||
if (c->enabled) {
|
||||
if (c->isa) {
|
||||
if (!isa_bus) {
|
||||
error_report("ISA bus not available for %s", c->name);
|
||||
fprintf(stderr, "ISA bus not available for %s\n", c->name);
|
||||
exit(1);
|
||||
}
|
||||
c->init.init_isa(isa_bus);
|
||||
} else {
|
||||
if (!pci_bus) {
|
||||
error_report("PCI bus not available for %s", c->name);
|
||||
fprintf(stderr, "PCI bus not available for %s\n", c->name);
|
||||
exit(1);
|
||||
}
|
||||
c->init.init_pci(pci_bus);
|
||||
|
@@ -14,4 +14,4 @@ common-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
|
||||
common-obj-y += wavcapture.o
|
||||
|
||||
$(obj)/audio.o $(obj)/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
|
||||
sdlaudio.o-cflags := $(SDL_CFLAGS)
|
||||
$(obj)/sdlaudio.o: QEMU_CFLAGS += $(SDL_CFLAGS)
|
||||
|
@@ -1812,7 +1812,8 @@ static const VMStateDescription vmstate_audio = {
|
||||
.name = "audio",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@@ -105,7 +105,7 @@ static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
|
||||
bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ());
|
||||
samples = (bytes - rate->bytes_sent) >> info->shift;
|
||||
if (samples < 0 || samples > 65536) {
|
||||
error_report("Resetting rate control (%" PRId64 " samples)", samples);
|
||||
fprintf (stderr, "Resetting rate control (%" PRId64 " samples)\n", samples);
|
||||
rate_start (rate);
|
||||
samples = 0;
|
||||
}
|
||||
|
@@ -63,7 +63,8 @@ static void wav_destroy (void *opaque)
|
||||
}
|
||||
doclose:
|
||||
if (fclose (wav->f)) {
|
||||
error_report("wav_destroy: fclose failed: %s", strerror(errno));
|
||||
fprintf (stderr, "wav_destroy: fclose failed: %s",
|
||||
strerror (errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3,6 +3,6 @@ common-obj-$(CONFIG_POSIX) += rng-random.o
|
||||
|
||||
common-obj-y += msmouse.o
|
||||
common-obj-$(CONFIG_BRLAPI) += baum.o
|
||||
baum.o-cflags := $(SDL_CFLAGS)
|
||||
$(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
|
||||
|
||||
common-obj-$(CONFIG_TPM) += tpm.o
|
||||
|
@@ -50,7 +50,6 @@ static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
RngBackend *s = RNG_BACKEND(obj);
|
||||
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (value == s->opened) {
|
||||
return;
|
||||
@@ -62,14 +61,12 @@ static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
|
||||
}
|
||||
|
||||
if (k->opened) {
|
||||
k->opened(s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
k->opened(s, errp);
|
||||
}
|
||||
|
||||
s->opened = true;
|
||||
if (!error_is_set(errp)) {
|
||||
s->opened = value;
|
||||
}
|
||||
}
|
||||
|
||||
static void rng_backend_init(Object *obj)
|
||||
|
@@ -112,7 +112,6 @@ static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
TPMBackend *s = TPM_BACKEND(obj);
|
||||
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (value == s->opened) {
|
||||
return;
|
||||
@@ -124,14 +123,12 @@ static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
|
||||
}
|
||||
|
||||
if (k->opened) {
|
||||
k->opened(s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
k->opened(s, errp);
|
||||
}
|
||||
|
||||
s->opened = true;
|
||||
if (!error_is_set(errp)) {
|
||||
s->opened = value;
|
||||
}
|
||||
}
|
||||
|
||||
static void tpm_backend_instance_init(Object *obj)
|
||||
|
@@ -59,7 +59,6 @@ typedef struct BlkMigDevState {
|
||||
unsigned long *aio_bitmap;
|
||||
int64_t completed_sectors;
|
||||
BdrvDirtyBitmap *dirty_bitmap;
|
||||
Error *blocker;
|
||||
} BlkMigDevState;
|
||||
|
||||
typedef struct BlkMigBlock {
|
||||
@@ -311,28 +310,13 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
|
||||
|
||||
/* Called with iothread lock taken. */
|
||||
|
||||
static int set_dirty_tracking(void)
|
||||
static void set_dirty_tracking(void)
|
||||
{
|
||||
BlkMigDevState *bmds;
|
||||
int ret;
|
||||
|
||||
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||
bmds->dirty_bitmap = bdrv_create_dirty_bitmap(bmds->bs, BLOCK_SIZE,
|
||||
NULL);
|
||||
if (!bmds->dirty_bitmap) {
|
||||
ret = -errno;
|
||||
goto fail;
|
||||
}
|
||||
bmds->dirty_bitmap = bdrv_create_dirty_bitmap(bmds->bs, BLOCK_SIZE);
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||
if (bmds->dirty_bitmap) {
|
||||
bdrv_release_dirty_bitmap(bmds->bs, bmds->dirty_bitmap);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void unset_dirty_tracking(void)
|
||||
@@ -362,8 +346,7 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
|
||||
bmds->completed_sectors = 0;
|
||||
bmds->shared_base = block_mig_state.shared_base;
|
||||
alloc_aio_bitmap(bmds);
|
||||
error_setg(&bmds->blocker, "block device is in use by migration");
|
||||
bdrv_op_block_all(bs, bmds->blocker);
|
||||
bdrv_set_in_use(bs, 1);
|
||||
bdrv_ref(bs);
|
||||
|
||||
block_mig_state.total_sector_sum += sectors;
|
||||
@@ -601,8 +584,7 @@ static void blk_mig_cleanup(void)
|
||||
blk_mig_lock();
|
||||
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
|
||||
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
|
||||
bdrv_op_unblock_all(bmds->bs, bmds->blocker);
|
||||
error_free(bmds->blocker);
|
||||
bdrv_set_in_use(bmds->bs, 0);
|
||||
bdrv_unref(bmds->bs);
|
||||
g_free(bmds->aio_bitmap);
|
||||
g_free(bmds);
|
||||
@@ -632,13 +614,7 @@ static int block_save_setup(QEMUFile *f, void *opaque)
|
||||
init_blk_migration(f);
|
||||
|
||||
/* start track dirty blocks */
|
||||
ret = set_dirty_tracking();
|
||||
|
||||
if (ret) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
return ret;
|
||||
}
|
||||
|
||||
set_dirty_tracking();
|
||||
qemu_mutex_unlock_iothread();
|
||||
|
||||
ret = flush_blks(f);
|
||||
|
@@ -471,7 +471,7 @@ static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
|
||||
acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
|
||||
acb->ret = -error;
|
||||
|
||||
bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb);
|
||||
bh = qemu_bh_new(error_callback_bh, acb);
|
||||
acb->bh = bh;
|
||||
qemu_bh_schedule(bh);
|
||||
|
||||
|
@@ -39,13 +39,12 @@ struct BlkverifyAIOCB {
|
||||
static void blkverify_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
{
|
||||
BlkverifyAIOCB *acb = (BlkverifyAIOCB *)blockacb;
|
||||
AioContext *aio_context = bdrv_get_aio_context(blockacb->bs);
|
||||
bool finished = false;
|
||||
|
||||
/* Wait until request completes, invokes its callback, and frees itself */
|
||||
acb->finished = &finished;
|
||||
while (!finished) {
|
||||
aio_poll(aio_context, true);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,8 +228,7 @@ static void blkverify_aio_cb(void *opaque, int ret)
|
||||
acb->verify(acb);
|
||||
}
|
||||
|
||||
acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs),
|
||||
blkverify_aio_bh, acb);
|
||||
acb->bh = qemu_bh_new(blkverify_aio_bh, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
break;
|
||||
}
|
||||
@@ -304,40 +302,21 @@ static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
return bdrv_recurse_is_first_non_filter(s->test_file, candidate);
|
||||
}
|
||||
|
||||
/* Propagate AioContext changes to ->test_file */
|
||||
static void blkverify_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
|
||||
bdrv_detach_aio_context(s->test_file);
|
||||
}
|
||||
|
||||
static void blkverify_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
|
||||
bdrv_attach_aio_context(s->test_file, new_context);
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_blkverify = {
|
||||
.format_name = "blkverify",
|
||||
.protocol_name = "blkverify",
|
||||
.instance_size = sizeof(BDRVBlkverifyState),
|
||||
.format_name = "blkverify",
|
||||
.protocol_name = "blkverify",
|
||||
.instance_size = sizeof(BDRVBlkverifyState),
|
||||
|
||||
.bdrv_parse_filename = blkverify_parse_filename,
|
||||
.bdrv_file_open = blkverify_open,
|
||||
.bdrv_close = blkverify_close,
|
||||
.bdrv_getlength = blkverify_getlength,
|
||||
.bdrv_parse_filename = blkverify_parse_filename,
|
||||
.bdrv_file_open = blkverify_open,
|
||||
.bdrv_close = blkverify_close,
|
||||
.bdrv_getlength = blkverify_getlength,
|
||||
|
||||
.bdrv_aio_readv = blkverify_aio_readv,
|
||||
.bdrv_aio_writev = blkverify_aio_writev,
|
||||
.bdrv_aio_flush = blkverify_aio_flush,
|
||||
.bdrv_aio_readv = blkverify_aio_readv,
|
||||
.bdrv_aio_writev = blkverify_aio_writev,
|
||||
.bdrv_aio_flush = blkverify_aio_flush,
|
||||
|
||||
.bdrv_attach_aio_context = blkverify_attach_aio_context,
|
||||
.bdrv_detach_aio_context = blkverify_detach_aio_context,
|
||||
|
||||
.is_filter = true,
|
||||
.is_filter = true,
|
||||
.bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter,
|
||||
};
|
||||
|
||||
|
@@ -187,14 +187,13 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
uint64_t offset = sector_num * 512;
|
||||
uint64_t extent_index, extent_offset, bitmap_offset;
|
||||
char bitmap_entry;
|
||||
int ret;
|
||||
|
||||
// seek to sector
|
||||
extent_index = offset / s->extent_size;
|
||||
extent_offset = (offset % s->extent_size) / 512;
|
||||
|
||||
if (s->catalog_bitmap[extent_index] == 0xffffffff) {
|
||||
return 0; /* not allocated */
|
||||
return -1; /* not allocated */
|
||||
}
|
||||
|
||||
bitmap_offset = s->data_offset +
|
||||
@@ -202,14 +201,13 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
(s->extent_blocks + s->bitmap_blocks));
|
||||
|
||||
/* read in bitmap for current extent */
|
||||
ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
||||
&bitmap_entry, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
||||
&bitmap_entry, 1) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!((bitmap_entry >> (extent_offset % 8)) & 1)) {
|
||||
return 0; /* not allocated */
|
||||
return -1; /* not allocated */
|
||||
}
|
||||
|
||||
return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
|
||||
@@ -222,16 +220,13 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
int64_t block_offset = seek_to_sector(bs, sector_num);
|
||||
if (block_offset < 0) {
|
||||
return block_offset;
|
||||
} else if (block_offset > 0) {
|
||||
if (block_offset >= 0) {
|
||||
ret = bdrv_pread(bs->file, block_offset, buf, 512);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
if (ret != 512) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
memset(buf, 0, 512);
|
||||
}
|
||||
nb_sectors--;
|
||||
sector_num++;
|
||||
buf += 512;
|
||||
|
@@ -72,7 +72,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
s->block_size = be32_to_cpu(s->block_size);
|
||||
if (s->block_size % 512) {
|
||||
error_setg(errp, "block_size %" PRIu32 " must be a multiple of 512",
|
||||
error_setg(errp, "block_size %u must be a multiple of 512",
|
||||
s->block_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -86,7 +86,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
* need a buffer this big.
|
||||
*/
|
||||
if (s->block_size > MAX_BLOCK_SIZE) {
|
||||
error_setg(errp, "block_size %" PRIu32 " must be %u MB or less",
|
||||
error_setg(errp, "block_size %u must be %u MB or less",
|
||||
s->block_size,
|
||||
MAX_BLOCK_SIZE / (1024 * 1024));
|
||||
return -EINVAL;
|
||||
@@ -101,7 +101,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
/* read offsets */
|
||||
if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) {
|
||||
/* Prevent integer overflow */
|
||||
error_setg(errp, "n_blocks %" PRIu32 " must be %zu or less",
|
||||
error_setg(errp, "n_blocks %u must be %zu or less",
|
||||
s->n_blocks,
|
||||
(UINT32_MAX - 1) / sizeof(uint64_t));
|
||||
return -EINVAL;
|
||||
@@ -133,7 +133,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
if (s->offsets[i] < s->offsets[i - 1]) {
|
||||
error_setg(errp, "offsets not monotonically increasing at "
|
||||
"index %" PRIu32 ", image file is corrupt", i);
|
||||
"index %u, image file is corrupt", i);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
@@ -146,8 +146,8 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
* ridiculous s->compressed_block allocation.
|
||||
*/
|
||||
if (size > 2 * MAX_BLOCK_SIZE) {
|
||||
error_setg(errp, "invalid compressed block size at index %" PRIu32
|
||||
", image file is corrupt", i);
|
||||
error_setg(errp, "invalid compressed block size at index %u, "
|
||||
"image file is corrupt", i);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
@@ -194,7 +194,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
|
||||
if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
|
||||
on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
|
||||
!bdrv_iostatus_is_enabled(bs)) {
|
||||
error_setg(errp, "Invalid parameter combination");
|
||||
error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -82,7 +82,7 @@ static int cow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (be32_to_cpu(cow_header.version) != COW_VERSION) {
|
||||
char version[64];
|
||||
snprintf(version, sizeof(version),
|
||||
"COW version %" PRIu32, cow_header.version);
|
||||
"COW version %d", cow_header.version);
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "cow", version);
|
||||
ret = -ENOTSUP;
|
||||
|
410
block/curl.c
410
block/curl.c
@@ -23,7 +23,6 @@
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
// #define DEBUG
|
||||
@@ -38,21 +37,6 @@
|
||||
#if LIBCURL_VERSION_NUM >= 0x071000
|
||||
/* The multi interface timer callback was introduced in 7.16.0 */
|
||||
#define NEED_CURL_TIMER_CALLBACK
|
||||
#define HAVE_SOCKET_ACTION
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SOCKET_ACTION
|
||||
/* If curl_multi_socket_action isn't available, define it statically here in
|
||||
* terms of curl_multi_socket. Note that ev_bitmask will be ignored, which is
|
||||
* less efficient but still safe. */
|
||||
static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
|
||||
curl_socket_t sockfd,
|
||||
int ev_bitmask,
|
||||
int *running_handles)
|
||||
{
|
||||
return curl_multi_socket(multi_handle, sockfd, running_handles);
|
||||
}
|
||||
#define curl_multi_socket_action __curl_multi_socket_action
|
||||
#endif
|
||||
|
||||
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
|
||||
@@ -62,16 +46,12 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
|
||||
#define CURL_NUM_STATES 8
|
||||
#define CURL_NUM_ACB 8
|
||||
#define SECTOR_SIZE 512
|
||||
#define READ_AHEAD_DEFAULT (256 * 1024)
|
||||
#define READ_AHEAD_SIZE (256 * 1024)
|
||||
|
||||
#define FIND_RET_NONE 0
|
||||
#define FIND_RET_OK 1
|
||||
#define FIND_RET_WAIT 2
|
||||
|
||||
#define CURL_BLOCK_OPT_URL "url"
|
||||
#define CURL_BLOCK_OPT_READAHEAD "readahead"
|
||||
#define CURL_BLOCK_OPT_SSLVERIFY "sslverify"
|
||||
|
||||
struct BDRVCURLState;
|
||||
|
||||
typedef struct CURLAIOCB {
|
||||
@@ -91,7 +71,6 @@ typedef struct CURLState
|
||||
struct BDRVCURLState *s;
|
||||
CURLAIOCB *acb[CURL_NUM_ACB];
|
||||
CURL *curl;
|
||||
curl_socket_t sock_fd;
|
||||
char *orig_buf;
|
||||
size_t buf_start;
|
||||
size_t buf_off;
|
||||
@@ -108,14 +87,11 @@ typedef struct BDRVCURLState {
|
||||
CURLState states[CURL_NUM_STATES];
|
||||
char *url;
|
||||
size_t readahead_size;
|
||||
bool sslverify;
|
||||
bool accept_range;
|
||||
AioContext *aio_context;
|
||||
} BDRVCURLState;
|
||||
|
||||
static void curl_clean_state(CURLState *s);
|
||||
static void curl_multi_do(void *arg);
|
||||
static void curl_multi_read(void *arg);
|
||||
|
||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
||||
@@ -135,29 +111,21 @@ static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
||||
#endif
|
||||
|
||||
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
||||
void *userp, void *sp)
|
||||
void *s, void *sp)
|
||||
{
|
||||
BDRVCURLState *s;
|
||||
CURLState *state = NULL;
|
||||
curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
|
||||
state->sock_fd = fd;
|
||||
s = state->s;
|
||||
|
||||
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
|
||||
switch (action) {
|
||||
case CURL_POLL_IN:
|
||||
aio_set_fd_handler(s->aio_context, fd, curl_multi_read,
|
||||
NULL, state);
|
||||
qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, s);
|
||||
break;
|
||||
case CURL_POLL_OUT:
|
||||
aio_set_fd_handler(s->aio_context, fd, NULL, curl_multi_do, state);
|
||||
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, s);
|
||||
break;
|
||||
case CURL_POLL_INOUT:
|
||||
aio_set_fd_handler(s->aio_context, fd, curl_multi_read,
|
||||
curl_multi_do, state);
|
||||
qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do, s);
|
||||
break;
|
||||
case CURL_POLL_REMOVE:
|
||||
aio_set_fd_handler(s->aio_context, fd, NULL, NULL, NULL);
|
||||
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -187,7 +155,7 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
||||
DPRINTF("CURL: Just reading %zd bytes\n", realsize);
|
||||
|
||||
if (!s || !s->orig_buf)
|
||||
return 0;
|
||||
goto read_end;
|
||||
|
||||
if (s->buf_off >= s->buf_len) {
|
||||
/* buffer full, read nothing */
|
||||
@@ -212,6 +180,7 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
read_end:
|
||||
return realsize;
|
||||
}
|
||||
|
||||
@@ -246,8 +215,7 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
||||
}
|
||||
|
||||
// Wait for unfinished chunks
|
||||
if (state->in_use &&
|
||||
(start >= state->buf_start) &&
|
||||
if ((start >= state->buf_start) &&
|
||||
(start <= buf_fend) &&
|
||||
(end >= state->buf_start) &&
|
||||
(end <= buf_fend))
|
||||
@@ -269,69 +237,68 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
||||
return FIND_RET_NONE;
|
||||
}
|
||||
|
||||
static void curl_multi_check_completion(BDRVCURLState *s)
|
||||
static void curl_multi_read(BDRVCURLState *s)
|
||||
{
|
||||
int msgs_in_queue;
|
||||
|
||||
/* Try to find done transfers, so we can free the easy
|
||||
* handle again. */
|
||||
for (;;) {
|
||||
do {
|
||||
CURLMsg *msg;
|
||||
msg = curl_multi_info_read(s->multi, &msgs_in_queue);
|
||||
|
||||
/* Quit when there are no more completions */
|
||||
if (!msg)
|
||||
break;
|
||||
|
||||
if (msg->msg == CURLMSG_DONE) {
|
||||
CURLState *state = NULL;
|
||||
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
|
||||
(char **)&state);
|
||||
|
||||
/* ACBs for successful messages get completed in curl_read_cb */
|
||||
if (msg->data.result != CURLE_OK) {
|
||||
int i;
|
||||
for (i = 0; i < CURL_NUM_ACB; i++) {
|
||||
CURLAIOCB *acb = state->acb[i];
|
||||
|
||||
if (acb == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
acb->common.cb(acb->common.opaque, -EIO);
|
||||
qemu_aio_release(acb);
|
||||
state->acb[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
curl_clean_state(state);
|
||||
if (msg->msg == CURLMSG_NONE)
|
||||
break;
|
||||
|
||||
switch (msg->msg) {
|
||||
case CURLMSG_DONE:
|
||||
{
|
||||
CURLState *state = NULL;
|
||||
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state);
|
||||
|
||||
/* ACBs for successful messages get completed in curl_read_cb */
|
||||
if (msg->data.result != CURLE_OK) {
|
||||
int i;
|
||||
for (i = 0; i < CURL_NUM_ACB; i++) {
|
||||
CURLAIOCB *acb = state->acb[i];
|
||||
|
||||
if (acb == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
acb->common.cb(acb->common.opaque, -EIO);
|
||||
qemu_aio_release(acb);
|
||||
state->acb[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
curl_clean_state(state);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
msgs_in_queue = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(msgs_in_queue);
|
||||
}
|
||||
|
||||
static void curl_multi_do(void *arg)
|
||||
{
|
||||
CURLState *s = (CURLState *)arg;
|
||||
BDRVCURLState *s = (BDRVCURLState *)arg;
|
||||
int running;
|
||||
int r;
|
||||
|
||||
if (!s->s->multi) {
|
||||
if (!s->multi) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
r = curl_multi_socket_action(s->s->multi, s->sock_fd, 0, &running);
|
||||
r = curl_multi_socket_all(s->multi, &running);
|
||||
} while(r == CURLM_CALL_MULTI_PERFORM);
|
||||
|
||||
}
|
||||
|
||||
static void curl_multi_read(void *arg)
|
||||
{
|
||||
CURLState *s = (CURLState *)arg;
|
||||
|
||||
curl_multi_do(arg);
|
||||
curl_multi_check_completion(s->s);
|
||||
curl_multi_read(s);
|
||||
}
|
||||
|
||||
static void curl_multi_timeout_do(void *arg)
|
||||
@@ -346,7 +313,7 @@ static void curl_multi_timeout_do(void *arg)
|
||||
|
||||
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||
|
||||
curl_multi_check_completion(s);
|
||||
curl_multi_read(s);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
@@ -370,44 +337,44 @@ static CURLState *curl_init_state(BDRVCURLState *s)
|
||||
break;
|
||||
}
|
||||
if (!state) {
|
||||
aio_poll(state->s->aio_context, true);
|
||||
g_usleep(100);
|
||||
curl_multi_do(s);
|
||||
}
|
||||
} while(!state);
|
||||
|
||||
if (!state->curl) {
|
||||
state->curl = curl_easy_init();
|
||||
if (!state->curl) {
|
||||
return NULL;
|
||||
}
|
||||
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
|
||||
curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER,
|
||||
(long) s->sslverify);
|
||||
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
|
||||
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
|
||||
(void *)curl_read_cb);
|
||||
curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
|
||||
curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
|
||||
curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
|
||||
curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
|
||||
curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
|
||||
curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
|
||||
if (state->curl)
|
||||
goto has_curl;
|
||||
|
||||
/* Restrict supported protocols to avoid security issues in the more
|
||||
* obscure protocols. For example, do not allow POP3/SMTP/IMAP see
|
||||
* CVE-2013-0249.
|
||||
*
|
||||
* Restricting protocols is only supported from 7.19.4 upwards.
|
||||
*/
|
||||
state->curl = curl_easy_init();
|
||||
if (!state->curl)
|
||||
return NULL;
|
||||
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
|
||||
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
|
||||
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
|
||||
curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
|
||||
curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
|
||||
curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
|
||||
curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
|
||||
curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
|
||||
curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
|
||||
|
||||
/* Restrict supported protocols to avoid security issues in the more
|
||||
* obscure protocols. For example, do not allow POP3/SMTP/IMAP see
|
||||
* CVE-2013-0249.
|
||||
*
|
||||
* Restricting protocols is only supported from 7.19.4 upwards.
|
||||
*/
|
||||
#if LIBCURL_VERSION_NUM >= 0x071304
|
||||
curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
|
||||
curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
|
||||
curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
|
||||
curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
|
||||
curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
has_curl:
|
||||
|
||||
state->s = s;
|
||||
|
||||
@@ -424,52 +391,43 @@ static void curl_clean_state(CURLState *s)
|
||||
static void curl_parse_filename(const char *filename, QDict *options,
|
||||
Error **errp)
|
||||
{
|
||||
qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(filename));
|
||||
}
|
||||
|
||||
static void curl_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
BDRVCURLState *s = bs->opaque;
|
||||
int i;
|
||||
#define RA_OPTSTR ":readahead="
|
||||
char *file;
|
||||
char *ra;
|
||||
const char *ra_val;
|
||||
int parse_state = 0;
|
||||
|
||||
for (i = 0; i < CURL_NUM_STATES; i++) {
|
||||
if (s->states[i].in_use) {
|
||||
curl_clean_state(&s->states[i]);
|
||||
file = g_strdup(filename);
|
||||
|
||||
/* Parse a trailing ":readahead=#:" param, if present. */
|
||||
ra = file + strlen(file) - 1;
|
||||
while (ra >= file) {
|
||||
if (parse_state == 0) {
|
||||
if (*ra == ':') {
|
||||
parse_state++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (parse_state == 1) {
|
||||
if (*ra > '9' || *ra < '0') {
|
||||
char *opt_start = ra - strlen(RA_OPTSTR) + 1;
|
||||
if (opt_start > file &&
|
||||
strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
|
||||
ra_val = ra + 1;
|
||||
ra -= strlen(RA_OPTSTR) - 1;
|
||||
*ra = '\0';
|
||||
qdict_put(options, "readahead", qstring_from_str(ra_val));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s->states[i].curl) {
|
||||
curl_easy_cleanup(s->states[i].curl);
|
||||
s->states[i].curl = NULL;
|
||||
}
|
||||
if (s->states[i].orig_buf) {
|
||||
g_free(s->states[i].orig_buf);
|
||||
s->states[i].orig_buf = NULL;
|
||||
}
|
||||
}
|
||||
if (s->multi) {
|
||||
curl_multi_cleanup(s->multi);
|
||||
s->multi = NULL;
|
||||
ra--;
|
||||
}
|
||||
|
||||
timer_del(&s->timer);
|
||||
}
|
||||
qdict_put(options, "url", qstring_from_str(file));
|
||||
|
||||
static void curl_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
BDRVCURLState *s = bs->opaque;
|
||||
|
||||
aio_timer_init(new_context, &s->timer,
|
||||
QEMU_CLOCK_REALTIME, SCALE_NS,
|
||||
curl_multi_timeout_do, s);
|
||||
|
||||
assert(!s->multi);
|
||||
s->multi = curl_multi_init();
|
||||
s->aio_context = new_context;
|
||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
|
||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
|
||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
|
||||
#endif
|
||||
g_free(file);
|
||||
}
|
||||
|
||||
static QemuOptsList runtime_opts = {
|
||||
@@ -477,20 +435,15 @@ static QemuOptsList runtime_opts = {
|
||||
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = CURL_BLOCK_OPT_URL,
|
||||
.name = "url",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "URL to open",
|
||||
},
|
||||
{
|
||||
.name = CURL_BLOCK_OPT_READAHEAD,
|
||||
.name = "readahead",
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "Readahead size",
|
||||
},
|
||||
{
|
||||
.name = CURL_BLOCK_OPT_SSLVERIFY,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Verify SSL certificate"
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@@ -519,17 +472,14 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
|
||||
READ_AHEAD_DEFAULT);
|
||||
s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE);
|
||||
if ((s->readahead_size & 0x1ff) != 0) {
|
||||
error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
|
||||
s->readahead_size);
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true);
|
||||
|
||||
file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL);
|
||||
file = qemu_opt_get(opts, "url");
|
||||
if (file == NULL) {
|
||||
error_setg(errp, "curl block driver requires an 'url' option");
|
||||
goto out_noclean;
|
||||
@@ -541,7 +491,6 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
DPRINTF("CURL: Opening %s\n", file);
|
||||
s->aio_context = bdrv_get_aio_context(bs);
|
||||
s->url = g_strdup(file);
|
||||
state = curl_init_state(s);
|
||||
if (!state)
|
||||
@@ -574,13 +523,27 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
curl_easy_cleanup(state->curl);
|
||||
state->curl = NULL;
|
||||
|
||||
curl_attach_aio_context(bs, bdrv_get_aio_context(bs));
|
||||
aio_timer_init(bdrv_get_aio_context(bs), &s->timer,
|
||||
QEMU_CLOCK_REALTIME, SCALE_NS,
|
||||
curl_multi_timeout_do, s);
|
||||
|
||||
// Now we know the file exists and its size, so let's
|
||||
// initialize the multi interface!
|
||||
|
||||
s->multi = curl_multi_init();
|
||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, s);
|
||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
|
||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
|
||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
|
||||
#endif
|
||||
curl_multi_do(s);
|
||||
|
||||
qemu_opts_del(opts);
|
||||
return 0;
|
||||
|
||||
out:
|
||||
error_setg(errp, "CURL: Error opening file: %s", state->errmsg);
|
||||
fprintf(stderr, "CURL: Error opening file: %s\n", state->errmsg);
|
||||
curl_easy_cleanup(state->curl);
|
||||
state->curl = NULL;
|
||||
out_noclean:
|
||||
@@ -603,7 +566,6 @@ static const AIOCBInfo curl_aiocb_info = {
|
||||
static void curl_readv_bh_cb(void *p)
|
||||
{
|
||||
CURLState *state;
|
||||
int running;
|
||||
|
||||
CURLAIOCB *acb = p;
|
||||
BDRVCURLState *s = acb->common.bs->opaque;
|
||||
@@ -652,9 +614,8 @@ static void curl_readv_bh_cb(void *p)
|
||||
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
|
||||
|
||||
curl_multi_add_handle(s->multi, state->curl);
|
||||
curl_multi_do(s);
|
||||
|
||||
/* Tell curl it needs to kick things off */
|
||||
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
|
||||
@@ -669,7 +630,7 @@ static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
|
||||
acb->sector_num = sector_num;
|
||||
acb->nb_sectors = nb_sectors;
|
||||
|
||||
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), curl_readv_bh_cb, acb);
|
||||
acb->bh = qemu_bh_new(curl_readv_bh_cb, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
return &acb->common;
|
||||
}
|
||||
@@ -677,9 +638,25 @@ static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
|
||||
static void curl_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVCURLState *s = bs->opaque;
|
||||
int i;
|
||||
|
||||
DPRINTF("CURL: Close\n");
|
||||
curl_detach_aio_context(bs);
|
||||
for (i=0; i<CURL_NUM_STATES; i++) {
|
||||
if (s->states[i].in_use)
|
||||
curl_clean_state(&s->states[i]);
|
||||
if (s->states[i].curl) {
|
||||
curl_easy_cleanup(s->states[i].curl);
|
||||
s->states[i].curl = NULL;
|
||||
}
|
||||
if (s->states[i].orig_buf) {
|
||||
g_free(s->states[i].orig_buf);
|
||||
s->states[i].orig_buf = NULL;
|
||||
}
|
||||
}
|
||||
if (s->multi)
|
||||
curl_multi_cleanup(s->multi);
|
||||
|
||||
timer_del(&s->timer);
|
||||
|
||||
g_free(s->url);
|
||||
}
|
||||
@@ -691,83 +668,68 @@ static int64_t curl_getlength(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_http = {
|
||||
.format_name = "http",
|
||||
.protocol_name = "http",
|
||||
.format_name = "http",
|
||||
.protocol_name = "http",
|
||||
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_parse_filename = curl_parse_filename,
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_parse_filename = curl_parse_filename,
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
|
||||
.bdrv_aio_readv = curl_aio_readv,
|
||||
|
||||
.bdrv_detach_aio_context = curl_detach_aio_context,
|
||||
.bdrv_attach_aio_context = curl_attach_aio_context,
|
||||
.bdrv_aio_readv = curl_aio_readv,
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_https = {
|
||||
.format_name = "https",
|
||||
.protocol_name = "https",
|
||||
.format_name = "https",
|
||||
.protocol_name = "https",
|
||||
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_parse_filename = curl_parse_filename,
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_parse_filename = curl_parse_filename,
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
|
||||
.bdrv_aio_readv = curl_aio_readv,
|
||||
|
||||
.bdrv_detach_aio_context = curl_detach_aio_context,
|
||||
.bdrv_attach_aio_context = curl_attach_aio_context,
|
||||
.bdrv_aio_readv = curl_aio_readv,
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_ftp = {
|
||||
.format_name = "ftp",
|
||||
.protocol_name = "ftp",
|
||||
.format_name = "ftp",
|
||||
.protocol_name = "ftp",
|
||||
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_parse_filename = curl_parse_filename,
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_parse_filename = curl_parse_filename,
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
|
||||
.bdrv_aio_readv = curl_aio_readv,
|
||||
|
||||
.bdrv_detach_aio_context = curl_detach_aio_context,
|
||||
.bdrv_attach_aio_context = curl_attach_aio_context,
|
||||
.bdrv_aio_readv = curl_aio_readv,
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_ftps = {
|
||||
.format_name = "ftps",
|
||||
.protocol_name = "ftps",
|
||||
.format_name = "ftps",
|
||||
.protocol_name = "ftps",
|
||||
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_parse_filename = curl_parse_filename,
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_parse_filename = curl_parse_filename,
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
|
||||
.bdrv_aio_readv = curl_aio_readv,
|
||||
|
||||
.bdrv_detach_aio_context = curl_detach_aio_context,
|
||||
.bdrv_attach_aio_context = curl_attach_aio_context,
|
||||
.bdrv_aio_readv = curl_aio_readv,
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_tftp = {
|
||||
.format_name = "tftp",
|
||||
.protocol_name = "tftp",
|
||||
.format_name = "tftp",
|
||||
.protocol_name = "tftp",
|
||||
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_parse_filename = curl_parse_filename,
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_parse_filename = curl_parse_filename,
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
|
||||
.bdrv_aio_readv = curl_aio_readv,
|
||||
|
||||
.bdrv_detach_aio_context = curl_detach_aio_context,
|
||||
.bdrv_attach_aio_context = curl_attach_aio_context,
|
||||
.bdrv_aio_readv = curl_aio_readv,
|
||||
};
|
||||
|
||||
static void curl_block_init(void)
|
||||
|
@@ -248,8 +248,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
offset += 8;
|
||||
|
||||
if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
|
||||
error_report("sector count %" PRIu64 " for chunk %" PRIu32
|
||||
" is larger than max (%u)",
|
||||
error_report("sector count %" PRIu64 " for chunk %u is "
|
||||
"larger than max (%u)",
|
||||
s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
@@ -269,8 +269,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
offset += 8;
|
||||
|
||||
if (s->lengths[i] > DMG_LENGTHS_MAX) {
|
||||
error_report("length %" PRIu64 " for chunk %" PRIu32
|
||||
" is larger than max (%u)",
|
||||
error_report("length %" PRIu64 " for chunk %u is larger "
|
||||
"than max (%u)",
|
||||
s->lengths[i], i, DMG_LENGTHS_MAX);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
|
@@ -16,7 +16,6 @@ typedef struct GlusterAIOCB {
|
||||
int ret;
|
||||
QEMUBH *bh;
|
||||
Coroutine *coroutine;
|
||||
AioContext *aio_context;
|
||||
} GlusterAIOCB;
|
||||
|
||||
typedef struct BDRVGlusterState {
|
||||
@@ -208,11 +207,6 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename,
|
||||
"volume=%s image=%s transport=%s", gconf->server,
|
||||
gconf->port, gconf->volname, gconf->image,
|
||||
gconf->transport);
|
||||
|
||||
/* glfs_init sometimes doesn't set errno although docs suggest that */
|
||||
if (errno == 0)
|
||||
errno = EINVAL;
|
||||
|
||||
goto out;
|
||||
}
|
||||
return glfs;
|
||||
@@ -250,7 +244,7 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
|
||||
acb->ret = -EIO; /* Partial read/write - fail it */
|
||||
}
|
||||
|
||||
acb->bh = aio_bh_new(acb->aio_context, qemu_gluster_complete_aio, acb);
|
||||
acb->bh = qemu_bh_new(qemu_gluster_complete_aio, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
}
|
||||
|
||||
@@ -437,7 +431,6 @@ static coroutine_fn int qemu_gluster_co_write_zeroes(BlockDriverState *bs,
|
||||
acb->size = size;
|
||||
acb->ret = 0;
|
||||
acb->coroutine = qemu_coroutine_self();
|
||||
acb->aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
ret = glfs_zerofill_async(s->fd, offset, size, &gluster_finish_aiocb, acb);
|
||||
if (ret < 0) {
|
||||
@@ -489,7 +482,7 @@ static int qemu_gluster_create(const char *filename,
|
||||
|
||||
glfs = qemu_gluster_init(gconf, filename, errp);
|
||||
if (!glfs) {
|
||||
ret = -errno;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -551,7 +544,6 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
|
||||
acb->size = size;
|
||||
acb->ret = 0;
|
||||
acb->coroutine = qemu_coroutine_self();
|
||||
acb->aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
if (write) {
|
||||
ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0,
|
||||
@@ -608,7 +600,6 @@ static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
|
||||
acb->size = 0;
|
||||
acb->ret = 0;
|
||||
acb->coroutine = qemu_coroutine_self();
|
||||
acb->aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
ret = glfs_fsync_async(s->fd, &gluster_finish_aiocb, acb);
|
||||
if (ret < 0) {
|
||||
@@ -637,7 +628,6 @@ static coroutine_fn int qemu_gluster_co_discard(BlockDriverState *bs,
|
||||
acb->size = 0;
|
||||
acb->ret = 0;
|
||||
acb->coroutine = qemu_coroutine_self();
|
||||
acb->aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
ret = glfs_discard_async(s->fd, offset, size, &gluster_finish_aiocb, acb);
|
||||
if (ret < 0) {
|
||||
|
408
block/iscsi.c
408
block/iscsi.c
@@ -2,7 +2,7 @@
|
||||
* QEMU Block driver for iSCSI images
|
||||
*
|
||||
* Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
||||
* Copyright (c) 2012-2014 Peter Lieven <pl@kamp.de>
|
||||
* Copyright (c) 2012-2013 Peter Lieven <pl@kamp.de>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -30,8 +30,6 @@
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/bitmap.h"
|
||||
#include "block/block_int.h"
|
||||
#include "trace.h"
|
||||
#include "block/scsi.h"
|
||||
@@ -49,7 +47,6 @@
|
||||
|
||||
typedef struct IscsiLun {
|
||||
struct iscsi_context *iscsi;
|
||||
AioContext *aio_context;
|
||||
int lun;
|
||||
enum scsi_inquiry_peripheral_device_type type;
|
||||
int block_size;
|
||||
@@ -62,8 +59,6 @@ typedef struct IscsiLun {
|
||||
struct scsi_inquiry_logical_block_provisioning lbp;
|
||||
struct scsi_inquiry_block_limits bl;
|
||||
unsigned char *zeroblock;
|
||||
unsigned long *allocationmap;
|
||||
int cluster_sectors;
|
||||
} IscsiLun;
|
||||
|
||||
typedef struct IscsiTask {
|
||||
@@ -74,7 +69,6 @@ typedef struct IscsiTask {
|
||||
struct scsi_task *task;
|
||||
Coroutine *co;
|
||||
QEMUBH *bh;
|
||||
IscsiLun *iscsilun;
|
||||
} IscsiTask;
|
||||
|
||||
typedef struct IscsiAIOCB {
|
||||
@@ -98,15 +92,6 @@ typedef struct IscsiAIOCB {
|
||||
#define MAX_NOP_FAILURES 3
|
||||
#define ISCSI_CMD_RETRIES 5
|
||||
|
||||
/* this threshhold is a trade-off knob to choose between
|
||||
* the potential additional overhead of an extra GET_LBA_STATUS request
|
||||
* vs. unnecessarily reading a lot of zero sectors over the wire.
|
||||
* If a read request is greater or equal than ISCSI_CHECKALLOC_THRES
|
||||
* sectors we check the allocation status of the area covered by the
|
||||
* request first if the allocationmap indicates that the area might be
|
||||
* unallocated. */
|
||||
#define ISCSI_CHECKALLOC_THRES 64
|
||||
|
||||
static void
|
||||
iscsi_bh_cb(void *p)
|
||||
{
|
||||
@@ -135,7 +120,7 @@ iscsi_schedule_bh(IscsiAIOCB *acb)
|
||||
if (acb->bh) {
|
||||
return;
|
||||
}
|
||||
acb->bh = aio_bh_new(acb->iscsilun->aio_context, iscsi_bh_cb, acb);
|
||||
acb->bh = qemu_bh_new(iscsi_bh_cb, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
}
|
||||
|
||||
@@ -171,8 +156,7 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
||||
|
||||
out:
|
||||
if (iTask->co) {
|
||||
iTask->bh = aio_bh_new(iTask->iscsilun->aio_context,
|
||||
iscsi_co_generic_bh_cb, iTask);
|
||||
iTask->bh = qemu_bh_new(iscsi_co_generic_bh_cb, iTask);
|
||||
qemu_bh_schedule(iTask->bh);
|
||||
}
|
||||
}
|
||||
@@ -180,9 +164,8 @@ out:
|
||||
static void iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask)
|
||||
{
|
||||
*iTask = (struct IscsiTask) {
|
||||
.co = qemu_coroutine_self(),
|
||||
.retries = ISCSI_CMD_RETRIES,
|
||||
.iscsilun = iscsilun,
|
||||
.co = qemu_coroutine_self(),
|
||||
.retries = ISCSI_CMD_RETRIES,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -213,7 +196,7 @@ iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
iscsi_abort_task_cb, acb);
|
||||
|
||||
while (acb->status == -EINPROGRESS) {
|
||||
aio_poll(iscsilun->aio_context, true);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,11 +219,10 @@ iscsi_set_events(IscsiLun *iscsilun)
|
||||
ev = POLLIN;
|
||||
ev |= iscsi_which_events(iscsi);
|
||||
if (ev != iscsilun->events) {
|
||||
aio_set_fd_handler(iscsilun->aio_context,
|
||||
iscsi_get_fd(iscsi),
|
||||
iscsi_process_read,
|
||||
(ev & POLLOUT) ? iscsi_process_write : NULL,
|
||||
iscsilun);
|
||||
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi),
|
||||
iscsi_process_read,
|
||||
(ev & POLLOUT) ? iscsi_process_write : NULL,
|
||||
iscsilun);
|
||||
|
||||
}
|
||||
|
||||
@@ -291,32 +273,6 @@ static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void iscsi_allocationmap_set(IscsiLun *iscsilun, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
if (iscsilun->allocationmap == NULL) {
|
||||
return;
|
||||
}
|
||||
bitmap_set(iscsilun->allocationmap,
|
||||
sector_num / iscsilun->cluster_sectors,
|
||||
DIV_ROUND_UP(nb_sectors, iscsilun->cluster_sectors));
|
||||
}
|
||||
|
||||
static void iscsi_allocationmap_clear(IscsiLun *iscsilun, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
int64_t cluster_num, nb_clusters;
|
||||
if (iscsilun->allocationmap == NULL) {
|
||||
return;
|
||||
}
|
||||
cluster_num = DIV_ROUND_UP(sector_num, iscsilun->cluster_sectors);
|
||||
nb_clusters = (sector_num + nb_sectors) / iscsilun->cluster_sectors
|
||||
- cluster_num;
|
||||
if (nb_clusters > 0) {
|
||||
bitmap_clear(iscsilun->allocationmap, cluster_num, nb_clusters);
|
||||
}
|
||||
}
|
||||
|
||||
static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov)
|
||||
@@ -380,125 +336,9 @@ retry:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,
|
||||
int64_t sector_num, int nb_sectors)
|
||||
{
|
||||
unsigned long size;
|
||||
if (iscsilun->allocationmap == NULL) {
|
||||
return true;
|
||||
}
|
||||
size = DIV_ROUND_UP(sector_num + nb_sectors, iscsilun->cluster_sectors);
|
||||
return !(find_next_bit(iscsilun->allocationmap, size,
|
||||
sector_num / iscsilun->cluster_sectors) == size);
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct scsi_get_lba_status *lbas = NULL;
|
||||
struct scsi_lba_status_descriptor *lbasd = NULL;
|
||||
struct IscsiTask iTask;
|
||||
int64_t ret;
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
|
||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* default to all sectors allocated */
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
|
||||
*pnum = nb_sectors;
|
||||
|
||||
/* LUN does not support logical block provisioning */
|
||||
if (iscsilun->lbpme == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
retry:
|
||||
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
|
||||
sector_qemu2lun(sector_num, iscsilun),
|
||||
8 + 16, iscsi_co_generic_cb,
|
||||
&iTask) == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (!iTask.complete) {
|
||||
iscsi_set_events(iscsilun);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
iTask.task = NULL;
|
||||
}
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
/* in case the get_lba_status_callout fails (i.e.
|
||||
* because the device is busy or the cmd is not
|
||||
* supported) we pretend all blocks are allocated
|
||||
* for backwards compatibility */
|
||||
goto out;
|
||||
}
|
||||
|
||||
lbas = scsi_datain_unmarshall(iTask.task);
|
||||
if (lbas == NULL) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lbasd = &lbas->descriptors[0];
|
||||
|
||||
if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
|
||||
|
||||
if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
|
||||
lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
|
||||
ret &= ~BDRV_BLOCK_DATA;
|
||||
if (iscsilun->lbprz) {
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret & BDRV_BLOCK_ZERO) {
|
||||
iscsi_allocationmap_clear(iscsilun, sector_num, *pnum);
|
||||
} else {
|
||||
iscsi_allocationmap_set(iscsilun, sector_num, *pnum);
|
||||
}
|
||||
|
||||
if (*pnum > nb_sectors) {
|
||||
*pnum = nb_sectors;
|
||||
}
|
||||
out:
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* LIBISCSI_FEATURE_IOVECTOR */
|
||||
|
||||
|
||||
static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov)
|
||||
@@ -515,22 +355,6 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
if (iscsilun->lbprz && nb_sectors >= ISCSI_CHECKALLOC_THRES &&
|
||||
!iscsi_allocationmap_is_allocated(iscsilun, sector_num, nb_sectors)) {
|
||||
int64_t ret;
|
||||
int pnum;
|
||||
ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (ret & BDRV_BLOCK_ZERO && pnum >= nb_sectors) {
|
||||
qemu_iovec_memset(iov, 0, 0x00, iov->size);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
|
||||
|
||||
@@ -796,7 +620,7 @@ static int iscsi_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
|
||||
iscsi_aio_ioctl(bs, req, buf, ioctl_cb, &status);
|
||||
|
||||
while (status == -EINPROGRESS) {
|
||||
aio_poll(iscsilun->aio_context, true);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -819,6 +643,101 @@ iscsi_getlength(BlockDriverState *bs)
|
||||
return len;
|
||||
}
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
|
||||
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct scsi_get_lba_status *lbas = NULL;
|
||||
struct scsi_lba_status_descriptor *lbasd = NULL;
|
||||
struct IscsiTask iTask;
|
||||
int64_t ret;
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
|
||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* default to all sectors allocated */
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
|
||||
*pnum = nb_sectors;
|
||||
|
||||
/* LUN does not support logical block provisioning */
|
||||
if (iscsilun->lbpme == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
retry:
|
||||
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
|
||||
sector_qemu2lun(sector_num, iscsilun),
|
||||
8 + 16, iscsi_co_generic_cb,
|
||||
&iTask) == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (!iTask.complete) {
|
||||
iscsi_set_events(iscsilun);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
iTask.task = NULL;
|
||||
}
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
/* in case the get_lba_status_callout fails (i.e.
|
||||
* because the device is busy or the cmd is not
|
||||
* supported) we pretend all blocks are allocated
|
||||
* for backwards compatibility */
|
||||
goto out;
|
||||
}
|
||||
|
||||
lbas = scsi_datain_unmarshall(iTask.task);
|
||||
if (lbas == NULL) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lbasd = &lbas->descriptors[0];
|
||||
|
||||
if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
|
||||
if (*pnum > nb_sectors) {
|
||||
*pnum = nb_sectors;
|
||||
}
|
||||
|
||||
if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
|
||||
lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
|
||||
ret &= ~BDRV_BLOCK_DATA;
|
||||
if (iscsilun->lbprz) {
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* LIBISCSI_FEATURE_IOVECTOR */
|
||||
|
||||
static int
|
||||
coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
@@ -872,8 +791,6 @@ retry:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -892,17 +809,16 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
|
||||
/* WRITE SAME with UNMAP is not supported by the target,
|
||||
* fall back and try WRITE SAME without UNMAP */
|
||||
flags &= ~BDRV_REQ_MAY_UNMAP;
|
||||
}
|
||||
|
||||
if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
|
||||
/* WRITE SAME without UNMAP is not supported by the target */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
|
||||
/* WRITE SAME with UNMAP is not supported by the target */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
nb_blocks = sector_qemu2lun(nb_sectors, iscsilun);
|
||||
|
||||
@@ -948,12 +864,6 @@ retry:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (flags & BDRV_REQ_MAY_UNMAP) {
|
||||
iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors);
|
||||
} else {
|
||||
iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1185,55 +1095,22 @@ static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
|
||||
*inq = scsi_datain_unmarshall(task);
|
||||
if (*inq == NULL) {
|
||||
error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
|
||||
goto fail_with_err;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return task;
|
||||
|
||||
fail:
|
||||
error_setg(errp, "iSCSI: Inquiry command failed : %s",
|
||||
iscsi_get_error(iscsi));
|
||||
fail_with_err:
|
||||
if (!error_is_set(errp)) {
|
||||
error_setg(errp, "iSCSI: Inquiry command failed : %s",
|
||||
iscsi_get_error(iscsi));
|
||||
}
|
||||
if (task != NULL) {
|
||||
scsi_free_scsi_task(task);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void iscsi_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
|
||||
aio_set_fd_handler(iscsilun->aio_context,
|
||||
iscsi_get_fd(iscsilun->iscsi),
|
||||
NULL, NULL, NULL);
|
||||
iscsilun->events = 0;
|
||||
|
||||
if (iscsilun->nop_timer) {
|
||||
timer_del(iscsilun->nop_timer);
|
||||
timer_free(iscsilun->nop_timer);
|
||||
iscsilun->nop_timer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void iscsi_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
|
||||
iscsilun->aio_context = new_context;
|
||||
iscsi_set_events(iscsilun);
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
||||
/* Set up a timer for sending out iSCSI NOPs */
|
||||
iscsilun->nop_timer = aio_timer_new(iscsilun->aio_context,
|
||||
QEMU_CLOCK_REALTIME, SCALE_MS,
|
||||
iscsi_nop_timed_event, iscsilun);
|
||||
timer_mod(iscsilun->nop_timer,
|
||||
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* We support iscsi url's on the form
|
||||
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
|
||||
@@ -1340,7 +1217,6 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
iscsilun->iscsi = iscsi;
|
||||
iscsilun->aio_context = bdrv_get_aio_context(bs);
|
||||
iscsilun->lun = iscsi_url->lun;
|
||||
iscsilun->has_write_same = true;
|
||||
|
||||
@@ -1414,23 +1290,11 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
scsi_free_scsi_task(task);
|
||||
task = NULL;
|
||||
|
||||
iscsi_attach_aio_context(bs, iscsilun->aio_context);
|
||||
|
||||
/* Guess the internal cluster (page) size of the iscsi target by the means
|
||||
* of opt_unmap_gran. Transfer the unmap granularity only if it has a
|
||||
* reasonable size */
|
||||
if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 4 * 1024 &&
|
||||
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
|
||||
iscsilun->cluster_sectors = (iscsilun->bl.opt_unmap_gran *
|
||||
iscsilun->block_size) >> BDRV_SECTOR_BITS;
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
if (iscsilun->lbprz && !(bs->open_flags & BDRV_O_NOCACHE)) {
|
||||
iscsilun->allocationmap =
|
||||
bitmap_new(DIV_ROUND_UP(bs->total_sectors,
|
||||
iscsilun->cluster_sectors));
|
||||
}
|
||||
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
||||
/* Set up a timer for sending out iSCSI NOPs */
|
||||
iscsilun->nop_timer = timer_new_ms(QEMU_CLOCK_REALTIME, iscsi_nop_timed_event, iscsilun);
|
||||
timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
out:
|
||||
qemu_opts_del(opts);
|
||||
@@ -1458,10 +1322,13 @@ static void iscsi_close(BlockDriverState *bs)
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||
|
||||
iscsi_detach_aio_context(bs);
|
||||
if (iscsilun->nop_timer) {
|
||||
timer_del(iscsilun->nop_timer);
|
||||
timer_free(iscsilun->nop_timer);
|
||||
}
|
||||
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL);
|
||||
iscsi_destroy_context(iscsi);
|
||||
g_free(iscsilun->zeroblock);
|
||||
g_free(iscsilun->allocationmap);
|
||||
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||
}
|
||||
|
||||
@@ -1522,13 +1389,6 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iscsilun->allocationmap != NULL) {
|
||||
g_free(iscsilun->allocationmap);
|
||||
iscsilun->allocationmap =
|
||||
bitmap_new(DIV_ROUND_UP(bs->total_sectors,
|
||||
iscsilun->cluster_sectors));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1541,7 +1401,7 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options,
|
||||
IscsiLun *iscsilun = NULL;
|
||||
QDict *bs_options;
|
||||
|
||||
bs = bdrv_new("", &error_abort);
|
||||
bs = bdrv_new("");
|
||||
|
||||
/* Read out options */
|
||||
while (options && options->name) {
|
||||
@@ -1562,7 +1422,10 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options,
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
iscsi_detach_aio_context(bs);
|
||||
if (iscsilun->nop_timer) {
|
||||
timer_del(iscsilun->nop_timer);
|
||||
timer_free(iscsilun->nop_timer);
|
||||
}
|
||||
if (iscsilun->type != TYPE_DISK) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
@@ -1588,7 +1451,13 @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz;
|
||||
bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws;
|
||||
bdi->cluster_size = iscsilun->cluster_sectors * BDRV_SECTOR_SIZE;
|
||||
/* Guess the internal cluster (page) size of the iscsi target by the means
|
||||
* of opt_unmap_gran. Transfer the unmap granularity only if it has a
|
||||
* reasonable size for bdi->cluster_size */
|
||||
if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 64 * 1024 &&
|
||||
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
|
||||
bdi->cluster_size = iscsilun->bl.opt_unmap_gran * iscsilun->block_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1633,9 +1502,6 @@ static BlockDriver bdrv_iscsi = {
|
||||
.bdrv_ioctl = iscsi_ioctl,
|
||||
.bdrv_aio_ioctl = iscsi_aio_ioctl,
|
||||
#endif
|
||||
|
||||
.bdrv_detach_aio_context = iscsi_detach_aio_context,
|
||||
.bdrv_attach_aio_context = iscsi_attach_aio_context,
|
||||
};
|
||||
|
||||
static QemuOptsList qemu_iscsi_opts = {
|
||||
|
@@ -177,20 +177,6 @@ out_free_aiocb:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void laio_detach_aio_context(void *s_, AioContext *old_context)
|
||||
{
|
||||
struct qemu_laio_state *s = s_;
|
||||
|
||||
aio_set_event_notifier(old_context, &s->e, NULL);
|
||||
}
|
||||
|
||||
void laio_attach_aio_context(void *s_, AioContext *new_context)
|
||||
{
|
||||
struct qemu_laio_state *s = s_;
|
||||
|
||||
aio_set_event_notifier(new_context, &s->e, qemu_laio_completion_cb);
|
||||
}
|
||||
|
||||
void *laio_init(void)
|
||||
{
|
||||
struct qemu_laio_state *s;
|
||||
@@ -204,6 +190,8 @@ void *laio_init(void)
|
||||
goto out_close_efd;
|
||||
}
|
||||
|
||||
qemu_aio_set_event_notifier(&s->e, qemu_laio_completion_cb);
|
||||
|
||||
return s;
|
||||
|
||||
out_close_efd:
|
||||
@@ -212,11 +200,3 @@ out_free_state:
|
||||
g_free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void laio_cleanup(void *s_)
|
||||
{
|
||||
struct qemu_laio_state *s = s_;
|
||||
|
||||
event_notifier_cleanup(&s->e);
|
||||
g_free(s);
|
||||
}
|
||||
|
@@ -259,9 +259,11 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
next_sector = sector_num;
|
||||
while (nb_chunks-- > 0) {
|
||||
MirrorBuffer *buf = QSIMPLEQ_FIRST(&s->buf_free);
|
||||
size_t remaining = (nb_sectors * BDRV_SECTOR_SIZE) - op->qiov.size;
|
||||
|
||||
QSIMPLEQ_REMOVE_HEAD(&s->buf_free, next);
|
||||
s->buf_free_count--;
|
||||
qemu_iovec_add(&op->qiov, buf, s->granularity);
|
||||
qemu_iovec_add(&op->qiov, buf, MIN(s->granularity, remaining));
|
||||
|
||||
/* Advance the HBitmapIter in parallel, so that we do not examine
|
||||
* the same sector twice.
|
||||
@@ -324,12 +326,21 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
}
|
||||
|
||||
s->common.len = bdrv_getlength(bs);
|
||||
if (s->common.len <= 0) {
|
||||
if (s->common.len < 0) {
|
||||
ret = s->common.len;
|
||||
goto immediate_exit;
|
||||
} else if (s->common.len == 0) {
|
||||
/* Report BLOCK_JOB_READY and wait for complete. */
|
||||
block_job_ready(&s->common);
|
||||
s->synced = true;
|
||||
while (!block_job_is_cancelled(&s->common) && !s->should_complete) {
|
||||
block_job_yield(&s->common);
|
||||
}
|
||||
s->common.cancelled = false;
|
||||
goto immediate_exit;
|
||||
}
|
||||
|
||||
length = DIV_ROUND_UP(s->common.len, s->granularity);
|
||||
length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity;
|
||||
s->in_flight_bitmap = bitmap_new(length);
|
||||
|
||||
/* If we have no backing file yet in the destination, we cannot let
|
||||
@@ -339,10 +350,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
bdrv_get_backing_filename(s->target, backing_filename,
|
||||
sizeof(backing_filename));
|
||||
if (backing_filename[0] && !s->target->backing_hd) {
|
||||
ret = bdrv_get_info(s->target, &bdi);
|
||||
if (ret < 0) {
|
||||
goto immediate_exit;
|
||||
}
|
||||
bdrv_get_info(s->target, &bdi);
|
||||
if (s->granularity < bdi.cluster_size) {
|
||||
s->buf_size = MAX(s->buf_size, bdi.cluster_size);
|
||||
s->cow_bitmap = bitmap_new(length);
|
||||
@@ -498,7 +506,7 @@ immediate_exit:
|
||||
/* drop the bs loop chain formed by the swap: break the loop then
|
||||
* trigger the unref from the top one */
|
||||
BlockDriverState *p = s->base->backing_hd;
|
||||
bdrv_set_backing_hd(s->base, NULL);
|
||||
s->base->backing_hd = NULL;
|
||||
bdrv_unref(p);
|
||||
}
|
||||
}
|
||||
@@ -608,10 +616,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
||||
s->granularity = granularity;
|
||||
s->buf_size = MAX(buf_size, granularity);
|
||||
|
||||
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, errp);
|
||||
if (!s->dirty_bitmap) {
|
||||
return;
|
||||
}
|
||||
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity);
|
||||
bdrv_set_enable_write_cache(s->target, true);
|
||||
bdrv_set_on_error(s->target, on_target_error, on_target_error);
|
||||
bdrv_iostatus_enable(s->target);
|
||||
@@ -683,7 +688,7 @@ void commit_active_start(BlockDriverState *bs, BlockDriverState *base,
|
||||
mirror_start_job(bs, base, speed, 0, 0,
|
||||
on_error, on_error, cb, opaque, &local_err,
|
||||
&commit_active_job_driver, false, base);
|
||||
if (local_err) {
|
||||
if (error_is_set(&local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
goto error_restore_flags;
|
||||
}
|
||||
|
@@ -49,7 +49,7 @@ static void nbd_teardown_connection(NbdClientSession *client)
|
||||
shutdown(client->sock, 2);
|
||||
nbd_recv_coroutines_enter_all(client);
|
||||
|
||||
nbd_client_session_detach_aio_context(client);
|
||||
qemu_aio_set_fd_handler(client->sock, NULL, NULL, NULL);
|
||||
closesocket(client->sock);
|
||||
client->sock = -1;
|
||||
}
|
||||
@@ -103,14 +103,11 @@ static int nbd_co_send_request(NbdClientSession *s,
|
||||
struct nbd_request *request,
|
||||
QEMUIOVector *qiov, int offset)
|
||||
{
|
||||
AioContext *aio_context;
|
||||
int rc, ret;
|
||||
|
||||
qemu_co_mutex_lock(&s->send_mutex);
|
||||
s->send_coroutine = qemu_coroutine_self();
|
||||
aio_context = bdrv_get_aio_context(s->bs);
|
||||
aio_set_fd_handler(aio_context, s->sock,
|
||||
nbd_reply_ready, nbd_restart_write, s);
|
||||
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write, s);
|
||||
if (qiov) {
|
||||
if (!s->is_unix) {
|
||||
socket_set_cork(s->sock, 1);
|
||||
@@ -129,7 +126,7 @@ static int nbd_co_send_request(NbdClientSession *s,
|
||||
} else {
|
||||
rc = nbd_send_request(s->sock, request);
|
||||
}
|
||||
aio_set_fd_handler(aio_context, s->sock, nbd_reply_ready, NULL, s);
|
||||
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL, s);
|
||||
s->send_coroutine = NULL;
|
||||
qemu_co_mutex_unlock(&s->send_mutex);
|
||||
return rc;
|
||||
@@ -338,19 +335,6 @@ int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
|
||||
|
||||
}
|
||||
|
||||
void nbd_client_session_detach_aio_context(NbdClientSession *client)
|
||||
{
|
||||
aio_set_fd_handler(bdrv_get_aio_context(client->bs), client->sock,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void nbd_client_session_attach_aio_context(NbdClientSession *client,
|
||||
AioContext *new_context)
|
||||
{
|
||||
aio_set_fd_handler(new_context, client->sock,
|
||||
nbd_reply_ready, NULL, client);
|
||||
}
|
||||
|
||||
void nbd_client_session_close(NbdClientSession *client)
|
||||
{
|
||||
struct nbd_request request = {
|
||||
@@ -397,7 +381,7 @@ int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
|
||||
/* Now that we're connected, set the socket to be non-blocking and
|
||||
* kick the reply mechanism. */
|
||||
qemu_set_nonblock(sock);
|
||||
nbd_client_session_attach_aio_context(client, bdrv_get_aio_context(bs));
|
||||
qemu_aio_set_fd_handler(sock, nbd_reply_ready, NULL, client);
|
||||
|
||||
logout("Established connection with NBD server\n");
|
||||
return 0;
|
||||
|
@@ -47,8 +47,4 @@ int nbd_client_session_co_writev(NbdClientSession *client, int64_t sector_num,
|
||||
int nbd_client_session_co_readv(NbdClientSession *client, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov);
|
||||
|
||||
void nbd_client_session_detach_aio_context(NbdClientSession *client);
|
||||
void nbd_client_session_attach_aio_context(NbdClientSession *client,
|
||||
AioContext *new_context);
|
||||
|
||||
#endif /* NBD_CLIENT_H */
|
||||
|
89
block/nbd.c
89
block/nbd.c
@@ -175,7 +175,7 @@ static void nbd_parse_filename(const char *filename, QDict *options,
|
||||
InetSocketAddress *addr = NULL;
|
||||
|
||||
addr = inet_parse(host_spec, errp);
|
||||
if (!addr) {
|
||||
if (error_is_set(errp)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -323,67 +323,46 @@ static int64_t nbd_getlength(BlockDriverState *bs)
|
||||
return s->client.size;
|
||||
}
|
||||
|
||||
static void nbd_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
BDRVNBDState *s = bs->opaque;
|
||||
|
||||
nbd_client_session_detach_aio_context(&s->client);
|
||||
}
|
||||
|
||||
static void nbd_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
BDRVNBDState *s = bs->opaque;
|
||||
|
||||
nbd_client_session_attach_aio_context(&s->client, new_context);
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_nbd = {
|
||||
.format_name = "nbd",
|
||||
.protocol_name = "nbd",
|
||||
.instance_size = sizeof(BDRVNBDState),
|
||||
.bdrv_parse_filename = nbd_parse_filename,
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_readv = nbd_co_readv,
|
||||
.bdrv_co_writev = nbd_co_writev,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_discard = nbd_co_discard,
|
||||
.bdrv_getlength = nbd_getlength,
|
||||
.bdrv_detach_aio_context = nbd_detach_aio_context,
|
||||
.bdrv_attach_aio_context = nbd_attach_aio_context,
|
||||
.format_name = "nbd",
|
||||
.protocol_name = "nbd",
|
||||
.instance_size = sizeof(BDRVNBDState),
|
||||
.bdrv_parse_filename = nbd_parse_filename,
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_readv = nbd_co_readv,
|
||||
.bdrv_co_writev = nbd_co_writev,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_discard = nbd_co_discard,
|
||||
.bdrv_getlength = nbd_getlength,
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_nbd_tcp = {
|
||||
.format_name = "nbd",
|
||||
.protocol_name = "nbd+tcp",
|
||||
.instance_size = sizeof(BDRVNBDState),
|
||||
.bdrv_parse_filename = nbd_parse_filename,
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_readv = nbd_co_readv,
|
||||
.bdrv_co_writev = nbd_co_writev,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_discard = nbd_co_discard,
|
||||
.bdrv_getlength = nbd_getlength,
|
||||
.bdrv_detach_aio_context = nbd_detach_aio_context,
|
||||
.bdrv_attach_aio_context = nbd_attach_aio_context,
|
||||
.format_name = "nbd",
|
||||
.protocol_name = "nbd+tcp",
|
||||
.instance_size = sizeof(BDRVNBDState),
|
||||
.bdrv_parse_filename = nbd_parse_filename,
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_readv = nbd_co_readv,
|
||||
.bdrv_co_writev = nbd_co_writev,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_discard = nbd_co_discard,
|
||||
.bdrv_getlength = nbd_getlength,
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_nbd_unix = {
|
||||
.format_name = "nbd",
|
||||
.protocol_name = "nbd+unix",
|
||||
.instance_size = sizeof(BDRVNBDState),
|
||||
.bdrv_parse_filename = nbd_parse_filename,
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_readv = nbd_co_readv,
|
||||
.bdrv_co_writev = nbd_co_writev,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_discard = nbd_co_discard,
|
||||
.bdrv_getlength = nbd_getlength,
|
||||
.bdrv_detach_aio_context = nbd_detach_aio_context,
|
||||
.bdrv_attach_aio_context = nbd_attach_aio_context,
|
||||
.format_name = "nbd",
|
||||
.protocol_name = "nbd+unix",
|
||||
.instance_size = sizeof(BDRVNBDState),
|
||||
.bdrv_parse_filename = nbd_parse_filename,
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_readv = nbd_co_readv,
|
||||
.bdrv_co_writev = nbd_co_writev,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_discard = nbd_co_discard,
|
||||
.bdrv_getlength = nbd_getlength,
|
||||
};
|
||||
|
||||
static void bdrv_nbd_init(void)
|
||||
|
81
block/nfs.c
81
block/nfs.c
@@ -40,7 +40,6 @@ typedef struct NFSClient {
|
||||
struct nfsfh *fh;
|
||||
int events;
|
||||
bool has_zero_init;
|
||||
AioContext *aio_context;
|
||||
} NFSClient;
|
||||
|
||||
typedef struct NFSRPC {
|
||||
@@ -50,7 +49,6 @@ typedef struct NFSRPC {
|
||||
struct stat *st;
|
||||
Coroutine *co;
|
||||
QEMUBH *bh;
|
||||
NFSClient *client;
|
||||
} NFSRPC;
|
||||
|
||||
static void nfs_process_read(void *arg);
|
||||
@@ -60,11 +58,10 @@ static void nfs_set_events(NFSClient *client)
|
||||
{
|
||||
int ev = nfs_which_events(client->context);
|
||||
if (ev != client->events) {
|
||||
aio_set_fd_handler(client->aio_context,
|
||||
nfs_get_fd(client->context),
|
||||
(ev & POLLIN) ? nfs_process_read : NULL,
|
||||
(ev & POLLOUT) ? nfs_process_write : NULL,
|
||||
client);
|
||||
qemu_aio_set_fd_handler(nfs_get_fd(client->context),
|
||||
(ev & POLLIN) ? nfs_process_read : NULL,
|
||||
(ev & POLLOUT) ? nfs_process_write : NULL,
|
||||
client);
|
||||
|
||||
}
|
||||
client->events = ev;
|
||||
@@ -87,8 +84,7 @@ static void nfs_process_write(void *arg)
|
||||
static void nfs_co_init_task(NFSClient *client, NFSRPC *task)
|
||||
{
|
||||
*task = (NFSRPC) {
|
||||
.co = qemu_coroutine_self(),
|
||||
.client = client,
|
||||
.co = qemu_coroutine_self(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -120,8 +116,7 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
|
||||
error_report("NFS Error: %s", nfs_get_error(nfs));
|
||||
}
|
||||
if (task->co) {
|
||||
task->bh = aio_bh_new(task->client->aio_context,
|
||||
nfs_co_generic_bh_cb, task);
|
||||
task->bh = qemu_bh_new(nfs_co_generic_bh_cb, task);
|
||||
qemu_bh_schedule(task->bh);
|
||||
}
|
||||
}
|
||||
@@ -229,34 +224,13 @@ static QemuOptsList runtime_opts = {
|
||||
},
|
||||
};
|
||||
|
||||
static void nfs_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
NFSClient *client = bs->opaque;
|
||||
|
||||
aio_set_fd_handler(client->aio_context,
|
||||
nfs_get_fd(client->context),
|
||||
NULL, NULL, NULL);
|
||||
client->events = 0;
|
||||
}
|
||||
|
||||
static void nfs_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
NFSClient *client = bs->opaque;
|
||||
|
||||
client->aio_context = new_context;
|
||||
nfs_set_events(client);
|
||||
}
|
||||
|
||||
static void nfs_client_close(NFSClient *client)
|
||||
{
|
||||
if (client->context) {
|
||||
if (client->fh) {
|
||||
nfs_close(client->context, client->fh);
|
||||
}
|
||||
aio_set_fd_handler(client->aio_context,
|
||||
nfs_get_fd(client->context),
|
||||
NULL, NULL, NULL);
|
||||
qemu_aio_set_fd_handler(nfs_get_fd(client->context), NULL, NULL, NULL);
|
||||
nfs_destroy_context(client->context);
|
||||
}
|
||||
memset(client, 0, sizeof(NFSClient));
|
||||
@@ -282,10 +256,6 @@ static int64_t nfs_client_open(NFSClient *client, const char *filename,
|
||||
error_setg(errp, "Invalid URL specified");
|
||||
goto fail;
|
||||
}
|
||||
if (!uri->server) {
|
||||
error_setg(errp, "Invalid URL specified");
|
||||
goto fail;
|
||||
}
|
||||
strp = strrchr(uri->path, '/');
|
||||
if (strp == NULL) {
|
||||
error_setg(errp, "Invalid URL specified");
|
||||
@@ -371,11 +341,9 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
|
||||
client->aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
if (error_is_set(&local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -396,8 +364,6 @@ static int nfs_file_create(const char *url, QEMUOptionParameter *options,
|
||||
int64_t total_size = 0;
|
||||
NFSClient *client = g_malloc0(sizeof(NFSClient));
|
||||
|
||||
client->aio_context = qemu_get_aio_context();
|
||||
|
||||
/* Read out options */
|
||||
while (options && options->name) {
|
||||
if (!strcmp(options->name, "size")) {
|
||||
@@ -437,7 +403,7 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
|
||||
|
||||
while (!task.complete) {
|
||||
nfs_set_events(client);
|
||||
aio_poll(client->aio_context, true);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
|
||||
return (task.ret < 0 ? task.ret : st.st_blocks * st.st_blksize);
|
||||
@@ -450,25 +416,22 @@ static int nfs_file_truncate(BlockDriverState *bs, int64_t offset)
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_nfs = {
|
||||
.format_name = "nfs",
|
||||
.protocol_name = "nfs",
|
||||
.format_name = "nfs",
|
||||
.protocol_name = "nfs",
|
||||
|
||||
.instance_size = sizeof(NFSClient),
|
||||
.bdrv_needs_filename = true,
|
||||
.bdrv_has_zero_init = nfs_has_zero_init,
|
||||
.bdrv_get_allocated_file_size = nfs_get_allocated_file_size,
|
||||
.bdrv_truncate = nfs_file_truncate,
|
||||
.instance_size = sizeof(NFSClient),
|
||||
.bdrv_needs_filename = true,
|
||||
.bdrv_has_zero_init = nfs_has_zero_init,
|
||||
.bdrv_get_allocated_file_size = nfs_get_allocated_file_size,
|
||||
.bdrv_truncate = nfs_file_truncate,
|
||||
|
||||
.bdrv_file_open = nfs_file_open,
|
||||
.bdrv_close = nfs_file_close,
|
||||
.bdrv_create = nfs_file_create,
|
||||
.bdrv_file_open = nfs_file_open,
|
||||
.bdrv_close = nfs_file_close,
|
||||
.bdrv_create = nfs_file_create,
|
||||
|
||||
.bdrv_co_readv = nfs_co_readv,
|
||||
.bdrv_co_writev = nfs_co_writev,
|
||||
.bdrv_co_flush_to_disk = nfs_co_flush,
|
||||
|
||||
.bdrv_detach_aio_context = nfs_detach_aio_context,
|
||||
.bdrv_attach_aio_context = nfs_attach_aio_context,
|
||||
.bdrv_co_readv = nfs_co_readv,
|
||||
.bdrv_co_writev = nfs_co_writev,
|
||||
.bdrv_co_flush_to_disk = nfs_co_flush,
|
||||
};
|
||||
|
||||
static void nfs_block_init(void)
|
||||
|
@@ -50,7 +50,6 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
info->backing_file_depth = bdrv_get_backing_file_depth(bs);
|
||||
info->detect_zeroes = bs->detect_zeroes;
|
||||
|
||||
if (bs->io_limits_enabled) {
|
||||
ThrottleConfig cfg;
|
||||
@@ -534,11 +533,12 @@ static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
|
||||
void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
|
||||
ImageInfoSpecific *info_spec)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||
QObject *obj, *data;
|
||||
|
||||
visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), &info_spec, NULL,
|
||||
&error_abort);
|
||||
&local_err);
|
||||
obj = qmp_output_get_qobject(ov);
|
||||
assert(qobject_type(obj) == QTYPE_QDICT);
|
||||
data = qdict_get(qobject_to_qdict(obj), "data");
|
||||
|
@@ -121,8 +121,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
if (header.version != QCOW_VERSION) {
|
||||
char version[64];
|
||||
snprintf(version, sizeof(version), "QCOW version %" PRIu32,
|
||||
header.version);
|
||||
snprintf(version, sizeof(version), "QCOW version %d", header.version);
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "qcow", version);
|
||||
ret = -ENOTSUP;
|
||||
|
@@ -42,13 +42,6 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
||||
if (min_size <= s->l1_size)
|
||||
return 0;
|
||||
|
||||
/* Do a sanity check on min_size before trying to calculate new_l1_size
|
||||
* (this prevents overflows during the while loop for the calculation of
|
||||
* new_l1_size) */
|
||||
if (min_size > INT_MAX / sizeof(uint64_t)) {
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
if (exact_size) {
|
||||
new_l1_size = min_size;
|
||||
} else {
|
||||
@@ -379,8 +372,7 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
|
||||
|
||||
if (!bs->drv) {
|
||||
ret = -ENOMEDIUM;
|
||||
goto out;
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
/* Call .bdrv_co_readv() directly instead of using the public block-layer
|
||||
@@ -1368,9 +1360,9 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||
|
||||
for (i = 0; i < nb_clusters; i++) {
|
||||
uint64_t old_l2_entry;
|
||||
uint64_t old_offset;
|
||||
|
||||
old_l2_entry = be64_to_cpu(l2_table[l2_index + i]);
|
||||
old_offset = be64_to_cpu(l2_table[l2_index + i]);
|
||||
|
||||
/*
|
||||
* Make sure that a discarded area reads back as zeroes for v3 images
|
||||
@@ -1381,22 +1373,12 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
* TODO We might want to use bdrv_get_block_status(bs) here, but we're
|
||||
* holding s->lock, so that doesn't work today.
|
||||
*/
|
||||
switch (qcow2_get_cluster_type(old_l2_entry)) {
|
||||
case QCOW2_CLUSTER_UNALLOCATED:
|
||||
if (!bs->backing_hd) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
if (old_offset & QCOW_OFLAG_ZERO) {
|
||||
continue;
|
||||
}
|
||||
|
||||
case QCOW2_CLUSTER_ZERO:
|
||||
continue;
|
||||
|
||||
case QCOW2_CLUSTER_NORMAL:
|
||||
case QCOW2_CLUSTER_COMPRESSED:
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
if ((old_offset & L2E_OFFSET_MASK) == 0 && !bs->backing_hd) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* First remove L2 entries */
|
||||
@@ -1408,7 +1390,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
}
|
||||
|
||||
/* Then decrease the refcount */
|
||||
qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
|
||||
qcow2_free_any_clusters(bs, old_offset, 1, type);
|
||||
}
|
||||
|
||||
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||
|
@@ -653,15 +653,6 @@ retry:
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure that all offsets in the "allocated" range are representable
|
||||
* in an int64_t */
|
||||
if (s->free_cluster_index > 0 &&
|
||||
s->free_cluster_index - 1 > (INT64_MAX >> s->cluster_bits))
|
||||
{
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ALLOC2
|
||||
fprintf(stderr, "alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
|
||||
size,
|
||||
@@ -1489,11 +1480,6 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
int ret;
|
||||
|
||||
size = bdrv_getlength(bs->file);
|
||||
if (size < 0) {
|
||||
res->check_errors++;
|
||||
return size;
|
||||
}
|
||||
|
||||
nb_clusters = size_to_clusters(s, size);
|
||||
if (nb_clusters > INT_MAX) {
|
||||
res->check_errors++;
|
||||
|
@@ -124,9 +124,8 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||
|
||||
case QCOW2_EXT_MAGIC_BACKING_FORMAT:
|
||||
if (ext.len >= sizeof(bs->backing_format)) {
|
||||
error_setg(errp, "ERROR: ext_backing_format: len=%" PRIu32
|
||||
" too large (>=%zu)", ext.len,
|
||||
sizeof(bs->backing_format));
|
||||
error_setg(errp, "ERROR: ext_backing_format: len=%u too large"
|
||||
" (>=%zu)", ext.len, sizeof(bs->backing_format));
|
||||
return 2;
|
||||
}
|
||||
ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len);
|
||||
@@ -484,7 +483,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
if (header.version < 2 || header.version > 3) {
|
||||
report_unsupported(bs, errp, "QCOW version %" PRIu32, header.version);
|
||||
report_unsupported(bs, errp, "QCOW version %d", header.version);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
@@ -494,8 +493,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
/* Initialise cluster size */
|
||||
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
||||
header.cluster_bits > MAX_CLUSTER_BITS) {
|
||||
error_setg(errp, "Unsupported cluster size: 2^%" PRIu32,
|
||||
header.cluster_bits);
|
||||
error_setg(errp, "Unsupported cluster size: 2^%i", header.cluster_bits);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
@@ -593,7 +591,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->refcount_order = header.refcount_order;
|
||||
|
||||
if (header.crypt_method > QCOW_CRYPT_AES) {
|
||||
error_setg(errp, "Unsupported encryption method: %" PRIu32,
|
||||
error_setg(errp, "Unsupported encryption method: %i",
|
||||
header.crypt_method);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
|
@@ -173,7 +173,7 @@ int qed_read_l1_table_sync(BDRVQEDState *s)
|
||||
qed_read_table(s, s->header.l1_table_offset,
|
||||
s->l1_table, qed_sync_cb, &ret);
|
||||
while (ret == -EINPROGRESS) {
|
||||
aio_poll(bdrv_get_aio_context(s->bs), true);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -194,7 +194,7 @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
|
||||
|
||||
qed_write_l1_table(s, index, n, qed_sync_cb, &ret);
|
||||
while (ret == -EINPROGRESS) {
|
||||
aio_poll(bdrv_get_aio_context(s->bs), true);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -267,7 +267,7 @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset
|
||||
|
||||
qed_read_l2_table(s, request, offset, qed_sync_cb, &ret);
|
||||
while (ret == -EINPROGRESS) {
|
||||
aio_poll(bdrv_get_aio_context(s->bs), true);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -289,7 +289,7 @@ int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
|
||||
|
||||
qed_write_l2_table(s, request, index, n, flush, qed_sync_cb, &ret);
|
||||
while (ret == -EINPROGRESS) {
|
||||
aio_poll(bdrv_get_aio_context(s->bs), true);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
51
block/qed.c
51
block/qed.c
@@ -21,13 +21,12 @@
|
||||
static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
{
|
||||
QEDAIOCB *acb = (QEDAIOCB *)blockacb;
|
||||
AioContext *aio_context = bdrv_get_aio_context(blockacb->bs);
|
||||
bool finished = false;
|
||||
|
||||
/* Wait for the request to finish */
|
||||
acb->finished = &finished;
|
||||
while (!finished) {
|
||||
aio_poll(aio_context, true);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,27 +373,6 @@ static void bdrv_qed_rebind(BlockDriverState *bs)
|
||||
s->bs = bs;
|
||||
}
|
||||
|
||||
static void bdrv_qed_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
|
||||
qed_cancel_need_check_timer(s);
|
||||
timer_free(s->need_check_timer);
|
||||
}
|
||||
|
||||
static void bdrv_qed_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
|
||||
s->need_check_timer = aio_timer_new(new_context,
|
||||
QEMU_CLOCK_VIRTUAL, SCALE_NS,
|
||||
qed_need_check_timer_cb, s);
|
||||
if (s->header.features & QED_F_NEED_CHECK) {
|
||||
qed_start_need_check_timer(s);
|
||||
}
|
||||
}
|
||||
|
||||
static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -518,7 +496,8 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_qed_attach_aio_context(bs, bdrv_get_aio_context(bs));
|
||||
s->need_check_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
qed_need_check_timer_cb, s);
|
||||
|
||||
out:
|
||||
if (ret) {
|
||||
@@ -549,7 +528,8 @@ static void bdrv_qed_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
|
||||
bdrv_qed_detach_aio_context(bs);
|
||||
qed_cancel_need_check_timer(s);
|
||||
timer_free(s->need_check_timer);
|
||||
|
||||
/* Ensure writes reach stable storage */
|
||||
bdrv_flush(bs->file);
|
||||
@@ -670,21 +650,19 @@ static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options,
|
||||
}
|
||||
|
||||
if (!qed_is_cluster_size_valid(cluster_size)) {
|
||||
error_setg(errp, "QED cluster size must be within range [%u, %u] "
|
||||
"and power of 2",
|
||||
QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE);
|
||||
fprintf(stderr, "QED cluster size must be within range [%u, %u] and power of 2\n",
|
||||
QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!qed_is_table_size_valid(table_size)) {
|
||||
error_setg(errp, "QED table size must be within range [%u, %u] "
|
||||
"and power of 2",
|
||||
QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE);
|
||||
fprintf(stderr, "QED table size must be within range [%u, %u] and power of 2\n",
|
||||
QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!qed_is_image_size_valid(image_size, cluster_size, table_size)) {
|
||||
error_setg(errp, "QED image size must be a non-zero multiple of "
|
||||
"cluster size and less than %" PRIu64 " bytes",
|
||||
qed_max_image_size(cluster_size, table_size));
|
||||
fprintf(stderr, "QED image size must be a non-zero multiple of "
|
||||
"cluster size and less than %" PRIu64 " bytes\n",
|
||||
qed_max_image_size(cluster_size, table_size));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -939,8 +917,7 @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
|
||||
|
||||
/* Arrange for a bh to invoke the completion function */
|
||||
acb->bh_ret = ret;
|
||||
acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs),
|
||||
qed_aio_complete_bh, acb);
|
||||
acb->bh = qemu_bh_new(qed_aio_complete_bh, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
|
||||
/* Start next allocating write request waiting behind this one. Note that
|
||||
@@ -1665,8 +1642,6 @@ static BlockDriver bdrv_qed = {
|
||||
.bdrv_change_backing_file = bdrv_qed_change_backing_file,
|
||||
.bdrv_invalidate_cache = bdrv_qed_invalidate_cache,
|
||||
.bdrv_check = bdrv_qed_check,
|
||||
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
|
||||
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
|
||||
};
|
||||
|
||||
static void bdrv_qed_init(void)
|
||||
|
@@ -753,7 +753,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
opts = qemu_opts_create(&quorum_runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
if (error_is_set(&local_err)) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
@@ -828,7 +828,7 @@ close_exit:
|
||||
g_free(opened);
|
||||
exit:
|
||||
/* propagate error */
|
||||
if (local_err) {
|
||||
if (error_is_set(&local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
QDECREF(list);
|
||||
@@ -848,49 +848,25 @@ static void quorum_close(BlockDriverState *bs)
|
||||
g_free(s->bs);
|
||||
}
|
||||
|
||||
static void quorum_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
bdrv_detach_aio_context(s->bs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void quorum_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
bdrv_attach_aio_context(s->bs[i], new_context);
|
||||
}
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_quorum = {
|
||||
.format_name = "quorum",
|
||||
.protocol_name = "quorum",
|
||||
.format_name = "quorum",
|
||||
.protocol_name = "quorum",
|
||||
|
||||
.instance_size = sizeof(BDRVQuorumState),
|
||||
.instance_size = sizeof(BDRVQuorumState),
|
||||
|
||||
.bdrv_file_open = quorum_open,
|
||||
.bdrv_close = quorum_close,
|
||||
.bdrv_file_open = quorum_open,
|
||||
.bdrv_close = quorum_close,
|
||||
|
||||
.bdrv_co_flush_to_disk = quorum_co_flush,
|
||||
.bdrv_co_flush_to_disk = quorum_co_flush,
|
||||
|
||||
.bdrv_getlength = quorum_getlength,
|
||||
.bdrv_getlength = quorum_getlength,
|
||||
|
||||
.bdrv_aio_readv = quorum_aio_readv,
|
||||
.bdrv_aio_writev = quorum_aio_writev,
|
||||
.bdrv_invalidate_cache = quorum_invalidate_cache,
|
||||
.bdrv_aio_readv = quorum_aio_readv,
|
||||
.bdrv_aio_writev = quorum_aio_writev,
|
||||
.bdrv_invalidate_cache = quorum_invalidate_cache,
|
||||
|
||||
.bdrv_detach_aio_context = quorum_detach_aio_context,
|
||||
.bdrv_attach_aio_context = quorum_attach_aio_context,
|
||||
|
||||
.is_filter = true,
|
||||
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
|
||||
.is_filter = true,
|
||||
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
|
||||
};
|
||||
|
||||
static void bdrv_quorum_init(void)
|
||||
|
@@ -34,27 +34,19 @@
|
||||
/* linux-aio.c - Linux native implementation */
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
void *laio_init(void);
|
||||
void laio_cleanup(void *s);
|
||||
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type);
|
||||
void laio_detach_aio_context(void *s, AioContext *old_context);
|
||||
void laio_attach_aio_context(void *s, AioContext *new_context);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef struct QEMUWin32AIOState QEMUWin32AIOState;
|
||||
QEMUWin32AIOState *win32_aio_init(void);
|
||||
void win32_aio_cleanup(QEMUWin32AIOState *aio);
|
||||
int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile);
|
||||
BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
|
||||
QEMUWin32AIOState *aio, HANDLE hfile,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type);
|
||||
void win32_aio_detach_aio_context(QEMUWin32AIOState *aio,
|
||||
AioContext *old_context);
|
||||
void win32_aio_attach_aio_context(QEMUWin32AIOState *aio,
|
||||
AioContext *new_context);
|
||||
#endif
|
||||
|
||||
#endif /* QEMU_RAW_AIO_H */
|
||||
|
@@ -146,9 +146,6 @@ typedef struct BDRVRawState {
|
||||
bool has_discard:1;
|
||||
bool has_write_zeroes:1;
|
||||
bool discard_zeroes:1;
|
||||
#ifdef CONFIG_FIEMAP
|
||||
bool skip_fiemap;
|
||||
#endif
|
||||
} BDRVRawState;
|
||||
|
||||
typedef struct BDRVRawReopenState {
|
||||
@@ -307,29 +304,6 @@ static void raw_parse_flags(int bdrv_flags, int *open_flags)
|
||||
}
|
||||
}
|
||||
|
||||
static void raw_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
if (s->use_aio) {
|
||||
laio_detach_aio_context(s->aio_ctx, bdrv_get_aio_context(bs));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void raw_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
if (s->use_aio) {
|
||||
laio_attach_aio_context(s->aio_ctx, new_context);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
static int raw_set_aio(void **aio_ctx, int *use_aio, int bdrv_flags)
|
||||
{
|
||||
@@ -392,7 +366,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
BDRVRawState *s = bs->opaque;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
const char *filename = NULL;
|
||||
const char *filename;
|
||||
int fd, ret;
|
||||
struct stat st;
|
||||
|
||||
@@ -470,13 +444,8 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
}
|
||||
#endif
|
||||
|
||||
raw_attach_aio_context(bs, bdrv_get_aio_context(bs));
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
|
||||
unlink(filename);
|
||||
}
|
||||
qemu_opts_del(opts);
|
||||
return ret;
|
||||
}
|
||||
@@ -1084,14 +1053,6 @@ static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
|
||||
static void raw_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
raw_detach_aio_context(bs);
|
||||
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
if (s->use_aio) {
|
||||
laio_cleanup(s->aio_ctx);
|
||||
}
|
||||
#endif
|
||||
if (s->fd >= 0) {
|
||||
qemu_close(s->fd);
|
||||
s->fd = -1;
|
||||
@@ -1225,7 +1186,7 @@ again:
|
||||
if (size == 0)
|
||||
#endif
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
size = LLONG_MAX;
|
||||
size = LONG_LONG_MAX;
|
||||
#else
|
||||
size = lseek(fd, 0LL, SEEK_END);
|
||||
#endif
|
||||
@@ -1308,83 +1269,6 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
|
||||
return result;
|
||||
}
|
||||
|
||||
static int64_t try_fiemap(BlockDriverState *bs, off_t start, off_t *data,
|
||||
off_t *hole, int nb_sectors, int *pnum)
|
||||
{
|
||||
#ifdef CONFIG_FIEMAP
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int64_t ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
||||
struct {
|
||||
struct fiemap fm;
|
||||
struct fiemap_extent fe;
|
||||
} f;
|
||||
|
||||
if (s->skip_fiemap) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
f.fm.fm_start = start;
|
||||
f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE;
|
||||
f.fm.fm_flags = 0;
|
||||
f.fm.fm_extent_count = 1;
|
||||
f.fm.fm_reserved = 0;
|
||||
if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) {
|
||||
s->skip_fiemap = true;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (f.fm.fm_mapped_extents == 0) {
|
||||
/* No extents found, data is beyond f.fm.fm_start + f.fm.fm_length.
|
||||
* f.fm.fm_start + f.fm.fm_length must be clamped to the file size!
|
||||
*/
|
||||
off_t length = lseek(s->fd, 0, SEEK_END);
|
||||
*hole = f.fm.fm_start;
|
||||
*data = MIN(f.fm.fm_start + f.fm.fm_length, length);
|
||||
} else {
|
||||
*data = f.fe.fe_logical;
|
||||
*hole = f.fe.fe_logical + f.fe.fe_length;
|
||||
if (f.fe.fe_flags & FIEMAP_EXTENT_UNWRITTEN) {
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int64_t try_seek_hole(BlockDriverState *bs, off_t start, off_t *data,
|
||||
off_t *hole, int *pnum)
|
||||
{
|
||||
#if defined SEEK_HOLE && defined SEEK_DATA
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
*hole = lseek(s->fd, start, SEEK_HOLE);
|
||||
if (*hole == -1) {
|
||||
/* -ENXIO indicates that sector_num was past the end of the file.
|
||||
* There is a virtual hole there. */
|
||||
assert(errno != -ENXIO);
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (*hole > start) {
|
||||
*data = start;
|
||||
} else {
|
||||
/* On a hole. We need another syscall to find its end. */
|
||||
*data = lseek(s->fd, start, SEEK_DATA);
|
||||
if (*data == -1) {
|
||||
*data = lseek(s->fd, 0, SEEK_END);
|
||||
}
|
||||
}
|
||||
|
||||
return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true iff the specified sector is present in the disk image. Drivers
|
||||
* not implementing the functionality are assumed to not support backing files,
|
||||
@@ -1401,10 +1285,10 @@ static int64_t try_seek_hole(BlockDriverState *bs, off_t start, off_t *data,
|
||||
* beyond the end of the disk image it will be clamped.
|
||||
*/
|
||||
static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
off_t start, data = 0, hole = 0;
|
||||
off_t start, data, hole;
|
||||
int64_t ret;
|
||||
|
||||
ret = fd_open(bs);
|
||||
@@ -1413,18 +1297,71 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
start = sector_num * BDRV_SECTOR_SIZE;
|
||||
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
||||
|
||||
ret = try_fiemap(bs, start, &data, &hole, nb_sectors, pnum);
|
||||
if (ret < 0) {
|
||||
ret = try_seek_hole(bs, start, &data, &hole, pnum);
|
||||
if (ret < 0) {
|
||||
/* Assume everything is allocated. */
|
||||
data = 0;
|
||||
hole = start + nb_sectors * BDRV_SECTOR_SIZE;
|
||||
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
||||
#ifdef CONFIG_FIEMAP
|
||||
|
||||
BDRVRawState *s = bs->opaque;
|
||||
struct {
|
||||
struct fiemap fm;
|
||||
struct fiemap_extent fe;
|
||||
} f;
|
||||
|
||||
f.fm.fm_start = start;
|
||||
f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE;
|
||||
f.fm.fm_flags = 0;
|
||||
f.fm.fm_extent_count = 1;
|
||||
f.fm.fm_reserved = 0;
|
||||
if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) {
|
||||
/* Assume everything is allocated. */
|
||||
*pnum = nb_sectors;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (f.fm.fm_mapped_extents == 0) {
|
||||
/* No extents found, data is beyond f.fm.fm_start + f.fm.fm_length.
|
||||
* f.fm.fm_start + f.fm.fm_length must be clamped to the file size!
|
||||
*/
|
||||
off_t length = lseek(s->fd, 0, SEEK_END);
|
||||
hole = f.fm.fm_start;
|
||||
data = MIN(f.fm.fm_start + f.fm.fm_length, length);
|
||||
} else {
|
||||
data = f.fe.fe_logical;
|
||||
hole = f.fe.fe_logical + f.fe.fe_length;
|
||||
if (f.fe.fe_flags & FIEMAP_EXTENT_UNWRITTEN) {
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined SEEK_HOLE && defined SEEK_DATA
|
||||
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
hole = lseek(s->fd, start, SEEK_HOLE);
|
||||
if (hole == -1) {
|
||||
/* -ENXIO indicates that sector_num was past the end of the file.
|
||||
* There is a virtual hole there. */
|
||||
assert(errno != -ENXIO);
|
||||
|
||||
/* Most likely EINVAL. Assume everything is allocated. */
|
||||
*pnum = nb_sectors;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (hole > start) {
|
||||
data = start;
|
||||
} else {
|
||||
/* On a hole. We need another syscall to find its end. */
|
||||
data = lseek(s->fd, start, SEEK_DATA);
|
||||
if (data == -1) {
|
||||
data = lseek(s->fd, 0, SEEK_END);
|
||||
}
|
||||
}
|
||||
#else
|
||||
data = 0;
|
||||
hole = start + nb_sectors * BDRV_SECTOR_SIZE;
|
||||
#endif
|
||||
|
||||
if (data <= start) {
|
||||
/* On a data extent, compute sectors to the end of the extent. */
|
||||
*pnum = MIN(nb_sectors, (hole - start) / BDRV_SECTOR_SIZE);
|
||||
@@ -1511,9 +1448,6 @@ static BlockDriver bdrv_file = {
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
||||
.bdrv_detach_aio_context = raw_detach_aio_context,
|
||||
.bdrv_attach_aio_context = raw_attach_aio_context,
|
||||
|
||||
.create_options = raw_create_options,
|
||||
};
|
||||
|
||||
@@ -1914,9 +1848,6 @@ static BlockDriver bdrv_host_device = {
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
||||
.bdrv_detach_aio_context = raw_detach_aio_context,
|
||||
.bdrv_attach_aio_context = raw_attach_aio_context,
|
||||
|
||||
/* generic scsi device */
|
||||
#ifdef __linux__
|
||||
.bdrv_ioctl = hdev_ioctl,
|
||||
@@ -2059,9 +1990,6 @@ static BlockDriver bdrv_host_floppy = {
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
||||
.bdrv_detach_aio_context = raw_detach_aio_context,
|
||||
.bdrv_attach_aio_context = raw_attach_aio_context,
|
||||
|
||||
/* removable device support */
|
||||
.bdrv_is_inserted = floppy_is_inserted,
|
||||
.bdrv_media_changed = floppy_media_changed,
|
||||
@@ -2187,9 +2115,6 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
||||
.bdrv_detach_aio_context = raw_detach_aio_context,
|
||||
.bdrv_attach_aio_context = raw_attach_aio_context,
|
||||
|
||||
/* removable device support */
|
||||
.bdrv_is_inserted = cdrom_is_inserted,
|
||||
.bdrv_eject = cdrom_eject,
|
||||
@@ -2321,9 +2246,6 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
||||
.bdrv_detach_aio_context = raw_detach_aio_context,
|
||||
.bdrv_attach_aio_context = raw_attach_aio_context,
|
||||
|
||||
/* removable device support */
|
||||
.bdrv_is_inserted = cdrom_is_inserted,
|
||||
.bdrv_eject = cdrom_eject,
|
||||
@@ -2331,6 +2253,40 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
};
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
/**
|
||||
* Return the file descriptor for Linux AIO
|
||||
*
|
||||
* This function is a layering violation and should be removed when it becomes
|
||||
* possible to call the block layer outside the global mutex. It allows the
|
||||
* caller to hijack the file descriptor so I/O can be performed outside the
|
||||
* block layer.
|
||||
*/
|
||||
int raw_get_aio_fd(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s;
|
||||
|
||||
if (!bs->drv) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
if (bs->drv == bdrv_find_format("raw")) {
|
||||
bs = bs->file;
|
||||
}
|
||||
|
||||
/* raw-posix has several protocols so just check for raw_aio_readv */
|
||||
if (bs->drv->bdrv_aio_readv != raw_aio_readv) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
s = bs->opaque;
|
||||
if (!s->use_aio) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return s->fd;
|
||||
}
|
||||
#endif /* CONFIG_LINUX_AIO */
|
||||
|
||||
static void bdrv_file_init(void)
|
||||
{
|
||||
/*
|
||||
|
@@ -36,6 +36,8 @@
|
||||
#define FTYPE_CD 1
|
||||
#define FTYPE_HARDDISK 2
|
||||
|
||||
static QEMUWin32AIOState *aio;
|
||||
|
||||
typedef struct RawWin32AIOData {
|
||||
BlockDriverState *bs;
|
||||
HANDLE hfile;
|
||||
@@ -200,25 +202,6 @@ static int set_sparse(int fd)
|
||||
NULL, 0, NULL, 0, &returned, NULL);
|
||||
}
|
||||
|
||||
static void raw_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
if (s->aio) {
|
||||
win32_aio_detach_aio_context(s->aio, bdrv_get_aio_context(bs));
|
||||
}
|
||||
}
|
||||
|
||||
static void raw_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
if (s->aio) {
|
||||
win32_aio_attach_aio_context(s->aio, new_context);
|
||||
}
|
||||
}
|
||||
|
||||
static void raw_probe_alignment(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
@@ -317,6 +300,15 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
raw_parse_flags(flags, &access_flags, &overlapped);
|
||||
|
||||
if ((flags & BDRV_O_NATIVE_AIO) && aio == NULL) {
|
||||
aio = win32_aio_init();
|
||||
if (aio == NULL) {
|
||||
error_setg(errp, "Could not initialize AIO");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (filename[0] && filename[1] == ':') {
|
||||
snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", filename[0]);
|
||||
} else if (filename[0] == '\\' && filename[1] == '\\') {
|
||||
@@ -343,23 +335,13 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
if (flags & BDRV_O_NATIVE_AIO) {
|
||||
s->aio = win32_aio_init();
|
||||
if (s->aio == NULL) {
|
||||
CloseHandle(s->hfile);
|
||||
error_setg(errp, "Could not initialize AIO");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = win32_aio_attach(s->aio, s->hfile);
|
||||
ret = win32_aio_attach(aio, s->hfile);
|
||||
if (ret < 0) {
|
||||
win32_aio_cleanup(s->aio);
|
||||
CloseHandle(s->hfile);
|
||||
error_setg_errno(errp, -ret, "Could not enable AIO");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
win32_aio_attach_aio_context(s->aio, bdrv_get_aio_context(bs));
|
||||
s->aio = aio;
|
||||
}
|
||||
|
||||
raw_probe_alignment(bs);
|
||||
@@ -407,17 +389,7 @@ static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
|
||||
static void raw_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
if (s->aio) {
|
||||
win32_aio_detach_aio_context(s->aio, bdrv_get_aio_context(bs));
|
||||
win32_aio_cleanup(s->aio);
|
||||
s->aio = NULL;
|
||||
}
|
||||
|
||||
CloseHandle(s->hfile);
|
||||
if (bs->open_flags & BDRV_O_TEMPORARY) {
|
||||
unlink(bs->filename);
|
||||
}
|
||||
}
|
||||
|
||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||
@@ -709,9 +681,6 @@ static BlockDriver bdrv_host_device = {
|
||||
.bdrv_aio_writev = raw_aio_writev,
|
||||
.bdrv_aio_flush = raw_aio_flush,
|
||||
|
||||
.bdrv_detach_aio_context = raw_detach_aio_context,
|
||||
.bdrv_attach_aio_context = raw_attach_aio_context,
|
||||
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.has_variable_length = true,
|
||||
|
||||
|
81
block/rbd.c
81
block/rbd.c
@@ -105,7 +105,7 @@ typedef struct BDRVRBDState {
|
||||
static int qemu_rbd_next_tok(char *dst, int dst_len,
|
||||
char *src, char delim,
|
||||
const char *name,
|
||||
char **p, Error **errp)
|
||||
char **p)
|
||||
{
|
||||
int l;
|
||||
char *end;
|
||||
@@ -128,10 +128,10 @@ static int qemu_rbd_next_tok(char *dst, int dst_len,
|
||||
}
|
||||
l = strlen(src);
|
||||
if (l >= dst_len) {
|
||||
error_setg(errp, "%s too long", name);
|
||||
error_report("%s too long", name);
|
||||
return -EINVAL;
|
||||
} else if (l == 0) {
|
||||
error_setg(errp, "%s too short", name);
|
||||
error_report("%s too short", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -157,15 +157,13 @@ static int qemu_rbd_parsename(const char *filename,
|
||||
char *pool, int pool_len,
|
||||
char *snap, int snap_len,
|
||||
char *name, int name_len,
|
||||
char *conf, int conf_len,
|
||||
Error **errp)
|
||||
char *conf, int conf_len)
|
||||
{
|
||||
const char *start;
|
||||
char *p, *buf;
|
||||
int ret;
|
||||
|
||||
if (!strstart(filename, "rbd:", &start)) {
|
||||
error_setg(errp, "File name must start with 'rbd:'");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -174,8 +172,7 @@ static int qemu_rbd_parsename(const char *filename,
|
||||
*snap = '\0';
|
||||
*conf = '\0';
|
||||
|
||||
ret = qemu_rbd_next_tok(pool, pool_len, p,
|
||||
'/', "pool name", &p, errp);
|
||||
ret = qemu_rbd_next_tok(pool, pool_len, p, '/', "pool name", &p);
|
||||
if (ret < 0 || !p) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
@@ -183,25 +180,21 @@ static int qemu_rbd_parsename(const char *filename,
|
||||
qemu_rbd_unescape(pool);
|
||||
|
||||
if (strchr(p, '@')) {
|
||||
ret = qemu_rbd_next_tok(name, name_len, p,
|
||||
'@', "object name", &p, errp);
|
||||
ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p);
|
||||
if (ret < 0) {
|
||||
goto done;
|
||||
}
|
||||
ret = qemu_rbd_next_tok(snap, snap_len, p,
|
||||
':', "snap name", &p, errp);
|
||||
ret = qemu_rbd_next_tok(snap, snap_len, p, ':', "snap name", &p);
|
||||
qemu_rbd_unescape(snap);
|
||||
} else {
|
||||
ret = qemu_rbd_next_tok(name, name_len, p,
|
||||
':', "object name", &p, errp);
|
||||
ret = qemu_rbd_next_tok(name, name_len, p, ':', "object name", &p);
|
||||
}
|
||||
qemu_rbd_unescape(name);
|
||||
if (ret < 0 || !p) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = qemu_rbd_next_tok(conf, conf_len, p,
|
||||
'\0', "configuration", &p, errp);
|
||||
ret = qemu_rbd_next_tok(conf, conf_len, p, '\0', "configuration", &p);
|
||||
|
||||
done:
|
||||
g_free(buf);
|
||||
@@ -236,7 +229,7 @@ static char *qemu_rbd_parse_clientname(const char *conf, char *clientname)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int qemu_rbd_set_conf(rados_t cluster, const char *conf, Error **errp)
|
||||
static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
|
||||
{
|
||||
char *p, *buf;
|
||||
char name[RBD_MAX_CONF_NAME_SIZE];
|
||||
@@ -248,20 +241,20 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf, Error **errp)
|
||||
|
||||
while (p) {
|
||||
ret = qemu_rbd_next_tok(name, sizeof(name), p,
|
||||
'=', "conf option name", &p, errp);
|
||||
'=', "conf option name", &p);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
qemu_rbd_unescape(name);
|
||||
|
||||
if (!p) {
|
||||
error_setg(errp, "conf option %s has no value", name);
|
||||
error_report("conf option %s has no value", name);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = qemu_rbd_next_tok(value, sizeof(value), p,
|
||||
':', "conf option value", &p, errp);
|
||||
':', "conf option value", &p);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
@@ -270,7 +263,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf, Error **errp)
|
||||
if (strcmp(name, "conf") == 0) {
|
||||
ret = rados_conf_read_file(cluster, value);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "error reading conf file %s", value);
|
||||
error_report("error reading conf file %s", value);
|
||||
break;
|
||||
}
|
||||
} else if (strcmp(name, "id") == 0) {
|
||||
@@ -278,7 +271,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf, Error **errp)
|
||||
} else {
|
||||
ret = rados_conf_set(cluster, name, value);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "invalid conf option %s", name);
|
||||
error_report("invalid conf option %s", name);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
@@ -292,7 +285,6 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf, Error **errp)
|
||||
static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int64_t bytes = 0;
|
||||
int64_t objsize;
|
||||
int obj_order = 0;
|
||||
@@ -309,8 +301,7 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
|
||||
if (qemu_rbd_parsename(filename, pool, sizeof(pool),
|
||||
snap_buf, sizeof(snap_buf),
|
||||
name, sizeof(name),
|
||||
conf, sizeof(conf), &local_err) < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
conf, sizeof(conf)) < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -322,11 +313,11 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
|
||||
if (options->value.n) {
|
||||
objsize = options->value.n;
|
||||
if ((objsize - 1) & objsize) { /* not a power of 2? */
|
||||
error_setg(errp, "obj size needs to be power of 2");
|
||||
error_report("obj size needs to be power of 2");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (objsize < 4096) {
|
||||
error_setg(errp, "obj size too small");
|
||||
error_report("obj size too small");
|
||||
return -EINVAL;
|
||||
}
|
||||
obj_order = ffs(objsize) - 1;
|
||||
@@ -337,7 +328,7 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
|
||||
|
||||
clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
|
||||
if (rados_create(&cluster, clientname) < 0) {
|
||||
error_setg(errp, "error initializing");
|
||||
error_report("error initializing");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -347,20 +338,20 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
|
||||
}
|
||||
|
||||
if (conf[0] != '\0' &&
|
||||
qemu_rbd_set_conf(cluster, conf, &local_err) < 0) {
|
||||
qemu_rbd_set_conf(cluster, conf) < 0) {
|
||||
error_report("error setting config options");
|
||||
rados_shutdown(cluster);
|
||||
error_propagate(errp, local_err);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (rados_connect(cluster) < 0) {
|
||||
error_setg(errp, "error connecting");
|
||||
error_report("error connecting");
|
||||
rados_shutdown(cluster);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (rados_ioctx_create(cluster, pool, &io_ctx) < 0) {
|
||||
error_setg(errp, "error opening pool %s", pool);
|
||||
error_report("error opening pool %s", pool);
|
||||
rados_shutdown(cluster);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -450,7 +441,8 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
qemu_opts_del(opts);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -460,7 +452,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (qemu_rbd_parsename(filename, pool, sizeof(pool),
|
||||
snap_buf, sizeof(snap_buf),
|
||||
s->name, sizeof(s->name),
|
||||
conf, sizeof(conf), errp) < 0) {
|
||||
conf, sizeof(conf)) < 0) {
|
||||
r = -EINVAL;
|
||||
goto failed_opts;
|
||||
}
|
||||
@@ -468,7 +460,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
|
||||
r = rados_create(&s->cluster, clientname);
|
||||
if (r < 0) {
|
||||
error_setg(&local_err, "error initializing");
|
||||
error_report("error initializing");
|
||||
goto failed_opts;
|
||||
}
|
||||
|
||||
@@ -496,27 +488,28 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
if (conf[0] != '\0') {
|
||||
r = qemu_rbd_set_conf(s->cluster, conf, errp);
|
||||
r = qemu_rbd_set_conf(s->cluster, conf);
|
||||
if (r < 0) {
|
||||
error_report("error setting config options");
|
||||
goto failed_shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
r = rados_connect(s->cluster);
|
||||
if (r < 0) {
|
||||
error_setg(&local_err, "error connecting");
|
||||
error_report("error connecting");
|
||||
goto failed_shutdown;
|
||||
}
|
||||
|
||||
r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
|
||||
if (r < 0) {
|
||||
error_setg(&local_err, "error opening pool %s", pool);
|
||||
error_report("error opening pool %s", pool);
|
||||
goto failed_shutdown;
|
||||
}
|
||||
|
||||
r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
|
||||
if (r < 0) {
|
||||
error_setg(&local_err, "error reading header from %s", s->name);
|
||||
error_report("error reading header from %s", s->name);
|
||||
goto failed_open;
|
||||
}
|
||||
|
||||
@@ -555,7 +548,7 @@ static void qemu_rbd_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
acb->cancelled = 1;
|
||||
|
||||
while (acb->status == -EINPROGRESS) {
|
||||
aio_poll(bdrv_get_aio_context(acb->common.bs), true);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
|
||||
qemu_aio_release(acb);
|
||||
@@ -588,8 +581,7 @@ static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
|
||||
rcb->ret = rbd_aio_get_return_value(c);
|
||||
rbd_aio_release(c);
|
||||
|
||||
acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs),
|
||||
rbd_finish_bh, rcb);
|
||||
acb->bh = qemu_bh_new(rbd_finish_bh, rcb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
}
|
||||
|
||||
@@ -685,16 +677,13 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
goto failed_completion;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return &acb->common;
|
||||
|
||||
failed_completion:
|
||||
rbd_aio_release(c);
|
||||
failed:
|
||||
g_free(rcb);
|
||||
qemu_vfree(acb->bounce);
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
}
|
||||
|
320
block/sheepdog.c
320
block/sheepdog.c
@@ -200,8 +200,6 @@ typedef struct SheepdogInode {
|
||||
uint32_t data_vdi_id[MAX_DATA_OBJS];
|
||||
} SheepdogInode;
|
||||
|
||||
#define SD_INODE_HEADER_SIZE offsetof(SheepdogInode, data_vdi_id)
|
||||
|
||||
/*
|
||||
* 64 bit FNV-1a non-zero initial basis
|
||||
*/
|
||||
@@ -284,7 +282,6 @@ typedef struct AIOReq {
|
||||
unsigned int data_len;
|
||||
uint8_t flags;
|
||||
uint32_t id;
|
||||
bool create;
|
||||
|
||||
QLIST_ENTRY(AIOReq) aio_siblings;
|
||||
} AIOReq;
|
||||
@@ -317,7 +314,6 @@ struct SheepdogAIOCB {
|
||||
|
||||
typedef struct BDRVSheepdogState {
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
|
||||
SheepdogInode inode;
|
||||
|
||||
@@ -408,7 +404,7 @@ static const char * sd_strerror(int err)
|
||||
|
||||
static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb,
|
||||
uint64_t oid, unsigned int data_len,
|
||||
uint64_t offset, uint8_t flags, bool create,
|
||||
uint64_t offset, uint8_t flags,
|
||||
uint64_t base_oid, unsigned int iov_offset)
|
||||
{
|
||||
AIOReq *aio_req;
|
||||
@@ -422,7 +418,6 @@ static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb,
|
||||
aio_req->data_len = data_len;
|
||||
aio_req->flags = flags;
|
||||
aio_req->id = s->aioreq_seq_num++;
|
||||
aio_req->create = create;
|
||||
|
||||
acb->nr_pending++;
|
||||
return aio_req;
|
||||
@@ -501,7 +496,7 @@ static void sd_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
sd_finish_aiocb(acb);
|
||||
return;
|
||||
}
|
||||
aio_poll(s->aio_context, true);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,16 +526,17 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||
return acb;
|
||||
}
|
||||
|
||||
static int connect_to_sdog(BDRVSheepdogState *s, Error **errp)
|
||||
static int connect_to_sdog(BDRVSheepdogState *s)
|
||||
{
|
||||
int fd;
|
||||
Error *err = NULL;
|
||||
|
||||
if (s->is_unix) {
|
||||
fd = unix_connect(s->host_spec, errp);
|
||||
fd = unix_connect(s->host_spec, &err);
|
||||
} else {
|
||||
fd = inet_connect(s->host_spec, errp);
|
||||
fd = inet_connect(s->host_spec, &err);
|
||||
|
||||
if (fd >= 0) {
|
||||
if (err == NULL) {
|
||||
int ret = socket_set_nodelay(fd);
|
||||
if (ret < 0) {
|
||||
error_report("%s", strerror(errno));
|
||||
@@ -548,7 +544,10 @@ static int connect_to_sdog(BDRVSheepdogState *s, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
if (err != NULL) {
|
||||
qerror_report_err(err);
|
||||
error_free(err);
|
||||
} else {
|
||||
qemu_set_nonblock(fd);
|
||||
}
|
||||
|
||||
@@ -583,7 +582,6 @@ static void restart_co_req(void *opaque)
|
||||
|
||||
typedef struct SheepdogReqCo {
|
||||
int sockfd;
|
||||
AioContext *aio_context;
|
||||
SheepdogReq *hdr;
|
||||
void *data;
|
||||
unsigned int *wlen;
|
||||
@@ -604,14 +602,14 @@ static coroutine_fn void do_co_req(void *opaque)
|
||||
unsigned int *rlen = srco->rlen;
|
||||
|
||||
co = qemu_coroutine_self();
|
||||
aio_set_fd_handler(srco->aio_context, sockfd, NULL, restart_co_req, co);
|
||||
qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, co);
|
||||
|
||||
ret = send_co_req(sockfd, hdr, data, wlen);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
aio_set_fd_handler(srco->aio_context, sockfd, restart_co_req, NULL, co);
|
||||
qemu_aio_set_fd_handler(sockfd, restart_co_req, NULL, co);
|
||||
|
||||
ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr));
|
||||
if (ret != sizeof(*hdr)) {
|
||||
@@ -636,19 +634,18 @@ static coroutine_fn void do_co_req(void *opaque)
|
||||
out:
|
||||
/* there is at most one request for this sockfd, so it is safe to
|
||||
* set each handler to NULL. */
|
||||
aio_set_fd_handler(srco->aio_context, sockfd, NULL, NULL, NULL);
|
||||
qemu_aio_set_fd_handler(sockfd, NULL, NULL, NULL);
|
||||
|
||||
srco->ret = ret;
|
||||
srco->finished = true;
|
||||
}
|
||||
|
||||
static int do_req(int sockfd, AioContext *aio_context, SheepdogReq *hdr,
|
||||
void *data, unsigned int *wlen, unsigned int *rlen)
|
||||
static int do_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
unsigned int *wlen, unsigned int *rlen)
|
||||
{
|
||||
Coroutine *co;
|
||||
SheepdogReqCo srco = {
|
||||
.sockfd = sockfd,
|
||||
.aio_context = aio_context,
|
||||
.hdr = hdr,
|
||||
.data = data,
|
||||
.wlen = wlen,
|
||||
@@ -663,7 +660,7 @@ static int do_req(int sockfd, AioContext *aio_context, SheepdogReq *hdr,
|
||||
co = qemu_coroutine_create(do_co_req);
|
||||
qemu_coroutine_enter(co, &srco);
|
||||
while (!srco.finished) {
|
||||
aio_poll(aio_context, true);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -671,11 +668,11 @@ static int do_req(int sockfd, AioContext *aio_context, SheepdogReq *hdr,
|
||||
}
|
||||
|
||||
static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
struct iovec *iov, int niov,
|
||||
enum AIOCBState aiocb_type);
|
||||
struct iovec *iov, int niov, bool create,
|
||||
enum AIOCBState aiocb_type);
|
||||
static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req);
|
||||
static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag);
|
||||
static int get_sheep_fd(BDRVSheepdogState *s, Error **errp);
|
||||
static int get_sheep_fd(BDRVSheepdogState *s);
|
||||
static void co_write_request(void *opaque);
|
||||
|
||||
static AIOReq *find_pending_req(BDRVSheepdogState *s, uint64_t oid)
|
||||
@@ -705,18 +702,17 @@ static void coroutine_fn send_pending_req(BDRVSheepdogState *s, uint64_t oid)
|
||||
/* move aio_req from pending list to inflight one */
|
||||
QLIST_REMOVE(aio_req, aio_siblings);
|
||||
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
|
||||
add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
|
||||
add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, false,
|
||||
acb->aiocb_type);
|
||||
}
|
||||
}
|
||||
|
||||
static coroutine_fn void reconnect_to_sdog(void *opaque)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BDRVSheepdogState *s = opaque;
|
||||
AIOReq *aio_req, *next;
|
||||
|
||||
aio_set_fd_handler(s->aio_context, s->fd, NULL, NULL, NULL);
|
||||
qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL);
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
|
||||
@@ -727,11 +723,9 @@ static coroutine_fn void reconnect_to_sdog(void *opaque)
|
||||
|
||||
/* Try to reconnect the sheepdog server every one second. */
|
||||
while (s->fd < 0) {
|
||||
s->fd = get_sheep_fd(s, &local_err);
|
||||
s->fd = get_sheep_fd(s);
|
||||
if (s->fd < 0) {
|
||||
DPRINTF("Wait for connection to be established\n");
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
co_aio_sleep_ns(bdrv_get_aio_context(s->bs), QEMU_CLOCK_REALTIME,
|
||||
1000000000ULL);
|
||||
}
|
||||
@@ -804,7 +798,7 @@ static void coroutine_fn aio_read_response(void *opaque)
|
||||
}
|
||||
idx = data_oid_to_idx(aio_req->oid);
|
||||
|
||||
if (aio_req->create) {
|
||||
if (s->inode.data_vdi_id[idx] != s->inode.vdi_id) {
|
||||
/*
|
||||
* If the object is newly created one, we need to update
|
||||
* the vdi object (metadata object). min_dirty_data_idx
|
||||
@@ -920,16 +914,16 @@ static void co_write_request(void *opaque)
|
||||
* We cannot use this descriptor for other operations because
|
||||
* the block driver may be on waiting response from the server.
|
||||
*/
|
||||
static int get_sheep_fd(BDRVSheepdogState *s, Error **errp)
|
||||
static int get_sheep_fd(BDRVSheepdogState *s)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = connect_to_sdog(s, errp);
|
||||
fd = connect_to_sdog(s);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
aio_set_fd_handler(s->aio_context, fd, co_read_response, NULL, s);
|
||||
qemu_aio_set_fd_handler(fd, co_read_response, NULL, s);
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -1067,7 +1061,7 @@ static int parse_vdiname(BDRVSheepdogState *s, const char *filename,
|
||||
|
||||
static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
|
||||
uint32_t snapid, const char *tag, uint32_t *vid,
|
||||
bool lock, Error **errp)
|
||||
bool lock)
|
||||
{
|
||||
int ret, fd;
|
||||
SheepdogVdiReq hdr;
|
||||
@@ -1075,7 +1069,7 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
|
||||
unsigned int wlen, rlen = 0;
|
||||
char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
|
||||
|
||||
fd = connect_to_sdog(s, errp);
|
||||
fd = connect_to_sdog(s);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
@@ -1099,15 +1093,14 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
|
||||
hdr.snapid = snapid;
|
||||
hdr.flags = SD_FLAG_CMD_WRITE;
|
||||
|
||||
ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
|
||||
ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
|
||||
if (ret) {
|
||||
error_setg_errno(errp, -ret, "cannot get vdi info");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rsp->result != SD_RES_SUCCESS) {
|
||||
error_setg(errp, "cannot get vdi info, %s, %s %" PRIu32 " %s",
|
||||
sd_strerror(rsp->result), filename, snapid, tag);
|
||||
error_report("cannot get vdi info, %s, %s %d %s",
|
||||
sd_strerror(rsp->result), filename, snapid, tag);
|
||||
if (rsp->result == SD_RES_NO_VDI) {
|
||||
ret = -ENOENT;
|
||||
} else {
|
||||
@@ -1124,8 +1117,8 @@ out:
|
||||
}
|
||||
|
||||
static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
struct iovec *iov, int niov,
|
||||
enum AIOCBState aiocb_type)
|
||||
struct iovec *iov, int niov, bool create,
|
||||
enum AIOCBState aiocb_type)
|
||||
{
|
||||
int nr_copies = s->inode.nr_copies;
|
||||
SheepdogObjReq hdr;
|
||||
@@ -1136,7 +1129,6 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
uint64_t offset = aio_req->offset;
|
||||
uint8_t flags = aio_req->flags;
|
||||
uint64_t old_oid = aio_req->base_oid;
|
||||
bool create = aio_req->create;
|
||||
|
||||
if (!nr_copies) {
|
||||
error_report("bug");
|
||||
@@ -1181,8 +1173,7 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
s->co_send = qemu_coroutine_self();
|
||||
aio_set_fd_handler(s->aio_context, s->fd,
|
||||
co_read_response, co_write_request, s);
|
||||
qemu_aio_set_fd_handler(s->fd, co_read_response, co_write_request, s);
|
||||
socket_set_cork(s->fd, 1);
|
||||
|
||||
/* send a header */
|
||||
@@ -1200,13 +1191,12 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
}
|
||||
out:
|
||||
socket_set_cork(s->fd, 0);
|
||||
aio_set_fd_handler(s->aio_context, s->fd, co_read_response, NULL, s);
|
||||
qemu_aio_set_fd_handler(s->fd, co_read_response, NULL, s);
|
||||
s->co_send = NULL;
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
}
|
||||
|
||||
static int read_write_object(int fd, AioContext *aio_context, char *buf,
|
||||
uint64_t oid, uint8_t copies,
|
||||
static int read_write_object(int fd, char *buf, uint64_t oid, uint8_t copies,
|
||||
unsigned int datalen, uint64_t offset,
|
||||
bool write, bool create, uint32_t cache_flags)
|
||||
{
|
||||
@@ -1239,7 +1229,7 @@ static int read_write_object(int fd, AioContext *aio_context, char *buf,
|
||||
hdr.offset = offset;
|
||||
hdr.copies = copies;
|
||||
|
||||
ret = do_req(fd, aio_context, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
|
||||
ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
|
||||
if (ret) {
|
||||
error_report("failed to send a request to the sheep");
|
||||
return ret;
|
||||
@@ -1254,59 +1244,49 @@ static int read_write_object(int fd, AioContext *aio_context, char *buf,
|
||||
}
|
||||
}
|
||||
|
||||
static int read_object(int fd, AioContext *aio_context, char *buf,
|
||||
uint64_t oid, uint8_t copies,
|
||||
static int read_object(int fd, char *buf, uint64_t oid, uint8_t copies,
|
||||
unsigned int datalen, uint64_t offset,
|
||||
uint32_t cache_flags)
|
||||
{
|
||||
return read_write_object(fd, aio_context, buf, oid, copies,
|
||||
datalen, offset, false,
|
||||
return read_write_object(fd, buf, oid, copies, datalen, offset, false,
|
||||
false, cache_flags);
|
||||
}
|
||||
|
||||
static int write_object(int fd, AioContext *aio_context, char *buf,
|
||||
uint64_t oid, uint8_t copies,
|
||||
static int write_object(int fd, char *buf, uint64_t oid, uint8_t copies,
|
||||
unsigned int datalen, uint64_t offset, bool create,
|
||||
uint32_t cache_flags)
|
||||
{
|
||||
return read_write_object(fd, aio_context, buf, oid, copies,
|
||||
datalen, offset, true,
|
||||
return read_write_object(fd, buf, oid, copies, datalen, offset, true,
|
||||
create, cache_flags);
|
||||
}
|
||||
|
||||
/* update inode with the latest state */
|
||||
static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
SheepdogInode *inode;
|
||||
int ret = 0, fd;
|
||||
uint32_t vid = 0;
|
||||
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
fd = connect_to_sdog(s);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
inode = g_malloc(SD_INODE_HEADER_SIZE);
|
||||
inode = g_malloc(sizeof(s->inode));
|
||||
|
||||
ret = find_vdi_name(s, s->name, snapid, tag, &vid, false, &local_err);
|
||||
ret = find_vdi_name(s, s->name, snapid, tag, &vid, false);
|
||||
if (ret) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = read_object(fd, s->aio_context, (char *)inode, vid_to_vdi_oid(vid),
|
||||
s->inode.nr_copies, SD_INODE_HEADER_SIZE, 0,
|
||||
s->cache_flags);
|
||||
ret = read_object(fd, (char *)inode, vid_to_vdi_oid(vid),
|
||||
s->inode.nr_copies, sizeof(*inode), 0, s->cache_flags);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (inode->vdi_id != s->inode.vdi_id) {
|
||||
memcpy(&s->inode, inode, SD_INODE_HEADER_SIZE);
|
||||
memcpy(&s->inode, inode, sizeof(s->inode));
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -1330,7 +1310,6 @@ static bool check_simultaneous_create(BDRVSheepdogState *s, AIOReq *aio_req)
|
||||
DPRINTF("simultaneous create to %" PRIx64 "\n", aio_req->oid);
|
||||
aio_req->flags = 0;
|
||||
aio_req->base_oid = 0;
|
||||
aio_req->create = false;
|
||||
QLIST_REMOVE(aio_req, aio_siblings);
|
||||
QLIST_INSERT_HEAD(&s->pending_aio_head, aio_req, aio_siblings);
|
||||
return true;
|
||||
@@ -1343,8 +1322,7 @@ static bool check_simultaneous_create(BDRVSheepdogState *s, AIOReq *aio_req)
|
||||
static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req)
|
||||
{
|
||||
SheepdogAIOCB *acb = aio_req->aiocb;
|
||||
|
||||
aio_req->create = false;
|
||||
bool create = false;
|
||||
|
||||
/* check whether this request becomes a CoW one */
|
||||
if (acb->aiocb_type == AIOCB_WRITE_UDATA && is_data_obj(aio_req->oid)) {
|
||||
@@ -1362,36 +1340,20 @@ static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req)
|
||||
aio_req->base_oid = vid_to_data_oid(s->inode.data_vdi_id[idx], idx);
|
||||
aio_req->flags |= SD_FLAG_CMD_COW;
|
||||
}
|
||||
aio_req->create = true;
|
||||
create = true;
|
||||
}
|
||||
out:
|
||||
if (is_data_obj(aio_req->oid)) {
|
||||
add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
|
||||
add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, create,
|
||||
acb->aiocb_type);
|
||||
} else {
|
||||
struct iovec iov;
|
||||
iov.iov_base = &s->inode;
|
||||
iov.iov_len = sizeof(s->inode);
|
||||
add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA);
|
||||
add_aio_request(s, aio_req, &iov, 1, false, AIOCB_WRITE_UDATA);
|
||||
}
|
||||
}
|
||||
|
||||
static void sd_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
|
||||
aio_set_fd_handler(s->aio_context, s->fd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void sd_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
|
||||
s->aio_context = new_context;
|
||||
aio_set_fd_handler(new_context, s->fd, co_read_response, NULL, s);
|
||||
}
|
||||
|
||||
/* TODO Convert to fine grained options */
|
||||
static QemuOptsList runtime_opts = {
|
||||
.name = "sheepdog",
|
||||
@@ -1420,12 +1382,12 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
const char *filename;
|
||||
|
||||
s->bs = bs;
|
||||
s->aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1446,16 +1408,15 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
ret = parse_vdiname(s, filename, vdi, &snapid, tag);
|
||||
}
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Can't parse filename");
|
||||
goto out;
|
||||
}
|
||||
s->fd = get_sheep_fd(s, errp);
|
||||
s->fd = get_sheep_fd(s);
|
||||
if (s->fd < 0) {
|
||||
ret = s->fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = find_vdi_name(s, vdi, snapid, tag, &vid, true, errp);
|
||||
ret = find_vdi_name(s, vdi, snapid, tag, &vid, true);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
@@ -1475,20 +1436,19 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->is_snapshot = true;
|
||||
}
|
||||
|
||||
fd = connect_to_sdog(s, errp);
|
||||
fd = connect_to_sdog(s);
|
||||
if (fd < 0) {
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = g_malloc(SD_INODE_SIZE);
|
||||
ret = read_object(fd, s->aio_context, buf, vid_to_vdi_oid(vid),
|
||||
0, SD_INODE_SIZE, 0, s->cache_flags);
|
||||
ret = read_object(fd, buf, vid_to_vdi_oid(vid), 0, SD_INODE_SIZE, 0,
|
||||
s->cache_flags);
|
||||
|
||||
closesocket(fd);
|
||||
|
||||
if (ret) {
|
||||
error_setg(errp, "Can't read snapshot inode");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1503,7 +1463,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
g_free(buf);
|
||||
return 0;
|
||||
out:
|
||||
aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd, NULL, NULL, NULL);
|
||||
qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL);
|
||||
if (s->fd >= 0) {
|
||||
closesocket(s->fd);
|
||||
}
|
||||
@@ -1512,8 +1472,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot,
|
||||
Error **errp)
|
||||
static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
|
||||
{
|
||||
SheepdogVdiReq hdr;
|
||||
SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
|
||||
@@ -1521,7 +1480,7 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot,
|
||||
unsigned int wlen, rlen = 0;
|
||||
char buf[SD_MAX_VDI_LEN];
|
||||
|
||||
fd = connect_to_sdog(s, errp);
|
||||
fd = connect_to_sdog(s);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
@@ -1546,17 +1505,16 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot,
|
||||
hdr.copy_policy = s->inode.copy_policy;
|
||||
hdr.copies = s->inode.nr_copies;
|
||||
|
||||
ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
|
||||
ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
|
||||
|
||||
closesocket(fd);
|
||||
|
||||
if (ret) {
|
||||
error_setg_errno(errp, -ret, "create failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rsp->result != SD_RES_SUCCESS) {
|
||||
error_setg(errp, "%s, %s", sd_strerror(rsp->result), s->inode.name);
|
||||
error_report("%s, %s", sd_strerror(rsp->result), s->inode.name);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -1567,18 +1525,21 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_prealloc(const char *filename, Error **errp)
|
||||
static int sd_prealloc(const char *filename)
|
||||
{
|
||||
BlockDriverState *bs = NULL;
|
||||
uint32_t idx, max_idx;
|
||||
int64_t vdi_size;
|
||||
void *buf = g_malloc0(SD_DATA_OBJ_SIZE);
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
|
||||
NULL, errp);
|
||||
NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
goto out_with_err_set;
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
vdi_size = bdrv_getlength(bs);
|
||||
@@ -1602,12 +1563,7 @@ static int sd_prealloc(const char *filename, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Can't pre-allocate");
|
||||
}
|
||||
out_with_err_set:
|
||||
if (bs) {
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
@@ -1680,6 +1636,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
char tag[SD_MAX_VDI_TAG_LEN];
|
||||
uint32_t snapid;
|
||||
bool prealloc = false;
|
||||
Error *local_err = NULL;
|
||||
|
||||
s = g_malloc0(sizeof(BDRVSheepdogState));
|
||||
|
||||
@@ -1690,7 +1647,6 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
ret = parse_vdiname(s, filename, s->name, &snapid, tag);
|
||||
}
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Can't parse filename");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1705,8 +1661,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
} else if (!strcmp(options->value.s, "full")) {
|
||||
prealloc = true;
|
||||
} else {
|
||||
error_setg(errp, "Invalid preallocation mode: '%s'",
|
||||
options->value.s);
|
||||
error_report("Invalid preallocation mode: '%s'",
|
||||
options->value.s);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1714,8 +1670,6 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
if (options->value.s) {
|
||||
ret = parse_redundancy(s, options->value.s);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Invalid redundancy mode: '%s'",
|
||||
options->value.s);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -1724,7 +1678,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
}
|
||||
|
||||
if (s->inode.vdi_size > SD_MAX_VDI_SIZE) {
|
||||
error_setg(errp, "too big image size");
|
||||
error_report("too big image size");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1737,22 +1691,24 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
/* Currently, only Sheepdog backing image is supported. */
|
||||
drv = bdrv_find_protocol(backing_file, true);
|
||||
if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
|
||||
error_setg(errp, "backing_file must be a sheepdog image");
|
||||
error_report("backing_file must be a sheepdog image");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bs = NULL;
|
||||
ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_PROTOCOL, NULL,
|
||||
errp);
|
||||
&local_err);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
base = bs->opaque;
|
||||
|
||||
if (!is_snapshot(&base->inode)) {
|
||||
error_setg(errp, "cannot clone from a non snapshot vdi");
|
||||
error_report("cannot clone from a non snapshot vdi");
|
||||
bdrv_unref(bs);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
@@ -1761,14 +1717,12 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
|
||||
ret = do_sd_create(s, &vid, 0, errp);
|
||||
if (ret) {
|
||||
ret = do_sd_create(s, &vid, 0);
|
||||
if (!prealloc || ret) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (prealloc) {
|
||||
ret = sd_prealloc(filename, errp);
|
||||
}
|
||||
ret = sd_prealloc(filename);
|
||||
out:
|
||||
g_free(s);
|
||||
return ret;
|
||||
@@ -1776,7 +1730,6 @@ out:
|
||||
|
||||
static void sd_close(BlockDriverState *bs)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
SheepdogVdiReq hdr;
|
||||
SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
|
||||
@@ -1785,10 +1738,8 @@ static void sd_close(BlockDriverState *bs)
|
||||
|
||||
DPRINTF("%s\n", s->name);
|
||||
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
fd = connect_to_sdog(s);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1800,8 +1751,7 @@ static void sd_close(BlockDriverState *bs)
|
||||
hdr.data_length = wlen;
|
||||
hdr.flags = SD_FLAG_CMD_WRITE;
|
||||
|
||||
ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr,
|
||||
s->name, &wlen, &rlen);
|
||||
ret = do_req(fd, (SheepdogReq *)&hdr, s->name, &wlen, &rlen);
|
||||
|
||||
closesocket(fd);
|
||||
|
||||
@@ -1810,7 +1760,7 @@ static void sd_close(BlockDriverState *bs)
|
||||
error_report("%s, %s", sd_strerror(rsp->result), s->name);
|
||||
}
|
||||
|
||||
aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd, NULL, NULL, NULL);
|
||||
qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL);
|
||||
closesocket(s->fd);
|
||||
g_free(s->host_spec);
|
||||
}
|
||||
@@ -1824,7 +1774,6 @@ static int64_t sd_getlength(BlockDriverState *bs)
|
||||
|
||||
static int sd_truncate(BlockDriverState *bs, int64_t offset)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
int ret, fd;
|
||||
unsigned int datalen;
|
||||
@@ -1837,19 +1786,16 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
fd = connect_to_sdog(s);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* we don't need to update entire object */
|
||||
datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
|
||||
s->inode.vdi_size = offset;
|
||||
ret = write_object(fd, s->aio_context, (char *)&s->inode,
|
||||
vid_to_vdi_oid(s->inode.vdi_id), s->inode.nr_copies,
|
||||
datalen, 0, false, s->cache_flags);
|
||||
ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
|
||||
s->inode.nr_copies, datalen, 0, false, s->cache_flags);
|
||||
close(fd);
|
||||
|
||||
if (ret < 0) {
|
||||
@@ -1885,9 +1831,9 @@ static void coroutine_fn sd_write_done(SheepdogAIOCB *acb)
|
||||
iov.iov_base = &s->inode;
|
||||
iov.iov_len = sizeof(s->inode);
|
||||
aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id),
|
||||
data_len, offset, 0, false, 0, offset);
|
||||
data_len, offset, 0, 0, offset);
|
||||
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
|
||||
add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA);
|
||||
add_aio_request(s, aio_req, &iov, 1, false, AIOCB_WRITE_UDATA);
|
||||
|
||||
acb->aio_done_func = sd_finish_aiocb;
|
||||
acb->aiocb_type = AIOCB_WRITE_UDATA;
|
||||
@@ -1900,7 +1846,6 @@ static void coroutine_fn sd_write_done(SheepdogAIOCB *acb)
|
||||
/* Delete current working VDI on the snapshot chain */
|
||||
static bool sd_delete(BDRVSheepdogState *s)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
unsigned int wlen = SD_MAX_VDI_LEN, rlen = 0;
|
||||
SheepdogVdiReq hdr = {
|
||||
.opcode = SD_OP_DEL_VDI,
|
||||
@@ -1911,15 +1856,12 @@ static bool sd_delete(BDRVSheepdogState *s)
|
||||
SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
|
||||
int fd, ret;
|
||||
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
fd = connect_to_sdog(s);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr,
|
||||
s->name, &wlen, &rlen);
|
||||
ret = do_req(fd, (SheepdogReq *)&hdr, s->name, &wlen, &rlen);
|
||||
closesocket(fd);
|
||||
if (ret) {
|
||||
return false;
|
||||
@@ -1943,7 +1885,6 @@ static bool sd_delete(BDRVSheepdogState *s)
|
||||
*/
|
||||
static int sd_create_branch(BDRVSheepdogState *s)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int ret, fd;
|
||||
uint32_t vid;
|
||||
char *buf;
|
||||
@@ -1959,25 +1900,21 @@ static int sd_create_branch(BDRVSheepdogState *s)
|
||||
* false bail out.
|
||||
*/
|
||||
deleted = sd_delete(s);
|
||||
ret = do_sd_create(s, &vid, !deleted, &local_err);
|
||||
ret = do_sd_create(s, &vid, !deleted);
|
||||
if (ret) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
DPRINTF("%" PRIx32 " is created.\n", vid);
|
||||
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
fd = connect_to_sdog(s);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = read_object(fd, s->aio_context, buf, vid_to_vdi_oid(vid),
|
||||
s->inode.nr_copies, SD_INODE_SIZE, 0, s->cache_flags);
|
||||
ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies,
|
||||
SD_INODE_SIZE, 0, s->cache_flags);
|
||||
|
||||
closesocket(fd);
|
||||
|
||||
@@ -2086,8 +2023,7 @@ static int coroutine_fn sd_co_rw_vector(void *p)
|
||||
DPRINTF("new oid %" PRIx64 "\n", oid);
|
||||
}
|
||||
|
||||
aio_req = alloc_aio_req(s, acb, oid, len, offset, flags, create,
|
||||
old_oid, done);
|
||||
aio_req = alloc_aio_req(s, acb, oid, len, offset, flags, old_oid, done);
|
||||
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
|
||||
|
||||
if (create) {
|
||||
@@ -2096,7 +2032,7 @@ static int coroutine_fn sd_co_rw_vector(void *p)
|
||||
}
|
||||
}
|
||||
|
||||
add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
|
||||
add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, create,
|
||||
acb->aiocb_type);
|
||||
done:
|
||||
offset = 0;
|
||||
@@ -2176,9 +2112,9 @@ static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs)
|
||||
acb->aio_done_func = sd_finish_aiocb;
|
||||
|
||||
aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id),
|
||||
0, 0, 0, false, 0, 0);
|
||||
0, 0, 0, 0, 0);
|
||||
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
|
||||
add_aio_request(s, aio_req, NULL, 0, acb->aiocb_type);
|
||||
add_aio_request(s, aio_req, NULL, 0, false, acb->aiocb_type);
|
||||
|
||||
qemu_coroutine_yield();
|
||||
return acb->ret;
|
||||
@@ -2186,7 +2122,6 @@ static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs)
|
||||
|
||||
static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
int ret, fd;
|
||||
uint32_t new_vid;
|
||||
@@ -2217,34 +2152,28 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
inode = g_malloc(datalen);
|
||||
|
||||
/* refresh inode. */
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
fd = connect_to_sdog(s);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
ret = fd;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = write_object(fd, s->aio_context, (char *)&s->inode,
|
||||
vid_to_vdi_oid(s->inode.vdi_id), s->inode.nr_copies,
|
||||
datalen, 0, false, s->cache_flags);
|
||||
ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
|
||||
s->inode.nr_copies, datalen, 0, false, s->cache_flags);
|
||||
if (ret < 0) {
|
||||
error_report("failed to write snapshot's inode.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = do_sd_create(s, &new_vid, 1, &local_err);
|
||||
ret = do_sd_create(s, &new_vid, 1);
|
||||
if (ret < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
error_report("failed to create inode for snapshot. %s",
|
||||
strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = read_object(fd, s->aio_context, (char *)inode,
|
||||
vid_to_vdi_oid(new_vid), s->inode.nr_copies, datalen, 0,
|
||||
s->cache_flags);
|
||||
ret = read_object(fd, (char *)inode, vid_to_vdi_oid(new_vid),
|
||||
s->inode.nr_copies, datalen, 0, s->cache_flags);
|
||||
|
||||
if (ret < 0) {
|
||||
error_report("failed to read new inode info. %s", strerror(errno));
|
||||
@@ -2320,7 +2249,6 @@ static int sd_snapshot_delete(BlockDriverState *bs,
|
||||
|
||||
static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
SheepdogReq req;
|
||||
int fd, nr = 1024, ret, max = BITS_TO_LONGS(SD_NR_VDIS) * sizeof(long);
|
||||
@@ -2335,10 +2263,8 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
|
||||
vdi_inuse = g_malloc(max);
|
||||
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
fd = connect_to_sdog(s);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
@@ -2351,8 +2277,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
req.opcode = SD_OP_READ_VDIS;
|
||||
req.data_length = max;
|
||||
|
||||
ret = do_req(fd, s->aio_context, (SheepdogReq *)&req,
|
||||
vdi_inuse, &wlen, &rlen);
|
||||
ret = do_req(fd, (SheepdogReq *)&req, vdi_inuse, &wlen, &rlen);
|
||||
|
||||
closesocket(fd);
|
||||
if (ret) {
|
||||
@@ -2365,10 +2290,8 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
hval = fnv_64a_buf(s->name, strlen(s->name), FNV1A_64_INIT);
|
||||
start_nr = hval & (SD_NR_VDIS - 1);
|
||||
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
fd = connect_to_sdog(s);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
@@ -2379,8 +2302,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
}
|
||||
|
||||
/* we don't need to read entire object */
|
||||
ret = read_object(fd, s->aio_context, (char *)&inode,
|
||||
vid_to_vdi_oid(vid),
|
||||
ret = read_object(fd, (char *)&inode, vid_to_vdi_oid(vid),
|
||||
0, SD_INODE_SIZE - sizeof(inode.data_vdi_id), 0,
|
||||
s->cache_flags);
|
||||
|
||||
@@ -2394,8 +2316,8 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
sn_tab[found].vm_state_size = inode.vm_state_size;
|
||||
sn_tab[found].vm_clock_nsec = inode.vm_clock_nsec;
|
||||
|
||||
snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str),
|
||||
"%" PRIu32, inode.snap_id);
|
||||
snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str), "%u",
|
||||
inode.snap_id);
|
||||
pstrcpy(sn_tab[found].name,
|
||||
MIN(sizeof(sn_tab[found].name), sizeof(inode.tag)),
|
||||
inode.tag);
|
||||
@@ -2419,7 +2341,6 @@ out:
|
||||
static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
||||
int64_t pos, int size, int load)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
bool create;
|
||||
int fd, ret = 0, remaining = size;
|
||||
unsigned int data_len;
|
||||
@@ -2428,10 +2349,8 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
||||
uint32_t vdi_index;
|
||||
uint32_t vdi_id = load ? s->inode.parent_vdi_id : s->inode.vdi_id;
|
||||
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
fd = connect_to_sdog(s);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -2445,11 +2364,11 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
||||
|
||||
create = (offset == 0);
|
||||
if (load) {
|
||||
ret = read_object(fd, s->aio_context, (char *)data, vmstate_oid,
|
||||
ret = read_object(fd, (char *)data, vmstate_oid,
|
||||
s->inode.nr_copies, data_len, offset,
|
||||
s->cache_flags);
|
||||
} else {
|
||||
ret = write_object(fd, s->aio_context, (char *)data, vmstate_oid,
|
||||
ret = write_object(fd, (char *)data, vmstate_oid,
|
||||
s->inode.nr_copies, data_len, offset, create,
|
||||
s->cache_flags);
|
||||
}
|
||||
@@ -2622,9 +2541,6 @@ static BlockDriver bdrv_sheepdog = {
|
||||
.bdrv_save_vmstate = sd_save_vmstate,
|
||||
.bdrv_load_vmstate = sd_load_vmstate,
|
||||
|
||||
.bdrv_detach_aio_context = sd_detach_aio_context,
|
||||
.bdrv_attach_aio_context = sd_attach_aio_context,
|
||||
|
||||
.create_options = sd_create_options,
|
||||
};
|
||||
|
||||
@@ -2655,9 +2571,6 @@ static BlockDriver bdrv_sheepdog_tcp = {
|
||||
.bdrv_save_vmstate = sd_save_vmstate,
|
||||
.bdrv_load_vmstate = sd_load_vmstate,
|
||||
|
||||
.bdrv_detach_aio_context = sd_detach_aio_context,
|
||||
.bdrv_attach_aio_context = sd_attach_aio_context,
|
||||
|
||||
.create_options = sd_create_options,
|
||||
};
|
||||
|
||||
@@ -2688,9 +2601,6 @@ static BlockDriver bdrv_sheepdog_unix = {
|
||||
.bdrv_save_vmstate = sd_save_vmstate,
|
||||
.bdrv_load_vmstate = sd_load_vmstate,
|
||||
|
||||
.bdrv_detach_aio_context = sd_detach_aio_context,
|
||||
.bdrv_attach_aio_context = sd_attach_aio_context,
|
||||
|
||||
.create_options = sd_create_options,
|
||||
};
|
||||
|
||||
|
187
block/ssh.c
187
block/ssh.c
@@ -106,59 +106,30 @@ static void ssh_state_free(BDRVSSHState *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void GCC_FMT_ATTR(3, 4)
|
||||
session_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
|
||||
/* Wrappers around error_report which make sure to dump as much
|
||||
* information from libssh2 as possible.
|
||||
*/
|
||||
static void GCC_FMT_ATTR(2, 3)
|
||||
session_error_report(BDRVSSHState *s, const char *fs, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *msg;
|
||||
|
||||
va_start(args, fs);
|
||||
msg = g_strdup_vprintf(fs, args);
|
||||
va_end(args);
|
||||
error_vprintf(fs, args);
|
||||
|
||||
if (s->session) {
|
||||
if ((s)->session) {
|
||||
char *ssh_err;
|
||||
int ssh_err_code;
|
||||
|
||||
libssh2_session_last_error((s)->session, &ssh_err, NULL, 0);
|
||||
/* This is not an errno. See <libssh2.h>. */
|
||||
ssh_err_code = libssh2_session_last_error(s->session,
|
||||
&ssh_err, NULL, 0);
|
||||
error_setg(errp, "%s: %s (libssh2 error code: %d)",
|
||||
msg, ssh_err, ssh_err_code);
|
||||
} else {
|
||||
error_setg(errp, "%s", msg);
|
||||
ssh_err_code = libssh2_session_last_errno((s)->session);
|
||||
|
||||
error_printf(": %s (libssh2 error code: %d)", ssh_err, ssh_err_code);
|
||||
}
|
||||
g_free(msg);
|
||||
}
|
||||
|
||||
static void GCC_FMT_ATTR(3, 4)
|
||||
sftp_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *msg;
|
||||
|
||||
va_start(args, fs);
|
||||
msg = g_strdup_vprintf(fs, args);
|
||||
va_end(args);
|
||||
|
||||
if (s->sftp) {
|
||||
char *ssh_err;
|
||||
int ssh_err_code;
|
||||
unsigned long sftp_err_code;
|
||||
|
||||
/* This is not an errno. See <libssh2.h>. */
|
||||
ssh_err_code = libssh2_session_last_error(s->session,
|
||||
&ssh_err, NULL, 0);
|
||||
/* See <libssh2_sftp.h>. */
|
||||
sftp_err_code = libssh2_sftp_last_error((s)->sftp);
|
||||
|
||||
error_setg(errp,
|
||||
"%s: %s (libssh2 error code: %d, sftp error code: %lu)",
|
||||
msg, ssh_err, ssh_err_code, sftp_err_code);
|
||||
} else {
|
||||
error_setg(errp, "%s", msg);
|
||||
}
|
||||
g_free(msg);
|
||||
error_printf("\n");
|
||||
}
|
||||
|
||||
static void GCC_FMT_ATTR(2, 3)
|
||||
@@ -174,9 +145,9 @@ sftp_error_report(BDRVSSHState *s, const char *fs, ...)
|
||||
int ssh_err_code;
|
||||
unsigned long sftp_err_code;
|
||||
|
||||
libssh2_session_last_error((s)->session, &ssh_err, NULL, 0);
|
||||
/* This is not an errno. See <libssh2.h>. */
|
||||
ssh_err_code = libssh2_session_last_error(s->session,
|
||||
&ssh_err, NULL, 0);
|
||||
ssh_err_code = libssh2_session_last_errno((s)->session);
|
||||
/* See <libssh2_sftp.h>. */
|
||||
sftp_err_code = libssh2_sftp_last_error((s)->sftp);
|
||||
|
||||
@@ -272,7 +243,7 @@ static void ssh_parse_filename(const char *filename, QDict *options,
|
||||
}
|
||||
|
||||
static int check_host_key_knownhosts(BDRVSSHState *s,
|
||||
const char *host, int port, Error **errp)
|
||||
const char *host, int port)
|
||||
{
|
||||
const char *home;
|
||||
char *knh_file = NULL;
|
||||
@@ -286,15 +257,14 @@ static int check_host_key_knownhosts(BDRVSSHState *s,
|
||||
hostkey = libssh2_session_hostkey(s->session, &len, &type);
|
||||
if (!hostkey) {
|
||||
ret = -EINVAL;
|
||||
session_error_setg(errp, s, "failed to read remote host key");
|
||||
session_error_report(s, "failed to read remote host key");
|
||||
goto out;
|
||||
}
|
||||
|
||||
knh = libssh2_knownhost_init(s->session);
|
||||
if (!knh) {
|
||||
ret = -EINVAL;
|
||||
session_error_setg(errp, s,
|
||||
"failed to initialize known hosts support");
|
||||
session_error_report(s, "failed to initialize known hosts support");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -319,23 +289,21 @@ static int check_host_key_knownhosts(BDRVSSHState *s,
|
||||
break;
|
||||
case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
|
||||
ret = -EINVAL;
|
||||
session_error_setg(errp, s,
|
||||
"host key does not match the one in known_hosts"
|
||||
" (found key %s)", found->key);
|
||||
session_error_report(s, "host key does not match the one in known_hosts (found key %s)",
|
||||
found->key);
|
||||
goto out;
|
||||
case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
|
||||
ret = -EINVAL;
|
||||
session_error_setg(errp, s, "no host key was found in known_hosts");
|
||||
session_error_report(s, "no host key was found in known_hosts");
|
||||
goto out;
|
||||
case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
|
||||
ret = -EINVAL;
|
||||
session_error_setg(errp, s,
|
||||
"failure matching the host key with known_hosts");
|
||||
session_error_report(s, "failure matching the host key with known_hosts");
|
||||
goto out;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
session_error_setg(errp, s, "unknown error matching the host key"
|
||||
" with known_hosts (%d)", r);
|
||||
session_error_report(s, "unknown error matching the host key with known_hosts (%d)",
|
||||
r);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -390,20 +358,20 @@ static int compare_fingerprint(const unsigned char *fingerprint, size_t len,
|
||||
|
||||
static int
|
||||
check_host_key_hash(BDRVSSHState *s, const char *hash,
|
||||
int hash_type, size_t fingerprint_len, Error **errp)
|
||||
int hash_type, size_t fingerprint_len)
|
||||
{
|
||||
const char *fingerprint;
|
||||
|
||||
fingerprint = libssh2_hostkey_hash(s->session, hash_type);
|
||||
if (!fingerprint) {
|
||||
session_error_setg(errp, s, "failed to read remote host key");
|
||||
session_error_report(s, "failed to read remote host key");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if(compare_fingerprint((unsigned char *) fingerprint, fingerprint_len,
|
||||
hash) != 0) {
|
||||
error_setg(errp, "remote host key does not match host_key_check '%s'",
|
||||
hash);
|
||||
error_report("remote host key does not match host_key_check '%s'",
|
||||
hash);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@@ -411,7 +379,7 @@ check_host_key_hash(BDRVSSHState *s, const char *hash,
|
||||
}
|
||||
|
||||
static int check_host_key(BDRVSSHState *s, const char *host, int port,
|
||||
const char *host_key_check, Error **errp)
|
||||
const char *host_key_check)
|
||||
{
|
||||
/* host_key_check=no */
|
||||
if (strcmp(host_key_check, "no") == 0) {
|
||||
@@ -421,25 +389,25 @@ static int check_host_key(BDRVSSHState *s, const char *host, int port,
|
||||
/* host_key_check=md5:xx:yy:zz:... */
|
||||
if (strncmp(host_key_check, "md5:", 4) == 0) {
|
||||
return check_host_key_hash(s, &host_key_check[4],
|
||||
LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
|
||||
LIBSSH2_HOSTKEY_HASH_MD5, 16);
|
||||
}
|
||||
|
||||
/* host_key_check=sha1:xx:yy:zz:... */
|
||||
if (strncmp(host_key_check, "sha1:", 5) == 0) {
|
||||
return check_host_key_hash(s, &host_key_check[5],
|
||||
LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
|
||||
LIBSSH2_HOSTKEY_HASH_SHA1, 20);
|
||||
}
|
||||
|
||||
/* host_key_check=yes */
|
||||
if (strcmp(host_key_check, "yes") == 0) {
|
||||
return check_host_key_knownhosts(s, host, port, errp);
|
||||
return check_host_key_knownhosts(s, host, port);
|
||||
}
|
||||
|
||||
error_setg(errp, "unknown host_key_check setting (%s)", host_key_check);
|
||||
error_report("unknown host_key_check setting (%s)", host_key_check);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
|
||||
static int authenticate(BDRVSSHState *s, const char *user)
|
||||
{
|
||||
int r, ret;
|
||||
const char *userauthlist;
|
||||
@@ -450,8 +418,7 @@ static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
|
||||
userauthlist = libssh2_userauth_list(s->session, user, strlen(user));
|
||||
if (strstr(userauthlist, "publickey") == NULL) {
|
||||
ret = -EPERM;
|
||||
error_setg(errp,
|
||||
"remote server does not support \"publickey\" authentication");
|
||||
error_report("remote server does not support \"publickey\" authentication");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -459,18 +426,17 @@ static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
|
||||
agent = libssh2_agent_init(s->session);
|
||||
if (!agent) {
|
||||
ret = -EINVAL;
|
||||
session_error_setg(errp, s, "failed to initialize ssh-agent support");
|
||||
session_error_report(s, "failed to initialize ssh-agent support");
|
||||
goto out;
|
||||
}
|
||||
if (libssh2_agent_connect(agent)) {
|
||||
ret = -ECONNREFUSED;
|
||||
session_error_setg(errp, s, "failed to connect to ssh-agent");
|
||||
session_error_report(s, "failed to connect to ssh-agent");
|
||||
goto out;
|
||||
}
|
||||
if (libssh2_agent_list_identities(agent)) {
|
||||
ret = -EINVAL;
|
||||
session_error_setg(errp, s,
|
||||
"failed requesting identities from ssh-agent");
|
||||
session_error_report(s, "failed requesting identities from ssh-agent");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -481,8 +447,7 @@ static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
|
||||
}
|
||||
if (r < 0) {
|
||||
ret = -EINVAL;
|
||||
session_error_setg(errp, s,
|
||||
"failed to obtain identity from ssh-agent");
|
||||
session_error_report(s, "failed to obtain identity from ssh-agent");
|
||||
goto out;
|
||||
}
|
||||
r = libssh2_agent_userauth(agent, user, identity);
|
||||
@@ -496,8 +461,8 @@ static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
|
||||
}
|
||||
|
||||
ret = -EPERM;
|
||||
error_setg(errp, "failed to authenticate using publickey authentication "
|
||||
"and the identities held by your ssh-agent");
|
||||
error_report("failed to authenticate using publickey authentication "
|
||||
"and the identities held by your ssh-agent");
|
||||
|
||||
out:
|
||||
if (agent != NULL) {
|
||||
@@ -511,9 +476,10 @@ static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
|
||||
}
|
||||
|
||||
static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
int ssh_flags, int creat_mode, Error **errp)
|
||||
int ssh_flags, int creat_mode)
|
||||
{
|
||||
int r, ret;
|
||||
Error *err = NULL;
|
||||
const char *host, *user, *path, *host_key_check;
|
||||
int port;
|
||||
|
||||
@@ -532,7 +498,6 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
} else {
|
||||
user = g_get_user_name();
|
||||
if (!user) {
|
||||
error_setg_errno(errp, errno, "Can't get user name");
|
||||
ret = -errno;
|
||||
goto err;
|
||||
}
|
||||
@@ -549,9 +514,11 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
s->hostport = g_strdup_printf("%s:%d", host, port);
|
||||
|
||||
/* Open the socket and connect. */
|
||||
s->sock = inet_connect(s->hostport, errp);
|
||||
if (s->sock < 0) {
|
||||
s->sock = inet_connect(s->hostport, &err);
|
||||
if (err != NULL) {
|
||||
ret = -errno;
|
||||
qerror_report_err(err);
|
||||
error_free(err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -559,7 +526,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
s->session = libssh2_session_init();
|
||||
if (!s->session) {
|
||||
ret = -EINVAL;
|
||||
session_error_setg(errp, s, "failed to initialize libssh2 session");
|
||||
session_error_report(s, "failed to initialize libssh2 session");
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -570,18 +537,18 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
r = libssh2_session_handshake(s->session, s->sock);
|
||||
if (r != 0) {
|
||||
ret = -EINVAL;
|
||||
session_error_setg(errp, s, "failed to establish SSH session");
|
||||
session_error_report(s, "failed to establish SSH session");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Check the remote host's key against known_hosts. */
|
||||
ret = check_host_key(s, host, port, host_key_check, errp);
|
||||
ret = check_host_key(s, host, port, host_key_check);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Authenticate. */
|
||||
ret = authenticate(s, user, errp);
|
||||
ret = authenticate(s, user);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
@@ -589,7 +556,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
/* Start SFTP. */
|
||||
s->sftp = libssh2_sftp_init(s->session);
|
||||
if (!s->sftp) {
|
||||
session_error_setg(errp, s, "failed to initialize sftp handle");
|
||||
session_error_report(s, "failed to initialize sftp handle");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
@@ -599,14 +566,14 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
path, ssh_flags, creat_mode);
|
||||
s->sftp_handle = libssh2_sftp_open(s->sftp, path, ssh_flags, creat_mode);
|
||||
if (!s->sftp_handle) {
|
||||
session_error_setg(errp, s, "failed to open remote file '%s'", path);
|
||||
session_error_report(s, "failed to open remote file '%s'", path);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
|
||||
if (r < 0) {
|
||||
sftp_error_setg(errp, s, "failed to read file attributes");
|
||||
sftp_error_report(s, "failed to read file attributes");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -656,7 +623,7 @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
|
||||
}
|
||||
|
||||
/* Start up SSH. */
|
||||
ret = connect_to_ssh(s, options, ssh_flags, 0, errp);
|
||||
ret = connect_to_ssh(s, options, ssh_flags, 0);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
@@ -688,6 +655,7 @@ static int ssh_create(const char *filename, QEMUOptionParameter *options,
|
||||
Error **errp)
|
||||
{
|
||||
int r, ret;
|
||||
Error *local_err = NULL;
|
||||
int64_t total_size = 0;
|
||||
QDict *uri_options = NULL;
|
||||
BDRVSSHState s;
|
||||
@@ -706,16 +674,17 @@ static int ssh_create(const char *filename, QEMUOptionParameter *options,
|
||||
DPRINTF("total_size=%" PRIi64, total_size);
|
||||
|
||||
uri_options = qdict_new();
|
||||
r = parse_uri(filename, uri_options, errp);
|
||||
r = parse_uri(filename, uri_options, &local_err);
|
||||
if (r < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
ret = r;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = connect_to_ssh(&s, uri_options,
|
||||
LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
|
||||
LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
|
||||
0644, errp);
|
||||
LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC, 0644);
|
||||
if (r < 0) {
|
||||
ret = r;
|
||||
goto out;
|
||||
@@ -725,7 +694,7 @@ static int ssh_create(const char *filename, QEMUOptionParameter *options,
|
||||
libssh2_sftp_seek64(s.sftp_handle, total_size-1);
|
||||
r2 = libssh2_sftp_write(s.sftp_handle, c, 1);
|
||||
if (r2 < 0) {
|
||||
sftp_error_setg(errp, &s, "truncate failed");
|
||||
sftp_error_report(&s, "truncate failed");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -773,7 +742,7 @@ static void restart_coroutine(void *opaque)
|
||||
qemu_coroutine_enter(co, NULL);
|
||||
}
|
||||
|
||||
static coroutine_fn void set_fd_handler(BDRVSSHState *s, BlockDriverState *bs)
|
||||
static coroutine_fn void set_fd_handler(BDRVSSHState *s)
|
||||
{
|
||||
int r;
|
||||
IOHandler *rd_handler = NULL, *wr_handler = NULL;
|
||||
@@ -791,26 +760,24 @@ static coroutine_fn void set_fd_handler(BDRVSSHState *s, BlockDriverState *bs)
|
||||
DPRINTF("s->sock=%d rd_handler=%p wr_handler=%p", s->sock,
|
||||
rd_handler, wr_handler);
|
||||
|
||||
aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock,
|
||||
rd_handler, wr_handler, co);
|
||||
qemu_aio_set_fd_handler(s->sock, rd_handler, wr_handler, co);
|
||||
}
|
||||
|
||||
static coroutine_fn void clear_fd_handler(BDRVSSHState *s,
|
||||
BlockDriverState *bs)
|
||||
static coroutine_fn void clear_fd_handler(BDRVSSHState *s)
|
||||
{
|
||||
DPRINTF("s->sock=%d", s->sock);
|
||||
aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock, NULL, NULL, NULL);
|
||||
qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/* A non-blocking call returned EAGAIN, so yield, ensuring the
|
||||
* handlers are set up so that we'll be rescheduled when there is an
|
||||
* interesting event on the socket.
|
||||
*/
|
||||
static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
|
||||
static coroutine_fn void co_yield(BDRVSSHState *s)
|
||||
{
|
||||
set_fd_handler(s, bs);
|
||||
set_fd_handler(s);
|
||||
qemu_coroutine_yield();
|
||||
clear_fd_handler(s, bs);
|
||||
clear_fd_handler(s);
|
||||
}
|
||||
|
||||
/* SFTP has a function `libssh2_sftp_seek64' which seeks to a position
|
||||
@@ -840,7 +807,7 @@ static void ssh_seek(BDRVSSHState *s, int64_t offset, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
|
||||
static coroutine_fn int ssh_read(BDRVSSHState *s,
|
||||
int64_t offset, size_t size,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
@@ -873,7 +840,7 @@ static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
|
||||
DPRINTF("sftp_read returned %zd", r);
|
||||
|
||||
if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
|
||||
co_yield(s, bs);
|
||||
co_yield(s);
|
||||
goto again;
|
||||
}
|
||||
if (r < 0) {
|
||||
@@ -908,14 +875,14 @@ static coroutine_fn int ssh_co_readv(BlockDriverState *bs,
|
||||
int ret;
|
||||
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
ret = ssh_read(s, bs, sector_num * BDRV_SECTOR_SIZE,
|
||||
ret = ssh_read(s, sector_num * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE, qiov);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
|
||||
static int ssh_write(BDRVSSHState *s,
|
||||
int64_t offset, size_t size,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
@@ -943,7 +910,7 @@ static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
|
||||
DPRINTF("sftp_write returned %zd", r);
|
||||
|
||||
if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
|
||||
co_yield(s, bs);
|
||||
co_yield(s);
|
||||
goto again;
|
||||
}
|
||||
if (r < 0) {
|
||||
@@ -962,7 +929,7 @@ static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
|
||||
*/
|
||||
if (r == 0) {
|
||||
ssh_seek(s, offset + written, SSH_SEEK_WRITE|SSH_SEEK_FORCE);
|
||||
co_yield(s, bs);
|
||||
co_yield(s);
|
||||
goto again;
|
||||
}
|
||||
|
||||
@@ -990,7 +957,7 @@ static coroutine_fn int ssh_co_writev(BlockDriverState *bs,
|
||||
int ret;
|
||||
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
ret = ssh_write(s, bs, sector_num * BDRV_SECTOR_SIZE,
|
||||
ret = ssh_write(s, sector_num * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE, qiov);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
|
||||
@@ -1011,7 +978,7 @@ static void unsafe_flush_warning(BDRVSSHState *s, const char *what)
|
||||
|
||||
#ifdef HAS_LIBSSH2_SFTP_FSYNC
|
||||
|
||||
static coroutine_fn int ssh_flush(BDRVSSHState *s, BlockDriverState *bs)
|
||||
static coroutine_fn int ssh_flush(BDRVSSHState *s)
|
||||
{
|
||||
int r;
|
||||
|
||||
@@ -1019,7 +986,7 @@ static coroutine_fn int ssh_flush(BDRVSSHState *s, BlockDriverState *bs)
|
||||
again:
|
||||
r = libssh2_sftp_fsync(s->sftp_handle);
|
||||
if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
|
||||
co_yield(s, bs);
|
||||
co_yield(s);
|
||||
goto again;
|
||||
}
|
||||
if (r == LIBSSH2_ERROR_SFTP_PROTOCOL &&
|
||||
@@ -1041,7 +1008,7 @@ static coroutine_fn int ssh_co_flush(BlockDriverState *bs)
|
||||
int ret;
|
||||
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
ret = ssh_flush(s, bs);
|
||||
ret = ssh_flush(s);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
|
||||
return ret;
|
||||
|
@@ -60,7 +60,7 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base,
|
||||
/* Must assign before bdrv_delete() to prevent traversing dangling pointer
|
||||
* while we delete backing image instances.
|
||||
*/
|
||||
bdrv_set_backing_hd(top, base);
|
||||
top->backing_hd = base;
|
||||
|
||||
while (intermediate) {
|
||||
BlockDriverState *unused;
|
||||
@@ -72,7 +72,7 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base,
|
||||
|
||||
unused = intermediate;
|
||||
intermediate = intermediate->backing_hd;
|
||||
bdrv_set_backing_hd(unused, NULL);
|
||||
unused->backing_hd = NULL;
|
||||
bdrv_unref(unused);
|
||||
}
|
||||
|
||||
|
28
block/vdi.c
28
block/vdi.c
@@ -408,35 +408,34 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
if (header.signature != VDI_SIGNATURE) {
|
||||
error_setg(errp, "Image not in VDI format (bad signature %08" PRIx32
|
||||
")", header.signature);
|
||||
error_setg(errp, "Image not in VDI format (bad signature %08x)", header.signature);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
} else if (header.version != VDI_VERSION_1_1) {
|
||||
error_setg(errp, "unsupported VDI image (version %" PRIu32 ".%" PRIu32
|
||||
")", header.version >> 16, header.version & 0xffff);
|
||||
error_setg(errp, "unsupported VDI image (version %u.%u)",
|
||||
header.version >> 16, header.version & 0xffff);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.offset_bmap % SECTOR_SIZE != 0) {
|
||||
/* We only support block maps which start on a sector boundary. */
|
||||
error_setg(errp, "unsupported VDI image (unaligned block map offset "
|
||||
"0x%" PRIx32 ")", header.offset_bmap);
|
||||
"0x%x)", header.offset_bmap);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.offset_data % SECTOR_SIZE != 0) {
|
||||
/* We only support data blocks which start on a sector boundary. */
|
||||
error_setg(errp, "unsupported VDI image (unaligned data offset 0x%"
|
||||
PRIx32 ")", header.offset_data);
|
||||
error_setg(errp, "unsupported VDI image (unaligned data offset 0x%x)",
|
||||
header.offset_data);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.sector_size != SECTOR_SIZE) {
|
||||
error_setg(errp, "unsupported VDI image (sector size %" PRIu32
|
||||
" is not %u)", header.sector_size, SECTOR_SIZE);
|
||||
error_setg(errp, "unsupported VDI image (sector size %u is not %u)",
|
||||
header.sector_size, SECTOR_SIZE);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
|
||||
error_setg(errp, "unsupported VDI image (block size %" PRIu32
|
||||
" is not %u)", header.block_size, DEFAULT_CLUSTER_SIZE);
|
||||
error_setg(errp, "unsupported VDI image (block size %u is not %u)",
|
||||
header.block_size, DEFAULT_CLUSTER_SIZE);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.disk_size >
|
||||
@@ -756,7 +755,6 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
||||
vdi_header_to_le(&header);
|
||||
if (write(fd, &header, sizeof(header)) < 0) {
|
||||
result = -errno;
|
||||
goto close_and_exit;
|
||||
}
|
||||
|
||||
if (bmap_size > 0) {
|
||||
@@ -770,8 +768,6 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
||||
}
|
||||
if (write(fd, bmap, bmap_size) < 0) {
|
||||
result = -errno;
|
||||
g_free(bmap);
|
||||
goto close_and_exit;
|
||||
}
|
||||
g_free(bmap);
|
||||
}
|
||||
@@ -779,12 +775,10 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
||||
if (image_type == VDI_TYPE_STATIC) {
|
||||
if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
|
||||
result = -errno;
|
||||
goto close_and_exit;
|
||||
}
|
||||
}
|
||||
|
||||
close_and_exit:
|
||||
if ((close(fd) < 0) && !result) {
|
||||
if (close(fd) < 0) {
|
||||
result = -errno;
|
||||
}
|
||||
|
||||
|
@@ -473,14 +473,7 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
|
||||
} else if (h2_seq > h1_seq) {
|
||||
s->curr_header = 1;
|
||||
} else {
|
||||
/* The Microsoft Disk2VHD tool will create 2 identical
|
||||
* headers, with identical sequence numbers. If the headers are
|
||||
* identical, don't consider the file corrupt */
|
||||
if (!memcmp(header1, header2, sizeof(VHDXHeader))) {
|
||||
s->curr_header = 0;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
89
block/vmdk.c
89
block/vmdk.c
@@ -262,7 +262,7 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
|
||||
p_name = strstr(desc, cid_str);
|
||||
if (p_name != NULL) {
|
||||
p_name += cid_str_size;
|
||||
sscanf(p_name, "%" SCNx32, &cid);
|
||||
sscanf(p_name, "%x", &cid);
|
||||
}
|
||||
|
||||
return cid;
|
||||
@@ -290,7 +290,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
|
||||
p_name = strstr(desc, "CID");
|
||||
if (p_name != NULL) {
|
||||
p_name += sizeof("CID");
|
||||
snprintf(p_name, sizeof(desc) - (p_name - desc), "%" PRIx32 "\n", cid);
|
||||
snprintf(p_name, sizeof(desc) - (p_name - desc), "%x\n", cid);
|
||||
pstrcat(desc, sizeof(desc), tmp_desc);
|
||||
}
|
||||
|
||||
@@ -640,7 +640,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
|
||||
if (le32_to_cpu(header.version) > 3) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "VMDK version %" PRId32,
|
||||
snprintf(buf, sizeof(buf), "VMDK version %d",
|
||||
le32_to_cpu(header.version));
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "vmdk", buf);
|
||||
@@ -671,9 +671,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
}
|
||||
if (bdrv_getlength(file) <
|
||||
le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE) {
|
||||
error_setg(errp, "File truncated, expecting at least %" PRId64 " bytes",
|
||||
(int64_t)(le64_to_cpu(header.grain_offset)
|
||||
* BDRV_SECTOR_SIZE));
|
||||
error_setg(errp, "File truncated, expecting at least %lld bytes",
|
||||
le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1496,19 +1495,6 @@ static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vmdk_write_compressed(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
const uint8_t *buf,
|
||||
int nb_sectors)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
if (s->num_extents == 1 && s->extents[0].compressed) {
|
||||
return vmdk_write(bs, sector_num, buf, nb_sectors, false, false);
|
||||
} else {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors,
|
||||
@@ -1534,7 +1520,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||
int ret, i;
|
||||
BlockDriverState *bs = NULL;
|
||||
VMDK4Header header;
|
||||
Error *local_err = NULL;
|
||||
Error *local_err;
|
||||
uint32_t tmp, magic, grains, gd_sectors, gt_size, gt_count;
|
||||
uint32_t *gd_buf = NULL;
|
||||
int gd_buf_size;
|
||||
@@ -1700,7 +1686,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
{
|
||||
int idx = 0;
|
||||
BlockDriverState *new_bs = NULL;
|
||||
Error *local_err = NULL;
|
||||
Error *local_err;
|
||||
char *desc = NULL;
|
||||
int64_t total_size = 0, filesize;
|
||||
const char *adapter_type = NULL;
|
||||
@@ -1721,8 +1707,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
const char desc_template[] =
|
||||
"# Disk DescriptorFile\n"
|
||||
"version=1\n"
|
||||
"CID=%" PRIx32 "\n"
|
||||
"parentCID=%" PRIx32 "\n"
|
||||
"CID=%x\n"
|
||||
"parentCID=%x\n"
|
||||
"createType=\"%s\"\n"
|
||||
"%s"
|
||||
"\n"
|
||||
@@ -1734,7 +1720,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
"\n"
|
||||
"ddb.virtualHWVersion = \"%d\"\n"
|
||||
"ddb.geometry.cylinders = \"%" PRId64 "\"\n"
|
||||
"ddb.geometry.heads = \"%" PRIu32 "\"\n"
|
||||
"ddb.geometry.heads = \"%d\"\n"
|
||||
"ddb.geometry.sectors = \"63\"\n"
|
||||
"ddb.adapterType = \"%s\"\n";
|
||||
|
||||
@@ -1794,9 +1780,9 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
strcmp(fmt, "twoGbMaxExtentFlat"));
|
||||
compress = !strcmp(fmt, "streamOptimized");
|
||||
if (flat) {
|
||||
desc_extent_line = "RW %" PRId64 " FLAT \"%s\" 0\n";
|
||||
desc_extent_line = "RW %lld FLAT \"%s\" 0\n";
|
||||
} else {
|
||||
desc_extent_line = "RW %" PRId64 " SPARSE \"%s\"\n";
|
||||
desc_extent_line = "RW %lld SPARSE \"%s\"\n";
|
||||
}
|
||||
if (flat && backing_file) {
|
||||
error_setg(errp, "Flat image can't have backing file");
|
||||
@@ -1864,7 +1850,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
}
|
||||
/* generate descriptor file */
|
||||
desc = g_strdup_printf(desc_template,
|
||||
(uint32_t)time(NULL),
|
||||
(unsigned int)time(NULL),
|
||||
parent_cid,
|
||||
fmt,
|
||||
parent_desc_line,
|
||||
@@ -1881,7 +1867,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
} else {
|
||||
ret = bdrv_create_file(filename, options, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
error_setg_errno(errp, -ret, "Could not create image file");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
@@ -1889,7 +1875,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
ret = bdrv_open(&new_bs, filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
error_setg_errno(errp, -ret, "Could not write description");
|
||||
goto exit;
|
||||
}
|
||||
ret = bdrv_pwrite(new_bs, desc_offset, desc, desc_len);
|
||||
@@ -2076,47 +2062,6 @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs)
|
||||
return spec_info;
|
||||
}
|
||||
|
||||
static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
int i;
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
assert(s->num_extents);
|
||||
bdi->needs_compressed_writes = s->extents[0].compressed;
|
||||
if (!s->extents[0].flat) {
|
||||
bdi->cluster_size = s->extents[0].cluster_sectors << BDRV_SECTOR_BITS;
|
||||
}
|
||||
/* See if we have multiple extents but they have different cases */
|
||||
for (i = 1; i < s->num_extents; i++) {
|
||||
if (bdi->needs_compressed_writes != s->extents[i].compressed ||
|
||||
(bdi->cluster_size && bdi->cluster_size !=
|
||||
s->extents[i].cluster_sectors << BDRV_SECTOR_BITS)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vmdk_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->num_extents; i++) {
|
||||
bdrv_detach_aio_context(s->extents[i].file);
|
||||
}
|
||||
}
|
||||
|
||||
static void vmdk_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->num_extents; i++) {
|
||||
bdrv_attach_aio_context(s->extents[i].file, new_context);
|
||||
}
|
||||
}
|
||||
|
||||
static QEMUOptionParameter vmdk_create_options[] = {
|
||||
{
|
||||
.name = BLOCK_OPT_SIZE,
|
||||
@@ -2163,7 +2108,6 @@ static BlockDriver bdrv_vmdk = {
|
||||
.bdrv_reopen_prepare = vmdk_reopen_prepare,
|
||||
.bdrv_read = vmdk_co_read,
|
||||
.bdrv_write = vmdk_co_write,
|
||||
.bdrv_write_compressed = vmdk_write_compressed,
|
||||
.bdrv_co_write_zeroes = vmdk_co_write_zeroes,
|
||||
.bdrv_close = vmdk_close,
|
||||
.bdrv_create = vmdk_create,
|
||||
@@ -2173,9 +2117,6 @@ static BlockDriver bdrv_vmdk = {
|
||||
.bdrv_has_zero_init = vmdk_has_zero_init,
|
||||
.bdrv_get_specific_info = vmdk_get_specific_info,
|
||||
.bdrv_refresh_limits = vmdk_refresh_limits,
|
||||
.bdrv_get_info = vmdk_get_info,
|
||||
.bdrv_detach_aio_context = vmdk_detach_aio_context,
|
||||
.bdrv_attach_aio_context = vmdk_attach_aio_context,
|
||||
|
||||
.create_options = vmdk_create_options,
|
||||
};
|
||||
|
@@ -833,8 +833,7 @@ static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
|
||||
}
|
||||
|
||||
static int init_directories(BDRVVVFATState* s,
|
||||
const char *dirname, int heads, int secs,
|
||||
Error **errp)
|
||||
const char *dirname, int heads, int secs)
|
||||
{
|
||||
bootsector_t* bootsector;
|
||||
mapping_t* mapping;
|
||||
@@ -895,8 +894,8 @@ static int init_directories(BDRVVVFATState* s,
|
||||
if (mapping->mode & MODE_DIRECTORY) {
|
||||
mapping->begin = cluster;
|
||||
if(read_directory(s, i)) {
|
||||
error_setg(errp, "Could not read directory %s",
|
||||
mapping->path);
|
||||
fprintf(stderr, "Could not read directory %s\n",
|
||||
mapping->path);
|
||||
return -1;
|
||||
}
|
||||
mapping = array_get(&(s->mapping), i);
|
||||
@@ -922,10 +921,9 @@ static int init_directories(BDRVVVFATState* s,
|
||||
cluster = mapping->end;
|
||||
|
||||
if(cluster > s->cluster_count) {
|
||||
error_setg(errp,
|
||||
"Directory does not fit in FAT%d (capacity %.2f MB)",
|
||||
s->fat_type, s->sector_count / 2000.0);
|
||||
return -1;
|
||||
fprintf(stderr,"Directory does not fit in FAT%d (capacity %.2f MB)\n",
|
||||
s->fat_type, s->sector_count / 2000.0);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* fix fat for entry */
|
||||
@@ -983,7 +981,7 @@ static int init_directories(BDRVVVFATState* s,
|
||||
static BDRVVVFATState *vvv = NULL;
|
||||
#endif
|
||||
|
||||
static int enable_write_target(BDRVVVFATState *s, Error **errp);
|
||||
static int enable_write_target(BDRVVVFATState *s);
|
||||
static int is_consistent(BDRVVVFATState *s);
|
||||
|
||||
static void vvfat_rebind(BlockDriverState *bs)
|
||||
@@ -1164,7 +1162,7 @@ DLOG(if (stderr == NULL) {
|
||||
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
|
||||
|
||||
if (qemu_opt_get_bool(opts, "rw", false)) {
|
||||
ret = enable_write_target(s, errp);
|
||||
ret = enable_write_target(s);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -1173,7 +1171,7 @@ DLOG(if (stderr == NULL) {
|
||||
|
||||
bs->total_sectors = cyls * heads * secs;
|
||||
|
||||
if (init_directories(s, dirname, heads, secs, errp)) {
|
||||
if (init_directories(s, dirname, heads, secs)) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
@@ -2908,10 +2906,11 @@ static BlockDriver vvfat_write_target = {
|
||||
.bdrv_close = write_target_close,
|
||||
};
|
||||
|
||||
static int enable_write_target(BDRVVVFATState *s, Error **errp)
|
||||
static int enable_write_target(BDRVVVFATState *s)
|
||||
{
|
||||
BlockDriver *bdrv_qcow;
|
||||
QEMUOptionParameter *options;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
int size = sector2cluster(s, s->sector_count);
|
||||
s->used_clusters = calloc(size, 1);
|
||||
@@ -2921,7 +2920,6 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
|
||||
s->qcow_filename = g_malloc(1024);
|
||||
ret = get_tmp_filename(s->qcow_filename, 1024);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "can't create temporary file");
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -2930,17 +2928,20 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
|
||||
set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
|
||||
set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
|
||||
|
||||
ret = bdrv_create(bdrv_qcow, s->qcow_filename, options, errp);
|
||||
free_option_parameters(options);
|
||||
ret = bdrv_create(bdrv_qcow, s->qcow_filename, options, &local_err);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
s->qcow = NULL;
|
||||
ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH,
|
||||
bdrv_qcow, errp);
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow,
|
||||
&local_err);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -2948,7 +2949,7 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
|
||||
unlink(s->qcow_filename);
|
||||
#endif
|
||||
|
||||
bdrv_set_backing_hd(s->bs, bdrv_new("", &error_abort));
|
||||
s->bs->backing_hd = bdrv_new("");
|
||||
s->bs->backing_hd->drv = &vvfat_write_target;
|
||||
s->bs->backing_hd->opaque = g_malloc(sizeof(void*));
|
||||
*(void**)s->bs->backing_hd->opaque = s;
|
||||
|
@@ -40,7 +40,6 @@ struct QEMUWin32AIOState {
|
||||
HANDLE hIOCP;
|
||||
EventNotifier e;
|
||||
int count;
|
||||
bool is_aio_context_attached;
|
||||
};
|
||||
|
||||
typedef struct QEMUWin32AIOCB {
|
||||
@@ -115,7 +114,7 @@ static void win32_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
* wait for completion.
|
||||
*/
|
||||
while (!HasOverlappedIoCompleted(&waiocb->ov)) {
|
||||
aio_poll(bdrv_get_aio_context(blockacb->bs), true);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,20 +180,6 @@ int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile)
|
||||
}
|
||||
}
|
||||
|
||||
void win32_aio_detach_aio_context(QEMUWin32AIOState *aio,
|
||||
AioContext *old_context)
|
||||
{
|
||||
aio_set_event_notifier(old_context, &aio->e, NULL);
|
||||
aio->is_aio_context_attached = false;
|
||||
}
|
||||
|
||||
void win32_aio_attach_aio_context(QEMUWin32AIOState *aio,
|
||||
AioContext *new_context)
|
||||
{
|
||||
aio->is_aio_context_attached = true;
|
||||
aio_set_event_notifier(new_context, &aio->e, win32_aio_completion_cb);
|
||||
}
|
||||
|
||||
QEMUWin32AIOState *win32_aio_init(void)
|
||||
{
|
||||
QEMUWin32AIOState *s;
|
||||
@@ -209,6 +194,8 @@ QEMUWin32AIOState *win32_aio_init(void)
|
||||
goto out_close_efd;
|
||||
}
|
||||
|
||||
qemu_aio_set_event_notifier(&s->e, win32_aio_completion_cb);
|
||||
|
||||
return s;
|
||||
|
||||
out_close_efd:
|
||||
@@ -217,11 +204,3 @@ out_free_state:
|
||||
g_free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void win32_aio_cleanup(QEMUWin32AIOState *aio)
|
||||
{
|
||||
assert(!aio->is_aio_context_attached);
|
||||
CloseHandle(aio->hIOCP);
|
||||
event_notifier_cleanup(&aio->e);
|
||||
g_free(aio);
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@ static void nbd_accept(void *opaque)
|
||||
|
||||
int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
|
||||
if (fd >= 0 && !nbd_client_new(NULL, fd, nbd_client_put)) {
|
||||
shutdown(fd, 2);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
@@ -91,6 +92,10 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
||||
return;
|
||||
}
|
||||
if (!bdrv_is_inserted(bs)) {
|
||||
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!has_writable) {
|
||||
writable = false;
|
||||
|
124
blockdev.c
124
blockdev.c
@@ -34,6 +34,7 @@
|
||||
#include "hw/block/block.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
@@ -287,25 +288,6 @@ static int parse_block_error_action(const char *buf, bool is_read, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static inline int parse_enum_option(const char *lookup[], const char *buf,
|
||||
int max, int def, Error **errp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!buf) {
|
||||
return def;
|
||||
}
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
if (!strcmp(buf, lookup[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
error_setg(errp, "invalid parameter value: %s", buf);
|
||||
return def;
|
||||
}
|
||||
|
||||
static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
|
||||
{
|
||||
if (throttle_conflicting(cfg)) {
|
||||
@@ -342,7 +324,6 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
QemuOpts *opts;
|
||||
const char *id;
|
||||
bool has_driver_specific_opts;
|
||||
BlockdevDetectZeroesOptions detect_zeroes;
|
||||
BlockDriver *drv = NULL;
|
||||
|
||||
/* Check common options by copying from bs_opts to opts, all other options
|
||||
@@ -471,35 +452,18 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
}
|
||||
}
|
||||
|
||||
detect_zeroes =
|
||||
parse_enum_option(BlockdevDetectZeroesOptions_lookup,
|
||||
qemu_opt_get(opts, "detect-zeroes"),
|
||||
BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
|
||||
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
|
||||
&error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
goto early_err;
|
||||
}
|
||||
|
||||
if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
|
||||
!(bdrv_flags & BDRV_O_UNMAP)) {
|
||||
error_setg(errp, "setting detect-zeroes to unmap is not allowed "
|
||||
"without setting discard operation to unmap");
|
||||
if (bdrv_find_node(qemu_opts_id(opts))) {
|
||||
error_setg(errp, "device id=%s is conflicting with a node-name",
|
||||
qemu_opts_id(opts));
|
||||
goto early_err;
|
||||
}
|
||||
|
||||
/* init */
|
||||
dinfo = g_malloc0(sizeof(*dinfo));
|
||||
dinfo->id = g_strdup(qemu_opts_id(opts));
|
||||
dinfo->bdrv = bdrv_new(dinfo->id, &error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
goto bdrv_new_err;
|
||||
}
|
||||
dinfo->bdrv = bdrv_new(dinfo->id);
|
||||
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
||||
dinfo->bdrv->read_only = ro;
|
||||
dinfo->bdrv->detect_zeroes = detect_zeroes;
|
||||
dinfo->refcount = 1;
|
||||
if (serial != NULL) {
|
||||
dinfo->serial = g_strdup(serial);
|
||||
@@ -559,9 +523,8 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
|
||||
err:
|
||||
bdrv_unref(dinfo->bdrv);
|
||||
QTAILQ_REMOVE(&drives, dinfo, next);
|
||||
bdrv_new_err:
|
||||
g_free(dinfo->id);
|
||||
QTAILQ_REMOVE(&drives, dinfo, next);
|
||||
g_free(dinfo);
|
||||
early_err:
|
||||
qemu_opts_del(opts);
|
||||
@@ -730,7 +693,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
&error_abort);
|
||||
qemu_opts_absorb_qdict(legacy_opts, bs_opts, &local_err);
|
||||
if (local_err) {
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
goto fail;
|
||||
}
|
||||
@@ -943,7 +906,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
bs_opts = NULL;
|
||||
if (dinfo == NULL) {
|
||||
if (local_err) {
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
}
|
||||
goto fail;
|
||||
@@ -1156,7 +1119,6 @@ typedef struct InternalSnapshotState {
|
||||
static void internal_snapshot_prepare(BlkTransactionState *common,
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
const char *device;
|
||||
const char *name;
|
||||
BlockDriverState *bs;
|
||||
@@ -1205,10 +1167,8 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
|
||||
}
|
||||
|
||||
/* check whether a snapshot with name exist */
|
||||
ret = bdrv_snapshot_find_by_id_and_name(bs, NULL, name, &old_sn,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = bdrv_snapshot_find_by_id_and_name(bs, NULL, name, &old_sn, errp);
|
||||
if (error_is_set(errp)) {
|
||||
return;
|
||||
} else if (ret) {
|
||||
error_setg(errp,
|
||||
@@ -1336,8 +1296,8 @@ static void external_snapshot_prepare(BlkTransactionState *common,
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(state->old_bs,
|
||||
BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) {
|
||||
if (bdrv_in_use(state->old_bs)) {
|
||||
error_set(errp, QERR_DEVICE_IN_USE, device);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1559,20 +1519,19 @@ exit:
|
||||
|
||||
static void eject_device(BlockDriverState *bs, int force, Error **errp)
|
||||
{
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
|
||||
if (bdrv_in_use(bs)) {
|
||||
error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
|
||||
return;
|
||||
}
|
||||
if (!bdrv_dev_has_removable_media(bs)) {
|
||||
error_setg(errp, "Device '%s' is not removable",
|
||||
bdrv_get_device_name(bs));
|
||||
error_set(errp, QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
|
||||
bdrv_dev_eject_request(bs, force);
|
||||
if (!force) {
|
||||
error_setg(errp, "Device '%s' is locked",
|
||||
bdrv_get_device_name(bs));
|
||||
error_set(errp, QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1703,7 +1662,6 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
|
||||
{
|
||||
ThrottleConfig cfg;
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
|
||||
bs = bdrv_find(device);
|
||||
if (!bs) {
|
||||
@@ -1747,9 +1705,6 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
if (!bs->io_limits_enabled && throttle_enabled(&cfg)) {
|
||||
bdrv_io_limits_enable(bs);
|
||||
} else if (bs->io_limits_enabled && !throttle_enabled(&cfg)) {
|
||||
@@ -1759,24 +1714,20 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
|
||||
if (bs->io_limits_enabled) {
|
||||
bdrv_set_io_limits(bs, &cfg);
|
||||
}
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
const char *id = qdict_get_str(qdict, "id");
|
||||
BlockDriverState *bs;
|
||||
Error *local_err = NULL;
|
||||
|
||||
bs = bdrv_find(id);
|
||||
if (!bs) {
|
||||
error_report("Device '%s' not found", id);
|
||||
qerror_report(QERR_DEVICE_NOT_FOUND, id);
|
||||
return -1;
|
||||
}
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
if (bdrv_in_use(bs)) {
|
||||
qerror_report(QERR_DEVICE_IN_USE, id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1897,10 +1848,6 @@ void qmp_block_stream(const char *device, bool has_base,
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_STREAM, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (base) {
|
||||
base_bs = bdrv_find_backing_image(bs, base);
|
||||
if (base_bs == NULL) {
|
||||
@@ -1920,7 +1867,8 @@ void qmp_block_stream(const char *device, bool has_base,
|
||||
}
|
||||
|
||||
void qmp_block_commit(const char *device,
|
||||
bool has_base, const char *base, const char *top,
|
||||
bool has_base, const char *base,
|
||||
bool has_top, const char *top,
|
||||
bool has_speed, int64_t speed,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -1939,20 +1887,21 @@ void qmp_block_commit(const char *device,
|
||||
/* drain all i/o before commits */
|
||||
bdrv_drain_all();
|
||||
|
||||
/* Important Note:
|
||||
* libvirt relies on the DeviceNotFound error class in order to probe for
|
||||
* live commit feature versions; for this to work, we must make sure to
|
||||
* perform the device lookup before any generic errors that may occur in a
|
||||
* scenario in which all optional arguments are omitted. */
|
||||
bs = bdrv_find(device);
|
||||
if (!bs) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* default top_bs is the active layer */
|
||||
top_bs = bs;
|
||||
|
||||
if (top) {
|
||||
if (has_top && top) {
|
||||
if (strcmp(bs->filename, top) != 0) {
|
||||
top_bs = bdrv_find_backing_image(bs, top);
|
||||
}
|
||||
@@ -1974,6 +1923,12 @@ void qmp_block_commit(const char *device,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do not allow attempts to commit an image into itself */
|
||||
if (top_bs == base_bs) {
|
||||
error_setg(errp, "cannot commit an image into itself");
|
||||
return;
|
||||
}
|
||||
|
||||
if (top_bs == bs) {
|
||||
commit_active_start(bs, base_bs, speed, on_error, block_job_cb,
|
||||
bs, &local_err);
|
||||
@@ -2040,7 +1995,8 @@ void qmp_drive_backup(const char *device, const char *target,
|
||||
}
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
|
||||
if (bdrv_in_use(bs)) {
|
||||
error_set(errp, QERR_DEVICE_IN_USE, device);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2173,7 +2129,8 @@ void qmp_drive_mirror(const char *device, const char *target,
|
||||
}
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) {
|
||||
if (bdrv_in_use(bs)) {
|
||||
error_set(errp, QERR_DEVICE_IN_USE, device);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2278,8 +2235,7 @@ void qmp_block_job_cancel(const char *device,
|
||||
return;
|
||||
}
|
||||
if (job->paused && !force) {
|
||||
error_setg(errp, "The block job for device '%s' is currently paused",
|
||||
device);
|
||||
error_set(errp, QERR_BLOCK_JOB_PAUSED, device);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2509,10 +2465,6 @@ QemuOptsList qemu_common_drive_opts = {
|
||||
.name = "copy-on-read",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "copy read data from backing file into image file",
|
||||
},{
|
||||
.name = "detect-zeroes",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "try to optimize zero writes (off, on, unmap)",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
|
30
blockjob.c
30
blockjob.c
@@ -41,16 +41,14 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
|
||||
{
|
||||
BlockJob *job;
|
||||
|
||||
if (bs->job) {
|
||||
if (bs->job || bdrv_in_use(bs)) {
|
||||
error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
|
||||
return NULL;
|
||||
}
|
||||
bdrv_ref(bs);
|
||||
job = g_malloc0(driver->instance_size);
|
||||
error_setg(&job->blocker, "block device is in use by block job: %s",
|
||||
BlockJobType_lookup[driver->job_type]);
|
||||
bdrv_op_block_all(bs, job->blocker);
|
||||
bdrv_set_in_use(bs, 1);
|
||||
|
||||
job = g_malloc0(driver->instance_size);
|
||||
job->driver = driver;
|
||||
job->bs = bs;
|
||||
job->cb = cb;
|
||||
@@ -65,9 +63,8 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
|
||||
block_job_set_speed(job, speed, &local_err);
|
||||
if (local_err) {
|
||||
bs->job = NULL;
|
||||
bdrv_op_unblock_all(bs, job->blocker);
|
||||
error_free(job->blocker);
|
||||
g_free(job);
|
||||
bdrv_set_in_use(bs, 0);
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
@@ -82,9 +79,8 @@ void block_job_completed(BlockJob *job, int ret)
|
||||
assert(bs->job == job);
|
||||
job->cb(job->opaque, ret);
|
||||
bs->job = NULL;
|
||||
bdrv_op_unblock_all(bs, job->blocker);
|
||||
error_free(job->blocker);
|
||||
g_free(job);
|
||||
bdrv_set_in_use(bs, 0);
|
||||
}
|
||||
|
||||
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
||||
@@ -92,7 +88,7 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!job->driver->set_speed) {
|
||||
error_set(errp, QERR_UNSUPPORTED);
|
||||
error_set(errp, QERR_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
job->driver->set_speed(job, speed, &local_err);
|
||||
@@ -210,6 +206,20 @@ void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns)
|
||||
job->busy = true;
|
||||
}
|
||||
|
||||
void block_job_yield(BlockJob *job)
|
||||
{
|
||||
assert(job->busy);
|
||||
|
||||
/* Check cancellation *before* setting busy = false, too! */
|
||||
if (block_job_is_cancelled(job)) {
|
||||
return;
|
||||
}
|
||||
|
||||
job->busy = false;
|
||||
qemu_coroutine_yield();
|
||||
job->busy = true;
|
||||
}
|
||||
|
||||
BlockJobInfo *block_job_query(BlockJob *job)
|
||||
{
|
||||
BlockJobInfo *info = g_new0(BlockJobInfo, 1);
|
||||
|
@@ -43,7 +43,7 @@ unsigned long reserved_va;
|
||||
#endif
|
||||
|
||||
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
|
||||
const char *qemu_uname_release;
|
||||
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
|
||||
extern char **environ;
|
||||
enum BSDType bsd_type;
|
||||
|
||||
@@ -1003,8 +1003,10 @@ int main(int argc, char **argv)
|
||||
cpu->opaque = ts;
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
cpu_x86_set_cpl(env, 3);
|
||||
|
||||
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
|
||||
env->hflags |= HF_PE_MASK | HF_CPL_MASK;
|
||||
env->hflags |= HF_PE_MASK;
|
||||
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
|
||||
env->cr[4] |= CR4_OSFXSR_MASK;
|
||||
env->hflags |= HF_OSFXSR_MASK;
|
||||
|
@@ -5,7 +5,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
|
||||
#undef DEBUG_REMAP
|
||||
#ifdef DEBUG_REMAP
|
||||
|
163
configure
vendored
163
configure
vendored
@@ -2,28 +2,26 @@
|
||||
#
|
||||
# qemu configure script (c) 2003 Fabrice Bellard
|
||||
#
|
||||
|
||||
# Temporary directory used for files created while
|
||||
# configure runs. Since it is in the build directory
|
||||
# we can safely blow away any previous version of it
|
||||
# (and we need not jump through hoops to try to delete
|
||||
# it when configure exits.)
|
||||
TMPDIR1="config-temp"
|
||||
rm -rf "${TMPDIR1}"
|
||||
mkdir -p "${TMPDIR1}"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: failed to create temporary directory"
|
||||
exit 1
|
||||
# set temporary file name
|
||||
if test ! -z "$TMPDIR" ; then
|
||||
TMPDIR1="${TMPDIR}"
|
||||
elif test ! -z "$TEMPDIR" ; then
|
||||
TMPDIR1="${TEMPDIR}"
|
||||
else
|
||||
TMPDIR1="/tmp"
|
||||
fi
|
||||
|
||||
TMPB="qemu-conf"
|
||||
TMPC="${TMPDIR1}/${TMPB}.c"
|
||||
TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
|
||||
TMPB="qemu-conf-${RANDOM}-$$-${RANDOM}"
|
||||
TMPO="${TMPDIR1}/${TMPB}.o"
|
||||
TMPCXX="${TMPDIR1}/${TMPB}.cxx"
|
||||
TMPL="${TMPDIR1}/${TMPB}.lo"
|
||||
TMPA="${TMPDIR1}/lib${TMPB}.la"
|
||||
TMPE="${TMPDIR1}/${TMPB}.exe"
|
||||
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe"
|
||||
|
||||
# NB: do not call "exit" in the trap handler; this is buggy with some shells;
|
||||
# see <1285349658-3122-1-git-send-email-loic.minier@linaro.org>
|
||||
trap "rm -f $TMPC $TMPO $TMPCXX $TMPE" EXIT INT QUIT TERM
|
||||
rm -f config.log
|
||||
|
||||
# Print a helpful header at the top of config.log
|
||||
@@ -182,10 +180,6 @@ path_of() {
|
||||
return 1
|
||||
}
|
||||
|
||||
have_backend () {
|
||||
echo "$trace_backends" | grep "$1" >/dev/null
|
||||
}
|
||||
|
||||
# default parameters
|
||||
source_path=`dirname "$0"`
|
||||
cpu=""
|
||||
@@ -291,13 +285,14 @@ softmmu="yes"
|
||||
linux_user="no"
|
||||
bsd_user="no"
|
||||
guest_base="yes"
|
||||
uname_release=""
|
||||
aix="no"
|
||||
blobs="yes"
|
||||
pkgversion=""
|
||||
pie=""
|
||||
zero_malloc=""
|
||||
qom_cast_debug="yes"
|
||||
trace_backends="nop"
|
||||
trace_backend="nop"
|
||||
trace_file="trace"
|
||||
spice=""
|
||||
rbd=""
|
||||
@@ -323,7 +318,7 @@ glusterfs_discard="no"
|
||||
glusterfs_zerofill="no"
|
||||
virtio_blk_data_plane=""
|
||||
gtk=""
|
||||
gtkabi=""
|
||||
gtkabi="2.0"
|
||||
vte=""
|
||||
tpm="no"
|
||||
libssh2=""
|
||||
@@ -409,14 +404,6 @@ fi
|
||||
# make source path absolute
|
||||
source_path=`cd "$source_path"; pwd`
|
||||
|
||||
# running configure in the source tree?
|
||||
# we know that's the case if configure is there.
|
||||
if test -f "./configure"; then
|
||||
pwd_is_source_path="y"
|
||||
else
|
||||
pwd_is_source_path="n"
|
||||
fi
|
||||
|
||||
check_define() {
|
||||
cat > $TMPC <<EOF
|
||||
#if !defined($1)
|
||||
@@ -757,10 +744,7 @@ for opt do
|
||||
;;
|
||||
--target-list=*) target_list="$optarg"
|
||||
;;
|
||||
--enable-trace-backends=*) trace_backends="$optarg"
|
||||
;;
|
||||
# XXX: backwards compatibility
|
||||
--enable-trace-backend=*) trace_backends="$optarg"
|
||||
--enable-trace-backend=*) trace_backend="$optarg"
|
||||
;;
|
||||
--with-trace-file=*) trace_file="$optarg"
|
||||
;;
|
||||
@@ -961,6 +945,8 @@ for opt do
|
||||
;;
|
||||
--disable-pie) pie="no"
|
||||
;;
|
||||
--enable-uname-release=*) uname_release="$optarg"
|
||||
;;
|
||||
--enable-werror) werror="yes"
|
||||
;;
|
||||
--disable-werror) werror="no"
|
||||
@@ -1101,10 +1087,7 @@ for opt do
|
||||
;;
|
||||
--enable-quorum) quorum="yes"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: unknown option $opt"
|
||||
echo "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
*) echo "ERROR: unknown option $opt"; show_help="yes"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
@@ -1146,11 +1129,11 @@ case "$cpu" in
|
||||
CPU_CFLAGS="-m64 -mcpu=ultrasparc"
|
||||
;;
|
||||
s390)
|
||||
CPU_CFLAGS="-m31"
|
||||
CPU_CFLAGS="-m31 -march=z990"
|
||||
LDFLAGS="-m31 $LDFLAGS"
|
||||
;;
|
||||
s390x)
|
||||
CPU_CFLAGS="-m64"
|
||||
CPU_CFLAGS="-m64 -march=z990"
|
||||
LDFLAGS="-m64 $LDFLAGS"
|
||||
;;
|
||||
i386)
|
||||
@@ -1234,8 +1217,8 @@ Advanced options (experts only):
|
||||
--enable-modules enable modules support
|
||||
--enable-debug-tcg enable TCG debugging
|
||||
--disable-debug-tcg disable TCG debugging (default)
|
||||
--enable-debug-info enable debugging information (default)
|
||||
--disable-debug-info disable debugging information
|
||||
--enable-debug-info enable debugging information (default)
|
||||
--disable-debug-info disable debugging information
|
||||
--enable-debug enable common debug build options
|
||||
--enable-sparse enable sparse checker
|
||||
--disable-sparse disable sparse checker (default)
|
||||
@@ -1247,7 +1230,6 @@ Advanced options (experts only):
|
||||
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
|
||||
--disable-gtk disable gtk UI
|
||||
--enable-gtk enable gtk UI
|
||||
--with-gtkabi select preferred GTK ABI 2.0 or 3.0
|
||||
--disable-virtfs disable VirtFS
|
||||
--enable-virtfs enable VirtFS
|
||||
--disable-vnc disable VNC
|
||||
@@ -1309,6 +1291,7 @@ Advanced options (experts only):
|
||||
--fmod-lib path to FMOD library
|
||||
--fmod-inc path to FMOD includes
|
||||
--oss-lib path to OSS library
|
||||
--enable-uname-release=R Return R for uname -r in usermode emulation
|
||||
--cpu=CPU Build for host CPU [$cpu]
|
||||
--disable-uuid disable uuid support
|
||||
--enable-uuid enable uuid support
|
||||
@@ -1327,7 +1310,7 @@ Advanced options (experts only):
|
||||
--disable-docs disable documentation build
|
||||
--disable-vhost-net disable vhost-net acceleration support
|
||||
--enable-vhost-net enable vhost-net acceleration support
|
||||
--enable-trace-backends=B Set trace backend
|
||||
--enable-trace-backend=B Set trace backend
|
||||
Available backends: $($python $source_path/scripts/tracetool.py --list-backends)
|
||||
--with-trace-file=NAME Full PATH,NAME of file to store traces
|
||||
Default:trace-<pid>
|
||||
@@ -1370,7 +1353,7 @@ Advanced options (experts only):
|
||||
|
||||
NOTE: The object files are built at the place where configure is launched
|
||||
EOF
|
||||
exit 0
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Now we have handled --enable-tcg-interpreter and know we're not just
|
||||
@@ -1979,18 +1962,6 @@ fi
|
||||
##########################################
|
||||
# GTK probe
|
||||
|
||||
if test "$gtkabi" = ""; then
|
||||
# The GTK ABI was not specified explicitly, so try whether 2.0 is available.
|
||||
# Use 3.0 as a fallback if that is available.
|
||||
if $pkg_config --exists "gtk+-2.0 >= 2.18.0"; then
|
||||
gtkabi=2.0
|
||||
elif $pkg_config --exists "gtk+-3.0 >= 3.0.0"; then
|
||||
gtkabi=3.0
|
||||
else
|
||||
gtkabi=2.0
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$gtk" != "no"; then
|
||||
gtkpackage="gtk+-$gtkabi"
|
||||
if test "$gtkabi" = "3.0" ; then
|
||||
@@ -2004,7 +1975,7 @@ if test "$gtk" != "no"; then
|
||||
libs_softmmu="$gtk_libs $libs_softmmu"
|
||||
gtk="yes"
|
||||
elif test "$gtk" = "yes"; then
|
||||
feature_not_found "gtk" "Install gtk2 or gtk3 devel"
|
||||
feature_not_found "gtk" "Install gtk2 or gtk3 (requires --with-gtkabi=3.0 option to configure) devel"
|
||||
else
|
||||
gtk="no"
|
||||
fi
|
||||
@@ -2027,11 +1998,7 @@ if test "$vte" != "no"; then
|
||||
libs_softmmu="$vte_libs $libs_softmmu"
|
||||
vte="yes"
|
||||
elif test "$vte" = "yes"; then
|
||||
if test "$gtkabi" = "3.0"; then
|
||||
feature_not_found "vte" "Install libvte-2.90 devel"
|
||||
else
|
||||
feature_not_found "vte" "Install libvte devel"
|
||||
fi
|
||||
feature_not_found "vte" "Install libvte or libvte-2.90 (requires --with-gtkabi=3.0 option to configure) devel"
|
||||
else
|
||||
vte="no"
|
||||
fi
|
||||
@@ -2973,7 +2940,7 @@ EOF
|
||||
fdt=yes
|
||||
dtc_internal="yes"
|
||||
mkdir -p dtc
|
||||
if [ "$pwd_is_source_path" != "y" ] ; then
|
||||
if [ "$source_path" != `pwd` ] ; then
|
||||
symlink "$source_path/dtc/Makefile" "dtc/Makefile"
|
||||
symlink "$source_path/dtc/scripts" "dtc/scripts"
|
||||
fi
|
||||
@@ -3495,10 +3462,10 @@ if test "$smartcard_nss" != "no"; then
|
||||
#include <pk11pub.h>
|
||||
int main(void) { PK11_FreeSlot(0); return 0; }
|
||||
EOF
|
||||
# FIXME: do not include $glib_* in here
|
||||
nss_libs="$($pkg_config --libs nss 2>/dev/null) $glib_libs"
|
||||
nss_cflags="$($pkg_config --cflags nss 2>/dev/null) $glib_cflags"
|
||||
test_cflags="$nss_cflags"
|
||||
smartcard_includes="-I\$(SRC_PATH)/libcacard"
|
||||
libcacard_libs="$($pkg_config --libs nss 2>/dev/null) $glib_libs"
|
||||
libcacard_cflags="$($pkg_config --cflags nss 2>/dev/null) $glib_cflags"
|
||||
test_cflags="$libcacard_cflags"
|
||||
# The header files in nss < 3.13.3 have a bug which causes them to
|
||||
# emit a warning. If we're going to compile QEMU with -Werror, then
|
||||
# test that the headers don't have this bug. Otherwise we would pass
|
||||
@@ -3508,8 +3475,11 @@ EOF
|
||||
fi
|
||||
if test -n "$libtool" &&
|
||||
$pkg_config --atleast-version=3.12.8 nss && \
|
||||
compile_prog "$test_cflags" "$nss_libs"; then
|
||||
compile_prog "$test_cflags" "$libcacard_libs"; then
|
||||
smartcard_nss="yes"
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $libcacard_cflags"
|
||||
QEMU_INCLUDES="$QEMU_INCLUDES $smartcard_includes"
|
||||
libs_softmmu="$libcacard_libs $libs_softmmu"
|
||||
else
|
||||
if test "$smartcard_nss" = "yes"; then
|
||||
feature_not_found "nss"
|
||||
@@ -3673,15 +3643,15 @@ fi
|
||||
##########################################
|
||||
# check if trace backend exists
|
||||
|
||||
$python "$source_path/scripts/tracetool.py" "--backends=$trace_backends" --check-backends > /dev/null 2> /dev/null
|
||||
$python "$source_path/scripts/tracetool.py" "--backend=$trace_backend" --check-backend > /dev/null 2> /dev/null
|
||||
if test "$?" -ne 0 ; then
|
||||
error_exit "invalid trace backends" \
|
||||
"Please choose supported trace backends."
|
||||
error_exit "invalid trace backend" \
|
||||
"Please choose a supported trace backend."
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# For 'ust' backend, test if ust headers are present
|
||||
if have_backend "ust"; then
|
||||
if test "$trace_backend" = "ust"; then
|
||||
cat > $TMPC << EOF
|
||||
#include <lttng/tracepoint.h>
|
||||
int main(void) { return 0; }
|
||||
@@ -3707,7 +3677,7 @@ fi
|
||||
|
||||
##########################################
|
||||
# For 'dtrace' backend, test if 'dtrace' command is present
|
||||
if have_backend "dtrace"; then
|
||||
if test "$trace_backend" = "dtrace"; then
|
||||
if ! has 'dtrace' ; then
|
||||
error_exit "dtrace command is not found in PATH $PATH"
|
||||
fi
|
||||
@@ -4054,14 +4024,11 @@ fi
|
||||
if test "$pie" = "no" ; then
|
||||
textseg_addr=
|
||||
case "$cpu" in
|
||||
arm | i386 | ppc* | s390* | sparc* | x86_64 | x32)
|
||||
# ??? Rationale for choosing this address
|
||||
arm | hppa | i386 | m68k | ppc | ppc64 | s390* | sparc | sparc64 | x86_64 | x32)
|
||||
textseg_addr=0x60000000
|
||||
;;
|
||||
mips)
|
||||
# A 256M aligned address, high in the address space, with enough
|
||||
# room for the code_gen_buffer above it before the stack.
|
||||
textseg_addr=0x60000000
|
||||
textseg_addr=0x400000
|
||||
;;
|
||||
esac
|
||||
if [ -n "$textseg_addr" ]; then
|
||||
@@ -4128,6 +4095,7 @@ echo "sparse enabled $sparse"
|
||||
echo "strip binaries $strip_opt"
|
||||
echo "profiler $profiler"
|
||||
echo "static build $static"
|
||||
echo "-Werror enabled $werror"
|
||||
if test "$darwin" = "yes" ; then
|
||||
echo "Cocoa support $cocoa"
|
||||
fi
|
||||
@@ -4157,6 +4125,8 @@ echo "xen support $xen"
|
||||
echo "brlapi support $brlapi"
|
||||
echo "bluez support $bluez"
|
||||
echo "Documentation $docs"
|
||||
[ ! -z "$uname_release" ] && \
|
||||
echo "uname -r $uname_release"
|
||||
echo "GUEST_BASE $guest_base"
|
||||
echo "PIE $pie"
|
||||
echo "vde support $vde"
|
||||
@@ -4177,10 +4147,8 @@ echo "uuid support $uuid"
|
||||
echo "libcap-ng support $cap_ng"
|
||||
echo "vhost-net support $vhost_net"
|
||||
echo "vhost-scsi support $vhost_scsi"
|
||||
echo "Trace backends $trace_backends"
|
||||
if test "$trace_backend" = "simple"; then
|
||||
echo "Trace backend $trace_backend"
|
||||
echo "Trace output file $trace_file-<pid>"
|
||||
fi
|
||||
if test "$spice" = "yes"; then
|
||||
echo "spice support $spice ($spice_protocol_version/$spice_server_version)"
|
||||
else
|
||||
@@ -4379,7 +4347,6 @@ if test "$modules" = "yes"; then
|
||||
fi
|
||||
if test "$sdl" = "yes" ; then
|
||||
echo "CONFIG_SDL=y" >> $config_host_mak
|
||||
echo "CONFIG_SDLABI=$sdlabi" >> $config_host_mak
|
||||
echo "SDL_CFLAGS=$sdl_cflags" >> $config_host_mak
|
||||
fi
|
||||
if test "$cocoa" = "yes" ; then
|
||||
@@ -4463,7 +4430,6 @@ fi
|
||||
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
|
||||
if test "$gtk" = "yes" ; then
|
||||
echo "CONFIG_GTK=y" >> $config_host_mak
|
||||
echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
|
||||
echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
|
||||
fi
|
||||
if test "$vte" = "yes" ; then
|
||||
@@ -4526,8 +4492,8 @@ fi
|
||||
|
||||
if test "$smartcard_nss" = "yes" ; then
|
||||
echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak
|
||||
echo "NSS_LIBS=$nss_libs" >> $config_host_mak
|
||||
echo "NSS_CFLAGS=$nss_cflags" >> $config_host_mak
|
||||
echo "libcacard_libs=$libcacard_libs" >> $config_host_mak
|
||||
echo "libcacard_cflags=$libcacard_cflags" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$libusb" = "yes" ; then
|
||||
@@ -4573,6 +4539,8 @@ if [ "$bsd" = "yes" ] ; then
|
||||
echo "CONFIG_BSD=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
echo "CONFIG_UNAME_RELEASE=\"$uname_release\"" >> $config_host_mak
|
||||
|
||||
if test "$zero_malloc" = "yes" ; then
|
||||
echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak
|
||||
fi
|
||||
@@ -4671,35 +4639,43 @@ if test "$tpm" = "yes"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "TRACE_BACKENDS=$trace_backends" >> $config_host_mak
|
||||
if have_backend "nop"; then
|
||||
# use default implementation for tracing backend-specific routines
|
||||
trace_default=yes
|
||||
echo "TRACE_BACKEND=$trace_backend" >> $config_host_mak
|
||||
if test "$trace_backend" = "nop"; then
|
||||
echo "CONFIG_TRACE_NOP=y" >> $config_host_mak
|
||||
fi
|
||||
if have_backend "simple"; then
|
||||
if test "$trace_backend" = "simple"; then
|
||||
echo "CONFIG_TRACE_SIMPLE=y" >> $config_host_mak
|
||||
trace_default=no
|
||||
# Set the appropriate trace file.
|
||||
trace_file="\"$trace_file-\" FMT_pid"
|
||||
fi
|
||||
if have_backend "stderr"; then
|
||||
if test "$trace_backend" = "stderr"; then
|
||||
echo "CONFIG_TRACE_STDERR=y" >> $config_host_mak
|
||||
trace_default=no
|
||||
fi
|
||||
if have_backend "ust"; then
|
||||
if test "$trace_backend" = "ust"; then
|
||||
echo "CONFIG_TRACE_UST=y" >> $config_host_mak
|
||||
fi
|
||||
if have_backend "dtrace"; then
|
||||
if test "$trace_backend" = "dtrace"; then
|
||||
echo "CONFIG_TRACE_DTRACE=y" >> $config_host_mak
|
||||
if test "$trace_backend_stap" = "yes" ; then
|
||||
echo "CONFIG_TRACE_SYSTEMTAP=y" >> $config_host_mak
|
||||
fi
|
||||
fi
|
||||
if have_backend "ftrace"; then
|
||||
if test "$trace_backend" = "ftrace"; then
|
||||
if test "$linux" = "yes" ; then
|
||||
echo "CONFIG_TRACE_FTRACE=y" >> $config_host_mak
|
||||
trace_default=no
|
||||
else
|
||||
feature_not_found "ftrace(trace backend)" "ftrace requires Linux"
|
||||
fi
|
||||
fi
|
||||
echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
|
||||
if test "$trace_default" = "yes"; then
|
||||
echo "CONFIG_TRACE_DEFAULT=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$rdma" = "yes" ; then
|
||||
echo "CONFIG_RDMA=y" >> $config_host_mak
|
||||
@@ -5203,7 +5179,7 @@ do
|
||||
done
|
||||
mkdir -p $DIRS
|
||||
for f in $FILES ; do
|
||||
if [ -e "$source_path/$f" ] && [ "$pwd_is_source_path" != "y" ]; then
|
||||
if [ -e "$source_path/$f" ] && [ "$source_path" != `pwd` ]; then
|
||||
symlink "$source_path/$f" "$f"
|
||||
fi
|
||||
done
|
||||
@@ -5239,4 +5215,3 @@ printf " '%s'" "$0" "$@" >>config.status
|
||||
echo >>config.status
|
||||
chmod +x config.status
|
||||
|
||||
rm -r "$TMPDIR1"
|
||||
|
@@ -115,11 +115,14 @@ static inline GThread *create_thread(GThreadFunc func, gpointer data)
|
||||
|
||||
static void __attribute__((constructor)) coroutine_init(void)
|
||||
{
|
||||
#if !GLIB_CHECK_VERSION(2, 31, 0)
|
||||
if (!g_thread_supported()) {
|
||||
#if !GLIB_CHECK_VERSION(2, 31, 0)
|
||||
g_thread_init(NULL);
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "glib threading failed to initialize.\n");
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
init_coroutine_cond();
|
||||
}
|
||||
|
@@ -36,8 +36,17 @@ typedef struct
|
||||
static __thread CoroutineWin32 leader;
|
||||
static __thread Coroutine *current;
|
||||
|
||||
CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
|
||||
CoroutineAction action)
|
||||
/* This function is marked noinline to prevent GCC from inlining it
|
||||
* into coroutine_trampoline(). If we allow it to do that then it
|
||||
* hoists the code to get the address of the TLS variable "current"
|
||||
* out of the while() loop. This is an invalid transformation because
|
||||
* the SwitchToFiber() call may be called when running thread A but
|
||||
* return in thread B, and so we might be in a different thread
|
||||
* context each time round the loop.
|
||||
*/
|
||||
CoroutineAction __attribute__((noinline))
|
||||
qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
|
||||
CoroutineAction action)
|
||||
{
|
||||
CoroutineWin32 *from = DO_UPCAST(CoroutineWin32, base, from_);
|
||||
CoroutineWin32 *to = DO_UPCAST(CoroutineWin32, base, to_);
|
||||
|
23
cpu-exec.c
23
cpu-exec.c
@@ -335,18 +335,6 @@ int cpu_exec(CPUArchState *env)
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
#endif
|
||||
#if defined(TARGET_I386)
|
||||
if (interrupt_request & CPU_INTERRUPT_INIT) {
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0);
|
||||
do_cpu_init(x86_cpu);
|
||||
cpu->exception_index = EXCP_HALTED;
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
#else
|
||||
if (interrupt_request & CPU_INTERRUPT_RESET) {
|
||||
cpu_reset(cpu);
|
||||
}
|
||||
#endif
|
||||
#if defined(TARGET_I386)
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (interrupt_request & CPU_INTERRUPT_POLL) {
|
||||
@@ -354,7 +342,13 @@ int cpu_exec(CPUArchState *env)
|
||||
apic_poll_irq(x86_cpu->apic_state);
|
||||
}
|
||||
#endif
|
||||
if (interrupt_request & CPU_INTERRUPT_SIPI) {
|
||||
if (interrupt_request & CPU_INTERRUPT_INIT) {
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT,
|
||||
0);
|
||||
do_cpu_init(x86_cpu);
|
||||
cpu->exception_index = EXCP_HALTED;
|
||||
cpu_loop_exit(cpu);
|
||||
} else if (interrupt_request & CPU_INTERRUPT_SIPI) {
|
||||
do_cpu_sipi(x86_cpu);
|
||||
} else if (env->hflags2 & HF2_GIF_MASK) {
|
||||
if ((interrupt_request & CPU_INTERRUPT_SMI) &&
|
||||
@@ -411,6 +405,9 @@ int cpu_exec(CPUArchState *env)
|
||||
}
|
||||
}
|
||||
#elif defined(TARGET_PPC)
|
||||
if ((interrupt_request & CPU_INTERRUPT_RESET)) {
|
||||
cpu_reset(cpu);
|
||||
}
|
||||
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
||||
ppc_hw_interrupt(env);
|
||||
if (env->pending_interrupts == 0) {
|
||||
|
5
cpus.c
5
cpus.c
@@ -430,7 +430,8 @@ static const VMStateDescription vmstate_timers = {
|
||||
.name = "timer",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT64(cpu_ticks_offset, TimersState),
|
||||
VMSTATE_INT64(dummy, TimersState),
|
||||
VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
|
||||
@@ -1453,7 +1454,7 @@ void qmp_pmemsave(int64_t addr, int64_t size, const char *filename,
|
||||
l = sizeof(buf);
|
||||
if (l > size)
|
||||
l = size;
|
||||
cpu_physical_memory_read(addr, buf, l);
|
||||
cpu_physical_memory_rw(addr, buf, l, 0);
|
||||
if (fwrite(buf, 1, l, f) != l) {
|
||||
error_set(errp, QERR_IO_ERROR);
|
||||
goto exit;
|
||||
|
27
cputlb.c
27
cputlb.c
@@ -22,13 +22,11 @@
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/memory.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
|
||||
#include "exec/cputlb.h"
|
||||
|
||||
#include "exec/memory-internal.h"
|
||||
#include "exec/ram_addr.h"
|
||||
#include "tcg/tcg.h"
|
||||
|
||||
//#define DEBUG_TLB
|
||||
//#define DEBUG_TLB_CHECK
|
||||
@@ -332,21 +330,6 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
|
||||
return qemu_ram_addr_from_host_nofail(p);
|
||||
}
|
||||
|
||||
#define MMUSUFFIX _mmu
|
||||
|
||||
#define SHIFT 0
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 1
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 2
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 3
|
||||
#include "softmmu_template.h"
|
||||
#undef MMUSUFFIX
|
||||
|
||||
#define MMUSUFFIX _cmmu
|
||||
#undef GETPC_ADJ
|
||||
#define GETPC_ADJ 0
|
||||
@@ -355,13 +338,15 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
|
||||
#define SOFTMMU_CODE_ACCESS
|
||||
|
||||
#define SHIFT 0
|
||||
#include "softmmu_template.h"
|
||||
#include "exec/softmmu_template.h"
|
||||
|
||||
#define SHIFT 1
|
||||
#include "softmmu_template.h"
|
||||
#include "exec/softmmu_template.h"
|
||||
|
||||
#define SHIFT 2
|
||||
#include "softmmu_template.h"
|
||||
#include "exec/softmmu_template.h"
|
||||
|
||||
#define SHIFT 3
|
||||
#include "softmmu_template.h"
|
||||
#include "exec/softmmu_template.h"
|
||||
|
||||
#undef env
|
||||
|
@@ -1,4 +1,3 @@
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_SCLPCONSOLE=y
|
||||
CONFIG_S390_FLIC=y
|
||||
CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)
|
||||
CONFIG_S390_FLIC=$(CONFIG_KVM)
|
||||
|
@@ -1,7 +1,6 @@
|
||||
CONFIG_USB_TABLET_WACOM=y
|
||||
CONFIG_USB_STORAGE_BOT=y
|
||||
CONFIG_USB_STORAGE_UAS=y
|
||||
CONFIG_USB_STORAGE_MTP=y
|
||||
CONFIG_USB_SMARTCARD=y
|
||||
CONFIG_USB_AUDIO=y
|
||||
CONFIG_USB_SERIAL=y
|
||||
|
@@ -40,7 +40,7 @@ DriveInfo *add_init_drive(const char *optstr)
|
||||
return NULL;
|
||||
|
||||
mc = MACHINE_GET_CLASS(current_machine);
|
||||
dinfo = drive_init(opts, mc->block_default_type);
|
||||
dinfo = drive_init(opts, mc->qemu_machine->block_default_type);
|
||||
if (!dinfo) {
|
||||
qemu_opts_del(opts);
|
||||
return NULL;
|
||||
|
@@ -4,7 +4,7 @@ common-obj-$(CONFIG_ARM_DIS) += arm.o
|
||||
common-obj-$(CONFIG_ARM_A64_DIS) += arm-a64.o
|
||||
common-obj-$(CONFIG_ARM_A64_DIS) += libvixl/
|
||||
libvixldir = $(SRC_PATH)/disas/libvixl
|
||||
arm-a64.o-cflags := -I$(libvixldir)
|
||||
$(obj)/arm-a64.o: QEMU_CFLAGS := -I$(libvixldir) $(QEMU_CFLAGS)
|
||||
common-obj-$(CONFIG_CRIS_DIS) += cris.o
|
||||
common-obj-$(CONFIG_HPPA_DIS) += hppa.o
|
||||
common-obj-$(CONFIG_I386_DIS) += i386.o
|
||||
|
@@ -3,6 +3,6 @@ libvixl_OBJS = utils.o \
|
||||
a64/decoder-a64.o \
|
||||
a64/disasm-a64.o
|
||||
|
||||
$(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CFLAGS += -I$(SRC_PATH)/disas/libvixl
|
||||
$(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CFLAGS := -I$(SRC_PATH)/disas/libvixl $(QEMU_CFLAGS)
|
||||
|
||||
common-obj-$(CONFIG_ARM_A64_DIS) += $(libvixl_OBJS)
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -116,8 +116,6 @@ V_(ImmCmpBranch, 23, 5, SignedBits) \
|
||||
V_(ImmLLiteral, 23, 5, SignedBits) \
|
||||
V_(ImmException, 20, 5, Bits) \
|
||||
V_(ImmHint, 11, 5, Bits) \
|
||||
V_(ImmBarrierDomain, 11, 10, Bits) \
|
||||
V_(ImmBarrierType, 9, 8, Bits) \
|
||||
\
|
||||
/* System (MRS, MSR) */ \
|
||||
V_(ImmSystemRegister, 19, 5, Bits) \
|
||||
@@ -183,7 +181,7 @@ enum Condition {
|
||||
inline Condition InvertCondition(Condition cond) {
|
||||
// Conditions al and nv behave identically, as "always true". They can't be
|
||||
// inverted, because there is no "always false" condition.
|
||||
VIXL_ASSERT((cond != al) && (cond != nv));
|
||||
ASSERT((cond != al) && (cond != nv));
|
||||
return static_cast<Condition>(cond ^ 1);
|
||||
}
|
||||
|
||||
@@ -248,20 +246,6 @@ enum SystemHint {
|
||||
SEVL = 5
|
||||
};
|
||||
|
||||
enum BarrierDomain {
|
||||
OuterShareable = 0,
|
||||
NonShareable = 1,
|
||||
InnerShareable = 2,
|
||||
FullSystem = 3
|
||||
};
|
||||
|
||||
enum BarrierType {
|
||||
BarrierOther = 0,
|
||||
BarrierReads = 1,
|
||||
BarrierWrites = 2,
|
||||
BarrierAll = 3
|
||||
};
|
||||
|
||||
// System/special register names.
|
||||
// This information is not encoded as one field but as the concatenation of
|
||||
// multiple fields (Op0<0>, Op1, Crn, Crm, Op2).
|
||||
@@ -290,7 +274,7 @@ enum SystemRegister {
|
||||
//
|
||||
// The enumerations can be used like this:
|
||||
//
|
||||
// VIXL_ASSERT(instr->Mask(PCRelAddressingFMask) == PCRelAddressingFixed);
|
||||
// ASSERT(instr->Mask(PCRelAddressingFMask) == PCRelAddressingFixed);
|
||||
// switch(instr->Mask(PCRelAddressingMask)) {
|
||||
// case ADR: Format("adr 'Xd, 'AddrPCRelByte"); break;
|
||||
// case ADRP: Format("adrp 'Xd, 'AddrPCRelPage"); break;
|
||||
@@ -576,15 +560,6 @@ enum ExceptionOp {
|
||||
DCPS3 = ExceptionFixed | 0x00A00003
|
||||
};
|
||||
|
||||
enum MemBarrierOp {
|
||||
MemBarrierFixed = 0xD503309F,
|
||||
MemBarrierFMask = 0xFFFFF09F,
|
||||
MemBarrierMask = 0xFFFFF0FF,
|
||||
DSB = MemBarrierFixed | 0x00000000,
|
||||
DMB = MemBarrierFixed | 0x00000020,
|
||||
ISB = MemBarrierFixed | 0x00000040
|
||||
};
|
||||
|
||||
// Any load or store.
|
||||
enum LoadStoreAnyOp {
|
||||
LoadStoreAnyFMask = 0x0a000000,
|
||||
@@ -952,22 +927,17 @@ enum FPDataProcessing1SourceOp {
|
||||
FRINTN = FRINTN_s,
|
||||
FRINTP_s = FPDataProcessing1SourceFixed | 0x00048000,
|
||||
FRINTP_d = FPDataProcessing1SourceFixed | FP64 | 0x00048000,
|
||||
FRINTP = FRINTP_s,
|
||||
FRINTM_s = FPDataProcessing1SourceFixed | 0x00050000,
|
||||
FRINTM_d = FPDataProcessing1SourceFixed | FP64 | 0x00050000,
|
||||
FRINTM = FRINTM_s,
|
||||
FRINTZ_s = FPDataProcessing1SourceFixed | 0x00058000,
|
||||
FRINTZ_d = FPDataProcessing1SourceFixed | FP64 | 0x00058000,
|
||||
FRINTZ = FRINTZ_s,
|
||||
FRINTA_s = FPDataProcessing1SourceFixed | 0x00060000,
|
||||
FRINTA_d = FPDataProcessing1SourceFixed | FP64 | 0x00060000,
|
||||
FRINTA = FRINTA_s,
|
||||
FRINTX_s = FPDataProcessing1SourceFixed | 0x00070000,
|
||||
FRINTX_d = FPDataProcessing1SourceFixed | FP64 | 0x00070000,
|
||||
FRINTX = FRINTX_s,
|
||||
FRINTI_s = FPDataProcessing1SourceFixed | 0x00078000,
|
||||
FRINTI_d = FPDataProcessing1SourceFixed | FP64 | 0x00078000,
|
||||
FRINTI = FRINTI_s
|
||||
FRINTI_d = FPDataProcessing1SourceFixed | FP64 | 0x00078000
|
||||
};
|
||||
|
||||
// Floating point data processing 2 source.
|
||||
|
@@ -132,7 +132,7 @@ void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor,
|
||||
}
|
||||
// We reached the end of the list. The last element must be
|
||||
// registered_visitor.
|
||||
VIXL_ASSERT(*it == registered_visitor);
|
||||
ASSERT(*it == registered_visitor);
|
||||
visitors_.insert(it, new_visitor);
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ void Decoder::InsertVisitorAfter(DecoderVisitor* new_visitor,
|
||||
}
|
||||
// We reached the end of the list. The last element must be
|
||||
// registered_visitor.
|
||||
VIXL_ASSERT(*it == registered_visitor);
|
||||
ASSERT(*it == registered_visitor);
|
||||
visitors_.push_back(new_visitor);
|
||||
}
|
||||
|
||||
@@ -161,16 +161,16 @@ void Decoder::RemoveVisitor(DecoderVisitor* visitor) {
|
||||
|
||||
|
||||
void Decoder::DecodePCRelAddressing(Instruction* instr) {
|
||||
VIXL_ASSERT(instr->Bits(27, 24) == 0x0);
|
||||
ASSERT(instr->Bits(27, 24) == 0x0);
|
||||
// We know bit 28 is set, as <b28:b27> = 0 is filtered out at the top level
|
||||
// decode.
|
||||
VIXL_ASSERT(instr->Bit(28) == 0x1);
|
||||
ASSERT(instr->Bit(28) == 0x1);
|
||||
VisitPCRelAddressing(instr);
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeBranchSystemException(Instruction* instr) {
|
||||
VIXL_ASSERT((instr->Bits(27, 24) == 0x4) ||
|
||||
ASSERT((instr->Bits(27, 24) == 0x4) ||
|
||||
(instr->Bits(27, 24) == 0x5) ||
|
||||
(instr->Bits(27, 24) == 0x6) ||
|
||||
(instr->Bits(27, 24) == 0x7) );
|
||||
@@ -271,7 +271,7 @@ void Decoder::DecodeBranchSystemException(Instruction* instr) {
|
||||
|
||||
|
||||
void Decoder::DecodeLoadStore(Instruction* instr) {
|
||||
VIXL_ASSERT((instr->Bits(27, 24) == 0x8) ||
|
||||
ASSERT((instr->Bits(27, 24) == 0x8) ||
|
||||
(instr->Bits(27, 24) == 0x9) ||
|
||||
(instr->Bits(27, 24) == 0xC) ||
|
||||
(instr->Bits(27, 24) == 0xD) );
|
||||
@@ -390,7 +390,7 @@ void Decoder::DecodeLoadStore(Instruction* instr) {
|
||||
|
||||
|
||||
void Decoder::DecodeLogical(Instruction* instr) {
|
||||
VIXL_ASSERT(instr->Bits(27, 24) == 0x2);
|
||||
ASSERT(instr->Bits(27, 24) == 0x2);
|
||||
|
||||
if (instr->Mask(0x80400000) == 0x00400000) {
|
||||
VisitUnallocated(instr);
|
||||
@@ -409,7 +409,7 @@ void Decoder::DecodeLogical(Instruction* instr) {
|
||||
|
||||
|
||||
void Decoder::DecodeBitfieldExtract(Instruction* instr) {
|
||||
VIXL_ASSERT(instr->Bits(27, 24) == 0x3);
|
||||
ASSERT(instr->Bits(27, 24) == 0x3);
|
||||
|
||||
if ((instr->Mask(0x80400000) == 0x80000000) ||
|
||||
(instr->Mask(0x80400000) == 0x00400000) ||
|
||||
@@ -434,7 +434,7 @@ void Decoder::DecodeBitfieldExtract(Instruction* instr) {
|
||||
|
||||
|
||||
void Decoder::DecodeAddSubImmediate(Instruction* instr) {
|
||||
VIXL_ASSERT(instr->Bits(27, 24) == 0x1);
|
||||
ASSERT(instr->Bits(27, 24) == 0x1);
|
||||
if (instr->Bit(23) == 1) {
|
||||
VisitUnallocated(instr);
|
||||
} else {
|
||||
@@ -444,8 +444,8 @@ void Decoder::DecodeAddSubImmediate(Instruction* instr) {
|
||||
|
||||
|
||||
void Decoder::DecodeDataProcessing(Instruction* instr) {
|
||||
VIXL_ASSERT((instr->Bits(27, 24) == 0xA) ||
|
||||
(instr->Bits(27, 24) == 0xB));
|
||||
ASSERT((instr->Bits(27, 24) == 0xA) ||
|
||||
(instr->Bits(27, 24) == 0xB) );
|
||||
|
||||
if (instr->Bit(24) == 0) {
|
||||
if (instr->Bit(28) == 0) {
|
||||
@@ -559,8 +559,8 @@ void Decoder::DecodeDataProcessing(Instruction* instr) {
|
||||
|
||||
|
||||
void Decoder::DecodeFP(Instruction* instr) {
|
||||
VIXL_ASSERT((instr->Bits(27, 24) == 0xE) ||
|
||||
(instr->Bits(27, 24) == 0xF));
|
||||
ASSERT((instr->Bits(27, 24) == 0xE) ||
|
||||
(instr->Bits(27, 24) == 0xF) );
|
||||
|
||||
if (instr->Bit(28) == 0) {
|
||||
DecodeAdvSIMDDataProcessing(instr);
|
||||
@@ -665,14 +665,14 @@ void Decoder::DecodeFP(Instruction* instr) {
|
||||
VisitFPConditionalSelect(instr);
|
||||
break;
|
||||
}
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Bit 30 == 1 has been handled earlier.
|
||||
VIXL_ASSERT(instr->Bit(30) == 0);
|
||||
ASSERT(instr->Bit(30) == 0);
|
||||
if (instr->Mask(0xA0800000) != 0) {
|
||||
VisitUnallocated(instr);
|
||||
} else {
|
||||
@@ -687,21 +687,21 @@ void Decoder::DecodeFP(Instruction* instr) {
|
||||
|
||||
void Decoder::DecodeAdvSIMDLoadStore(Instruction* instr) {
|
||||
// TODO: Implement Advanced SIMD load/store instruction decode.
|
||||
VIXL_ASSERT(instr->Bits(29, 25) == 0x6);
|
||||
ASSERT(instr->Bits(29, 25) == 0x6);
|
||||
VisitUnimplemented(instr);
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeAdvSIMDDataProcessing(Instruction* instr) {
|
||||
// TODO: Implement Advanced SIMD data processing instruction decode.
|
||||
VIXL_ASSERT(instr->Bits(27, 25) == 0x7);
|
||||
ASSERT(instr->Bits(27, 25) == 0x7);
|
||||
VisitUnimplemented(instr);
|
||||
}
|
||||
|
||||
|
||||
#define DEFINE_VISITOR_CALLERS(A) \
|
||||
void Decoder::Visit##A(Instruction *instr) { \
|
||||
VIXL_ASSERT(instr->Mask(A##FMask) == A##Fixed); \
|
||||
ASSERT(instr->Mask(A##FMask) == A##Fixed); \
|
||||
std::list<DecoderVisitor*>::iterator it; \
|
||||
for (it = visitors_.begin(); it != visitors_.end(); it++) { \
|
||||
(*it)->Visit##A(instr); \
|
||||
|
@@ -95,7 +95,7 @@ void Disassembler::VisitAddSubImmediate(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -142,7 +142,7 @@ void Disassembler::VisitAddSubShifted(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -180,7 +180,7 @@ void Disassembler::VisitAddSubExtended(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -215,7 +215,7 @@ void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -258,30 +258,30 @@ void Disassembler::VisitLogicalImmediate(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
|
||||
|
||||
bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
|
||||
VIXL_ASSERT((reg_size == kXRegSize) ||
|
||||
((reg_size == kWRegSize) && (value <= 0xffffffff)));
|
||||
ASSERT((reg_size == kXRegSize) ||
|
||||
((reg_size == kWRegSize) && (value <= 0xffffffff)));
|
||||
|
||||
// Test for movz: 16 bits set at positions 0, 16, 32 or 48.
|
||||
if (((value & UINT64_C(0xffffffffffff0000)) == 0) ||
|
||||
((value & UINT64_C(0xffffffff0000ffff)) == 0) ||
|
||||
((value & UINT64_C(0xffff0000ffffffff)) == 0) ||
|
||||
((value & UINT64_C(0x0000ffffffffffff)) == 0)) {
|
||||
if (((value & 0xffffffffffff0000ULL) == 0ULL) ||
|
||||
((value & 0xffffffff0000ffffULL) == 0ULL) ||
|
||||
((value & 0xffff0000ffffffffULL) == 0ULL) ||
|
||||
((value & 0x0000ffffffffffffULL) == 0ULL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48).
|
||||
if ((reg_size == kXRegSize) &&
|
||||
(((~value & UINT64_C(0xffffffffffff0000)) == 0) ||
|
||||
((~value & UINT64_C(0xffffffff0000ffff)) == 0) ||
|
||||
((~value & UINT64_C(0xffff0000ffffffff)) == 0) ||
|
||||
((~value & UINT64_C(0x0000ffffffffffff)) == 0))) {
|
||||
(((value & 0xffffffffffff0000ULL) == 0xffffffffffff0000ULL) ||
|
||||
((value & 0xffffffff0000ffffULL) == 0xffffffff0000ffffULL) ||
|
||||
((value & 0xffff0000ffffffffULL) == 0xffff0000ffffffffULL) ||
|
||||
((value & 0x0000ffffffffffffULL) == 0x0000ffffffffffffULL))) {
|
||||
return true;
|
||||
}
|
||||
if ((reg_size == kWRegSize) &&
|
||||
@@ -337,7 +337,7 @@ void Disassembler::VisitLogicalShifted(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
||||
Format(instr, mnemonic, form);
|
||||
@@ -353,7 +353,7 @@ void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
|
||||
case CCMN_x: mnemonic = "ccmn"; break;
|
||||
case CCMP_w:
|
||||
case CCMP_x: mnemonic = "ccmp"; break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -368,7 +368,7 @@ void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
|
||||
case CCMN_x_imm: mnemonic = "ccmn"; break;
|
||||
case CCMP_w_imm:
|
||||
case CCMP_x_imm: mnemonic = "ccmp"; break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -421,7 +421,7 @@ void Disassembler::VisitConditionalSelect(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -520,7 +520,7 @@ void Disassembler::VisitExtract(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -538,7 +538,7 @@ void Disassembler::VisitPCRelAddressing(Instruction* instr) {
|
||||
void Disassembler::VisitConditionalBranch(Instruction* instr) {
|
||||
switch (instr->Mask(ConditionalBranchMask)) {
|
||||
case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,7 +570,7 @@ void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
|
||||
switch (instr->Mask(UnconditionalBranchMask)) {
|
||||
case B: mnemonic = "b"; break;
|
||||
case BL: mnemonic = "bl"; break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -591,7 +591,7 @@ void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
|
||||
FORMAT(CLS, "cls");
|
||||
#undef FORMAT
|
||||
case REV32_x: mnemonic = "rev32"; break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -690,7 +690,7 @@ void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
|
||||
form = form_xxx;
|
||||
break;
|
||||
}
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -705,7 +705,7 @@ void Disassembler::VisitCompareBranch(Instruction* instr) {
|
||||
case CBZ_x: mnemonic = "cbz"; break;
|
||||
case CBNZ_w:
|
||||
case CBNZ_x: mnemonic = "cbnz"; break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -722,7 +722,7 @@ void Disassembler::VisitTestBranch(Instruction* instr) {
|
||||
switch (instr->Mask(TestBranchMask)) {
|
||||
case TBZ: mnemonic = "tbz"; break;
|
||||
case TBNZ: mnemonic = "tbnz"; break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -742,7 +742,7 @@ void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
|
||||
case MOVZ_x: mnemonic = "movz"; break;
|
||||
case MOVK_w:
|
||||
case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -981,7 +981,7 @@ void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
|
||||
switch (instr->Mask(FPConditionalSelectMask)) {
|
||||
case FCSEL_s:
|
||||
case FCSEL_d: mnemonic = "fcsel"; break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -1033,7 +1033,7 @@ void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
|
||||
FORMAT(FMINNM, "fminnm");
|
||||
FORMAT(FNMUL, "fnmul");
|
||||
#undef FORMAT
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -1052,7 +1052,7 @@ void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
|
||||
FORMAT(FNMADD, "fnmadd");
|
||||
FORMAT(FNMSUB, "fnmsub");
|
||||
#undef FORMAT
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -1065,7 +1065,7 @@ void Disassembler::VisitFPImmediate(Instruction* instr) {
|
||||
switch (instr->Mask(FPImmediateMask)) {
|
||||
case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
|
||||
case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -1082,14 +1082,6 @@ void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
|
||||
case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
|
||||
case FMOV_sw:
|
||||
case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
|
||||
case FCVTAS_ws:
|
||||
case FCVTAS_xs:
|
||||
case FCVTAS_wd:
|
||||
case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
|
||||
case FCVTAU_ws:
|
||||
case FCVTAU_xs:
|
||||
case FCVTAU_wd:
|
||||
case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
|
||||
case FCVTMS_ws:
|
||||
case FCVTMS_xs:
|
||||
case FCVTMS_wd:
|
||||
@@ -1149,7 +1141,7 @@ void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
|
||||
case UCVTF_sx_fixed:
|
||||
case UCVTF_dw_fixed:
|
||||
case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -1184,7 +1176,7 @@ void Disassembler::VisitSystem(Instruction* instr) {
|
||||
}
|
||||
}
|
||||
} else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
|
||||
VIXL_ASSERT(instr->Mask(SystemHintMask) == HINT);
|
||||
ASSERT(instr->Mask(SystemHintMask) == HINT);
|
||||
switch (instr->ImmHint()) {
|
||||
case NOP: {
|
||||
mnemonic = "nop";
|
||||
@@ -1192,24 +1184,6 @@ void Disassembler::VisitSystem(Instruction* instr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
|
||||
switch (instr->Mask(MemBarrierMask)) {
|
||||
case DMB: {
|
||||
mnemonic = "dmb";
|
||||
form = "'M";
|
||||
break;
|
||||
}
|
||||
case DSB: {
|
||||
mnemonic = "dsb";
|
||||
form = "'M";
|
||||
break;
|
||||
}
|
||||
case ISB: {
|
||||
mnemonic = "isb";
|
||||
form = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Format(instr, mnemonic, form);
|
||||
@@ -1252,7 +1226,7 @@ void Disassembler::ProcessOutput(Instruction* /*instr*/) {
|
||||
|
||||
void Disassembler::Format(Instruction* instr, const char* mnemonic,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(mnemonic != NULL);
|
||||
ASSERT(mnemonic != NULL);
|
||||
ResetOutput();
|
||||
Substitute(instr, mnemonic);
|
||||
if (format != NULL) {
|
||||
@@ -1294,9 +1268,8 @@ int Disassembler::SubstituteField(Instruction* instr, const char* format) {
|
||||
case 'A': return SubstitutePCRelAddressField(instr, format);
|
||||
case 'B': return SubstituteBranchTargetField(instr, format);
|
||||
case 'O': return SubstituteLSRegOffsetField(instr, format);
|
||||
case 'M': return SubstituteBarrierField(instr, format);
|
||||
default: {
|
||||
VIXL_UNREACHABLE();
|
||||
UNREACHABLE();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -1321,7 +1294,7 @@ int Disassembler::SubstituteRegisterField(Instruction* instr,
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
||||
// Increase field length for registers tagged as stack.
|
||||
@@ -1358,7 +1331,7 @@ int Disassembler::SubstituteRegisterField(Instruction* instr,
|
||||
|
||||
int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(format[0] == 'I');
|
||||
ASSERT(format[0] == 'I');
|
||||
|
||||
switch (format[1]) {
|
||||
case 'M': { // IMoveImm or IMoveLSL.
|
||||
@@ -1366,10 +1339,10 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||
uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
|
||||
AppendToOutput("#0x%" PRIx64, imm);
|
||||
} else {
|
||||
VIXL_ASSERT(format[5] == 'L');
|
||||
ASSERT(format[5] == 'L');
|
||||
AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
|
||||
if (instr->ShiftMoveWide() > 0) {
|
||||
AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
|
||||
AppendToOutput(", lsl #%" PRId64, 16 * instr->ShiftMoveWide());
|
||||
}
|
||||
}
|
||||
return 8;
|
||||
@@ -1411,14 +1384,14 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||
return 6;
|
||||
}
|
||||
case 'A': { // IAddSub.
|
||||
VIXL_ASSERT(instr->ShiftAddSub() <= 1);
|
||||
ASSERT(instr->ShiftAddSub() <= 1);
|
||||
int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
|
||||
AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
|
||||
return 7;
|
||||
}
|
||||
case 'F': { // IFPSingle, IFPDouble or IFPFBits.
|
||||
if (format[3] == 'F') { // IFPFbits.
|
||||
AppendToOutput("#%d", 64 - instr->FPScale());
|
||||
AppendToOutput("#%" PRId64, 64 - instr->FPScale());
|
||||
return 8;
|
||||
} else {
|
||||
AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
|
||||
@@ -1439,27 +1412,27 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||
return 5;
|
||||
}
|
||||
case 'P': { // IP - Conditional compare.
|
||||
AppendToOutput("#%d", instr->ImmCondCmp());
|
||||
AppendToOutput("#%" PRId64, instr->ImmCondCmp());
|
||||
return 2;
|
||||
}
|
||||
case 'B': { // Bitfields.
|
||||
return SubstituteBitfieldImmediateField(instr, format);
|
||||
}
|
||||
case 'E': { // IExtract.
|
||||
AppendToOutput("#%d", instr->ImmS());
|
||||
AppendToOutput("#%" PRId64, instr->ImmS());
|
||||
return 8;
|
||||
}
|
||||
case 'S': { // IS - Test and branch bit.
|
||||
AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
|
||||
instr->ImmTestBranchBit40());
|
||||
AppendToOutput("#%" PRId64, (instr->ImmTestBranchBit5() << 5) |
|
||||
instr->ImmTestBranchBit40());
|
||||
return 2;
|
||||
}
|
||||
case 'D': { // IDebug - HLT and BRK instructions.
|
||||
AppendToOutput("#0x%x", instr->ImmException());
|
||||
AppendToOutput("#0x%" PRIx64, instr->ImmException());
|
||||
return 6;
|
||||
}
|
||||
default: {
|
||||
VIXL_UNIMPLEMENTED();
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1468,7 +1441,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||
|
||||
int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B'));
|
||||
ASSERT((format[0] == 'I') && (format[1] == 'B'));
|
||||
unsigned r = instr->ImmR();
|
||||
unsigned s = instr->ImmS();
|
||||
|
||||
@@ -1482,19 +1455,19 @@ int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
|
||||
AppendToOutput("#%d", s + 1);
|
||||
return 5;
|
||||
} else {
|
||||
VIXL_ASSERT(format[3] == '-');
|
||||
ASSERT(format[3] == '-');
|
||||
AppendToOutput("#%d", s - r + 1);
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
case 'Z': { // IBZ-r.
|
||||
VIXL_ASSERT((format[3] == '-') && (format[4] == 'r'));
|
||||
ASSERT((format[3] == '-') && (format[4] == 'r'));
|
||||
unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize;
|
||||
AppendToOutput("#%d", reg_size - r);
|
||||
return 5;
|
||||
}
|
||||
default: {
|
||||
VIXL_UNREACHABLE();
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1503,7 +1476,7 @@ int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
|
||||
|
||||
int Disassembler::SubstituteLiteralField(Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);
|
||||
ASSERT(strncmp(format, "LValue", 6) == 0);
|
||||
USE(format);
|
||||
|
||||
switch (instr->Mask(LoadLiteralMask)) {
|
||||
@@ -1511,7 +1484,7 @@ int Disassembler::SubstituteLiteralField(Instruction* instr,
|
||||
case LDR_x_lit:
|
||||
case LDR_s_lit:
|
||||
case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
||||
return 6;
|
||||
@@ -1519,12 +1492,12 @@ int Disassembler::SubstituteLiteralField(Instruction* instr,
|
||||
|
||||
|
||||
int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
|
||||
VIXL_ASSERT(format[0] == 'H');
|
||||
VIXL_ASSERT(instr->ShiftDP() <= 0x3);
|
||||
ASSERT(format[0] == 'H');
|
||||
ASSERT(instr->ShiftDP() <= 0x3);
|
||||
|
||||
switch (format[1]) {
|
||||
case 'D': { // HDP.
|
||||
VIXL_ASSERT(instr->ShiftDP() != ROR);
|
||||
ASSERT(instr->ShiftDP() != ROR);
|
||||
} // Fall through.
|
||||
case 'L': { // HLo.
|
||||
if (instr->ImmDPShift() != 0) {
|
||||
@@ -1535,7 +1508,7 @@ int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
|
||||
return 3;
|
||||
}
|
||||
default:
|
||||
VIXL_UNIMPLEMENTED();
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1543,7 +1516,7 @@ int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
|
||||
|
||||
int Disassembler::SubstituteConditionField(Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(format[0] == 'C');
|
||||
ASSERT(format[0] == 'C');
|
||||
const char* condition_code[] = { "eq", "ne", "hs", "lo",
|
||||
"mi", "pl", "vs", "vc",
|
||||
"hi", "ls", "ge", "lt",
|
||||
@@ -1565,27 +1538,27 @@ int Disassembler::SubstituteConditionField(Instruction* instr,
|
||||
int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
|
||||
const char* format) {
|
||||
USE(format);
|
||||
VIXL_ASSERT(strncmp(format, "AddrPCRel", 9) == 0);
|
||||
ASSERT(strncmp(format, "AddrPCRel", 9) == 0);
|
||||
|
||||
int offset = instr->ImmPCRel();
|
||||
|
||||
// Only ADR (AddrPCRelByte) is supported.
|
||||
VIXL_ASSERT(strcmp(format, "AddrPCRelByte") == 0);
|
||||
ASSERT(strcmp(format, "AddrPCRelByte") == 0);
|
||||
|
||||
char sign = '+';
|
||||
if (offset < 0) {
|
||||
offset = -offset;
|
||||
sign = '-';
|
||||
}
|
||||
VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
|
||||
AppendToOutput("#%c0x%x (addr %p)", sign, offset, instr + offset);
|
||||
// TODO: Extend this to support printing the target address.
|
||||
AppendToOutput("#%c0x%x", sign, offset);
|
||||
return 13;
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteBranchTargetField(Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(strncmp(format, "BImm", 4) == 0);
|
||||
ASSERT(strncmp(format, "BImm", 4) == 0);
|
||||
|
||||
int64_t offset = 0;
|
||||
switch (format[5]) {
|
||||
@@ -1597,7 +1570,7 @@ int Disassembler::SubstituteBranchTargetField(Instruction* instr,
|
||||
case 'm': offset = instr->ImmCmpBranch(); break;
|
||||
// BImmTest - test and branch immediate.
|
||||
case 'e': offset = instr->ImmTestBranch(); break;
|
||||
default: VIXL_UNIMPLEMENTED();
|
||||
default: UNIMPLEMENTED();
|
||||
}
|
||||
offset <<= kInstructionSizeLog2;
|
||||
char sign = '+';
|
||||
@@ -1605,16 +1578,15 @@ int Disassembler::SubstituteBranchTargetField(Instruction* instr,
|
||||
offset = -offset;
|
||||
sign = '-';
|
||||
}
|
||||
VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
|
||||
AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, offset, instr + offset);
|
||||
AppendToOutput("#%c0x%" PRIx64, sign, offset);
|
||||
return 8;
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteExtendField(Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(strncmp(format, "Ext", 3) == 0);
|
||||
VIXL_ASSERT(instr->ExtendMode() <= 7);
|
||||
ASSERT(strncmp(format, "Ext", 3) == 0);
|
||||
ASSERT(instr->ExtendMode() <= 7);
|
||||
USE(format);
|
||||
|
||||
const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
|
||||
@@ -1626,12 +1598,12 @@ int Disassembler::SubstituteExtendField(Instruction* instr,
|
||||
(((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
|
||||
(instr->ExtendMode() == UXTX))) {
|
||||
if (instr->ImmExtendShift() > 0) {
|
||||
AppendToOutput(", lsl #%d", instr->ImmExtendShift());
|
||||
AppendToOutput(", lsl #%" PRId64, instr->ImmExtendShift());
|
||||
}
|
||||
} else {
|
||||
AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
|
||||
if (instr->ImmExtendShift() > 0) {
|
||||
AppendToOutput(" #%d", instr->ImmExtendShift());
|
||||
AppendToOutput(" #%" PRId64, instr->ImmExtendShift());
|
||||
}
|
||||
}
|
||||
return 3;
|
||||
@@ -1640,7 +1612,7 @@ int Disassembler::SubstituteExtendField(Instruction* instr,
|
||||
|
||||
int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0);
|
||||
ASSERT(strncmp(format, "Offsetreg", 9) == 0);
|
||||
const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
|
||||
"undefined", "undefined", "sxtw", "sxtx" };
|
||||
USE(format);
|
||||
@@ -1660,7 +1632,7 @@ int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
|
||||
if (!((ext == UXTX) && (shift == 0))) {
|
||||
AppendToOutput(", %s", extend_mode[ext]);
|
||||
if (shift != 0) {
|
||||
AppendToOutput(" #%d", instr->SizeLS());
|
||||
AppendToOutput(" #%" PRId64, instr->SizeLS());
|
||||
}
|
||||
}
|
||||
return 9;
|
||||
@@ -1669,7 +1641,7 @@ int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
|
||||
|
||||
int Disassembler::SubstitutePrefetchField(Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(format[0] == 'P');
|
||||
ASSERT(format[0] == 'P');
|
||||
USE(format);
|
||||
|
||||
int prefetch_mode = instr->PrefetchMode();
|
||||
@@ -1682,23 +1654,6 @@ int Disassembler::SubstitutePrefetchField(Instruction* instr,
|
||||
return 6;
|
||||
}
|
||||
|
||||
int Disassembler::SubstituteBarrierField(Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(format[0] == 'M');
|
||||
USE(format);
|
||||
|
||||
static const char* options[4][4] = {
|
||||
{ "sy (0b0000)", "oshld", "oshst", "osh" },
|
||||
{ "sy (0b0100)", "nshld", "nshst", "nsh" },
|
||||
{ "sy (0b1000)", "ishld", "ishst", "ish" },
|
||||
{ "sy (0b1100)", "ld", "st", "sy" }
|
||||
};
|
||||
int domain = instr->ImmBarrierDomain();
|
||||
int type = instr->ImmBarrierType();
|
||||
|
||||
AppendToOutput("%s", options[domain][type]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Disassembler::ResetOutput() {
|
||||
buffer_pos_ = 0;
|
||||
|
@@ -64,7 +64,6 @@ class Disassembler: public DecoderVisitor {
|
||||
int SubstituteBranchTargetField(Instruction* instr, const char* format);
|
||||
int SubstituteLSRegOffsetField(Instruction* instr, const char* format);
|
||||
int SubstitutePrefetchField(Instruction* instr, const char* format);
|
||||
int SubstituteBarrierField(Instruction* instr, const char* format);
|
||||
|
||||
inline bool RdIsZROrSP(Instruction* instr) const {
|
||||
return (instr->Rd() == kZeroRegCode);
|
||||
|
@@ -33,20 +33,20 @@ namespace vixl {
|
||||
static uint64_t RotateRight(uint64_t value,
|
||||
unsigned int rotate,
|
||||
unsigned int width) {
|
||||
VIXL_ASSERT(width <= 64);
|
||||
ASSERT(width <= 64);
|
||||
rotate &= 63;
|
||||
return ((value & ((UINT64_C(1) << rotate) - 1)) <<
|
||||
(width - rotate)) | (value >> rotate);
|
||||
return ((value & ((1UL << rotate) - 1UL)) << (width - rotate)) |
|
||||
(value >> rotate);
|
||||
}
|
||||
|
||||
|
||||
static uint64_t RepeatBitsAcrossReg(unsigned reg_size,
|
||||
uint64_t value,
|
||||
unsigned width) {
|
||||
VIXL_ASSERT((width == 2) || (width == 4) || (width == 8) || (width == 16) ||
|
||||
(width == 32));
|
||||
VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize));
|
||||
uint64_t result = value & ((UINT64_C(1) << width) - 1);
|
||||
ASSERT((width == 2) || (width == 4) || (width == 8) || (width == 16) ||
|
||||
(width == 32));
|
||||
ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize));
|
||||
uint64_t result = value & ((1UL << width) - 1UL);
|
||||
for (unsigned i = width; i < reg_size; i *= 2) {
|
||||
result |= (result << i);
|
||||
}
|
||||
@@ -84,7 +84,7 @@ uint64_t Instruction::ImmLogical() {
|
||||
if (imm_s == 0x3F) {
|
||||
return 0;
|
||||
}
|
||||
uint64_t bits = (UINT64_C(1) << (imm_s + 1)) - 1;
|
||||
uint64_t bits = (1UL << (imm_s + 1)) - 1;
|
||||
return RotateRight(bits, imm_r, 64);
|
||||
} else {
|
||||
if ((imm_s >> 1) == 0x1F) {
|
||||
@@ -96,14 +96,14 @@ uint64_t Instruction::ImmLogical() {
|
||||
if ((imm_s & mask) == mask) {
|
||||
return 0;
|
||||
}
|
||||
uint64_t bits = (UINT64_C(1) << ((imm_s & mask) + 1)) - 1;
|
||||
uint64_t bits = (1UL << ((imm_s & mask) + 1)) - 1;
|
||||
return RepeatBitsAcrossReg(reg_size,
|
||||
RotateRight(bits, imm_r & mask, width),
|
||||
width);
|
||||
}
|
||||
}
|
||||
}
|
||||
VIXL_UNREACHABLE();
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ Instruction* Instruction::ImmPCOffsetTarget() {
|
||||
offset = ImmPCRel();
|
||||
} else {
|
||||
// All PC-relative branches.
|
||||
VIXL_ASSERT(BranchType() != UnknownBranchType);
|
||||
ASSERT(BranchType() != UnknownBranchType);
|
||||
// Relative branch offsets are instruction-size-aligned.
|
||||
offset = ImmBranch() << kInstructionSizeLog2;
|
||||
}
|
||||
@@ -169,7 +169,7 @@ inline int Instruction::ImmBranch() const {
|
||||
case UncondBranchType: return ImmUncondBranch();
|
||||
case CompareBranchType: return ImmCmpBranch();
|
||||
case TestBranchType: return ImmTestBranch();
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -186,7 +186,7 @@ void Instruction::SetImmPCOffsetTarget(Instruction* target) {
|
||||
|
||||
void Instruction::SetPCRelImmTarget(Instruction* target) {
|
||||
// ADRP is not supported, so 'this' must point to an ADR instruction.
|
||||
VIXL_ASSERT(Mask(PCRelAddressingMask) == ADR);
|
||||
ASSERT(Mask(PCRelAddressingMask) == ADR);
|
||||
|
||||
Instr imm = Assembler::ImmPCRelAddress(target - this);
|
||||
|
||||
@@ -195,7 +195,7 @@ void Instruction::SetPCRelImmTarget(Instruction* target) {
|
||||
|
||||
|
||||
void Instruction::SetBranchImmTarget(Instruction* target) {
|
||||
VIXL_ASSERT(((target - this) & 3) == 0);
|
||||
ASSERT(((target - this) & 3) == 0);
|
||||
Instr branch_imm = 0;
|
||||
uint32_t imm_mask = 0;
|
||||
int offset = (target - this) >> kInstructionSizeLog2;
|
||||
@@ -220,14 +220,14 @@ void Instruction::SetBranchImmTarget(Instruction* target) {
|
||||
imm_mask = ImmTestBranch_mask;
|
||||
break;
|
||||
}
|
||||
default: VIXL_UNREACHABLE();
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
SetInstructionBits(Mask(~imm_mask) | branch_imm);
|
||||
}
|
||||
|
||||
|
||||
void Instruction::SetImmLLiteral(Instruction* source) {
|
||||
VIXL_ASSERT(((source - this) & 3) == 0);
|
||||
ASSERT(((source - this) & 3) == 0);
|
||||
int offset = (source - this) >> kLiteralEntrySizeLog2;
|
||||
Instr imm = Assembler::ImmLLiteral(offset);
|
||||
Instr mask = ImmLLiteral_mask;
|
||||
|
@@ -44,36 +44,30 @@ const unsigned kMaxLoadLiteralRange = 1 * MBytes;
|
||||
const unsigned kWRegSize = 32;
|
||||
const unsigned kWRegSizeLog2 = 5;
|
||||
const unsigned kWRegSizeInBytes = kWRegSize / 8;
|
||||
const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3;
|
||||
const unsigned kXRegSize = 64;
|
||||
const unsigned kXRegSizeLog2 = 6;
|
||||
const unsigned kXRegSizeInBytes = kXRegSize / 8;
|
||||
const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3;
|
||||
const unsigned kSRegSize = 32;
|
||||
const unsigned kSRegSizeLog2 = 5;
|
||||
const unsigned kSRegSizeInBytes = kSRegSize / 8;
|
||||
const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3;
|
||||
const unsigned kDRegSize = 64;
|
||||
const unsigned kDRegSizeLog2 = 6;
|
||||
const unsigned kDRegSizeInBytes = kDRegSize / 8;
|
||||
const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3;
|
||||
const uint64_t kWRegMask = UINT64_C(0xffffffff);
|
||||
const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff);
|
||||
const uint64_t kSRegMask = UINT64_C(0xffffffff);
|
||||
const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff);
|
||||
const uint64_t kSSignMask = UINT64_C(0x80000000);
|
||||
const uint64_t kDSignMask = UINT64_C(0x8000000000000000);
|
||||
const uint64_t kWSignMask = UINT64_C(0x80000000);
|
||||
const uint64_t kXSignMask = UINT64_C(0x8000000000000000);
|
||||
const uint64_t kByteMask = UINT64_C(0xff);
|
||||
const uint64_t kHalfWordMask = UINT64_C(0xffff);
|
||||
const uint64_t kWordMask = UINT64_C(0xffffffff);
|
||||
const uint64_t kXMaxUInt = UINT64_C(0xffffffffffffffff);
|
||||
const uint64_t kWMaxUInt = UINT64_C(0xffffffff);
|
||||
const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff);
|
||||
const int64_t kXMinInt = INT64_C(0x8000000000000000);
|
||||
const int32_t kWMaxInt = INT32_C(0x7fffffff);
|
||||
const int32_t kWMinInt = INT32_C(0x80000000);
|
||||
const int64_t kWRegMask = 0x00000000ffffffffLL;
|
||||
const int64_t kXRegMask = 0xffffffffffffffffLL;
|
||||
const int64_t kSRegMask = 0x00000000ffffffffLL;
|
||||
const int64_t kDRegMask = 0xffffffffffffffffLL;
|
||||
const int64_t kXSignMask = 0x1LL << 63;
|
||||
const int64_t kWSignMask = 0x1LL << 31;
|
||||
const int64_t kByteMask = 0xffL;
|
||||
const int64_t kHalfWordMask = 0xffffL;
|
||||
const int64_t kWordMask = 0xffffffffLL;
|
||||
const uint64_t kXMaxUInt = 0xffffffffffffffffULL;
|
||||
const uint64_t kWMaxUInt = 0xffffffffULL;
|
||||
const int64_t kXMaxInt = 0x7fffffffffffffffLL;
|
||||
const int64_t kXMinInt = 0x8000000000000000LL;
|
||||
const int32_t kWMaxInt = 0x7fffffff;
|
||||
const int32_t kWMinInt = 0x80000000;
|
||||
const unsigned kLinkRegCode = 30;
|
||||
const unsigned kZeroRegCode = 31;
|
||||
const unsigned kSPRegInternalCode = 63;
|
||||
@@ -87,28 +81,18 @@ const unsigned kFloatExponentBits = 8;
|
||||
|
||||
const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000);
|
||||
const float kFP32NegativeInfinity = rawbits_to_float(0xff800000);
|
||||
const double kFP64PositiveInfinity =
|
||||
rawbits_to_double(UINT64_C(0x7ff0000000000000));
|
||||
const double kFP64NegativeInfinity =
|
||||
rawbits_to_double(UINT64_C(0xfff0000000000000));
|
||||
const double kFP64PositiveInfinity = rawbits_to_double(0x7ff0000000000000ULL);
|
||||
const double kFP64NegativeInfinity = rawbits_to_double(0xfff0000000000000ULL);
|
||||
|
||||
// This value is a signalling NaN as both a double and as a float (taking the
|
||||
// least-significant word).
|
||||
static const double kFP64SignallingNaN =
|
||||
rawbits_to_double(UINT64_C(0x7ff000007f800001));
|
||||
static const double kFP64SignallingNaN = rawbits_to_double(0x7ff000007f800001ULL);
|
||||
static const float kFP32SignallingNaN = rawbits_to_float(0x7f800001);
|
||||
|
||||
// A similar value, but as a quiet NaN.
|
||||
static const double kFP64QuietNaN =
|
||||
rawbits_to_double(UINT64_C(0x7ff800007fc00001));
|
||||
static const double kFP64QuietNaN = rawbits_to_double(0x7ff800007fc00001ULL);
|
||||
static const float kFP32QuietNaN = rawbits_to_float(0x7fc00001);
|
||||
|
||||
// The default NaN values (for FPCR.DN=1).
|
||||
static const double kFP64DefaultNaN =
|
||||
rawbits_to_double(UINT64_C(0x7ff8000000000000));
|
||||
static const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000);
|
||||
|
||||
|
||||
enum LSDataSize {
|
||||
LSByte = 0,
|
||||
LSHalfword = 1,
|
||||
@@ -341,7 +325,7 @@ class Instruction {
|
||||
}
|
||||
|
||||
inline Instruction* InstructionAtOffset(int64_t offset) {
|
||||
VIXL_ASSERT(IsWordAligned(this + offset));
|
||||
ASSERT(IsWordAligned(this + offset));
|
||||
return this + offset;
|
||||
}
|
||||
|
||||
|
@@ -27,20 +27,8 @@
|
||||
#ifndef VIXL_GLOBALS_H
|
||||
#define VIXL_GLOBALS_H
|
||||
|
||||
// Get standard C99 macros for integer types.
|
||||
#ifndef __STDC_CONSTANT_MACROS
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#endif
|
||||
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#endif
|
||||
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
// Get the standard printf format macros for C99 stdint types.
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <assert.h>
|
||||
@@ -57,29 +45,21 @@ typedef uint8_t byte;
|
||||
const int KBytes = 1024;
|
||||
const int MBytes = 1024 * KBytes;
|
||||
|
||||
#define VIXL_ABORT() printf("in %s, line %i", __FILE__, __LINE__); abort()
|
||||
#define ABORT() printf("in %s, line %i", __FILE__, __LINE__); abort()
|
||||
#ifdef DEBUG
|
||||
#define VIXL_ASSERT(condition) assert(condition)
|
||||
#define VIXL_CHECK(condition) VIXL_ASSERT(condition)
|
||||
#define VIXL_UNIMPLEMENTED() printf("UNIMPLEMENTED\t"); VIXL_ABORT()
|
||||
#define VIXL_UNREACHABLE() printf("UNREACHABLE\t"); VIXL_ABORT()
|
||||
#define ASSERT(condition) assert(condition)
|
||||
#define CHECK(condition) ASSERT(condition)
|
||||
#define UNIMPLEMENTED() printf("UNIMPLEMENTED\t"); ABORT()
|
||||
#define UNREACHABLE() printf("UNREACHABLE\t"); ABORT()
|
||||
#else
|
||||
#define VIXL_ASSERT(condition) ((void) 0)
|
||||
#define VIXL_CHECK(condition) assert(condition)
|
||||
#define VIXL_UNIMPLEMENTED() ((void) 0)
|
||||
#define VIXL_UNREACHABLE() ((void) 0)
|
||||
#define ASSERT(condition) ((void) 0)
|
||||
#define CHECK(condition) assert(condition)
|
||||
#define UNIMPLEMENTED() ((void) 0)
|
||||
#define UNREACHABLE() ((void) 0)
|
||||
#endif
|
||||
// This is not as powerful as template based assertions, but it is simple.
|
||||
// It assumes that the descriptions are unique. If this starts being a problem,
|
||||
// we can switch to a different implemention.
|
||||
#define VIXL_CONCAT(a, b) a##b
|
||||
#define VIXL_STATIC_ASSERT_LINE(line, condition) \
|
||||
typedef char VIXL_CONCAT(STATIC_ASSERT_LINE_, line)[(condition) ? 1 : -1] \
|
||||
__attribute__((unused))
|
||||
#define VIXL_STATIC_ASSERT(condition) VIXL_STATIC_ASSERT_LINE(__LINE__, condition) //NOLINT
|
||||
|
||||
template <typename T> inline void USE(T) {}
|
||||
|
||||
#define VIXL_ALIGNMENT_EXCEPTION() printf("ALIGNMENT EXCEPTION\t"); VIXL_ABORT()
|
||||
#define ALIGNMENT_EXCEPTION() printf("ALIGNMENT EXCEPTION\t"); ABORT()
|
||||
|
||||
#endif // VIXL_GLOBALS_H
|
||||
|
@@ -34,7 +34,9 @@ namespace vixl {
|
||||
// Currently we assume running the simulator implies running on x86 hardware.
|
||||
inline void HostBreakpoint() { asm("int3"); }
|
||||
#else
|
||||
inline void HostBreakpoint() { asm("brk"); }
|
||||
inline void HostBreakpoint() {
|
||||
// TODO: Implement HostBreakpoint on a64.
|
||||
}
|
||||
#endif
|
||||
} // namespace vixl
|
||||
|
||||
|
@@ -58,9 +58,9 @@ double rawbits_to_double(uint64_t bits) {
|
||||
|
||||
|
||||
int CountLeadingZeros(uint64_t value, int width) {
|
||||
VIXL_ASSERT((width == 32) || (width == 64));
|
||||
ASSERT((width == 32) || (width == 64));
|
||||
int count = 0;
|
||||
uint64_t bit_test = UINT64_C(1) << (width - 1);
|
||||
uint64_t bit_test = 1UL << (width - 1);
|
||||
while ((count < width) && ((bit_test & value) == 0)) {
|
||||
count++;
|
||||
bit_test >>= 1;
|
||||
@@ -70,7 +70,7 @@ int CountLeadingZeros(uint64_t value, int width) {
|
||||
|
||||
|
||||
int CountLeadingSignBits(int64_t value, int width) {
|
||||
VIXL_ASSERT((width == 32) || (width == 64));
|
||||
ASSERT((width == 32) || (width == 64));
|
||||
if (value >= 0) {
|
||||
return CountLeadingZeros(value, width) - 1;
|
||||
} else {
|
||||
@@ -80,7 +80,7 @@ int CountLeadingSignBits(int64_t value, int width) {
|
||||
|
||||
|
||||
int CountTrailingZeros(uint64_t value, int width) {
|
||||
VIXL_ASSERT((width == 32) || (width == 64));
|
||||
ASSERT((width == 32) || (width == 64));
|
||||
int count = 0;
|
||||
while ((count < width) && (((value >> count) & 1) == 0)) {
|
||||
count++;
|
||||
@@ -92,10 +92,10 @@ int CountTrailingZeros(uint64_t value, int width) {
|
||||
int CountSetBits(uint64_t value, int width) {
|
||||
// TODO: Other widths could be added here, as the implementation already
|
||||
// supports them.
|
||||
VIXL_ASSERT((width == 32) || (width == 64));
|
||||
ASSERT((width == 32) || (width == 64));
|
||||
|
||||
// Mask out unused bits to ensure that they are not counted.
|
||||
value &= (UINT64_C(0xffffffffffffffff) >> (64-width));
|
||||
value &= (0xffffffffffffffffULL >> (64-width));
|
||||
|
||||
// Add up the set bits.
|
||||
// The algorithm works by adding pairs of bit fields together iteratively,
|
||||
@@ -108,19 +108,18 @@ int CountSetBits(uint64_t value, int width) {
|
||||
// value = h+g+f+e d+c+b+a
|
||||
// \ |
|
||||
// value = h+g+f+e+d+c+b+a
|
||||
const uint64_t kMasks[] = {
|
||||
UINT64_C(0x5555555555555555),
|
||||
UINT64_C(0x3333333333333333),
|
||||
UINT64_C(0x0f0f0f0f0f0f0f0f),
|
||||
UINT64_C(0x00ff00ff00ff00ff),
|
||||
UINT64_C(0x0000ffff0000ffff),
|
||||
UINT64_C(0x00000000ffffffff),
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < (sizeof(kMasks) / sizeof(kMasks[0])); i++) {
|
||||
int shift = 1 << i;
|
||||
value = ((value >> shift) & kMasks[i]) + (value & kMasks[i]);
|
||||
}
|
||||
value = ((value >> 1) & 0x5555555555555555ULL) +
|
||||
(value & 0x5555555555555555ULL);
|
||||
value = ((value >> 2) & 0x3333333333333333ULL) +
|
||||
(value & 0x3333333333333333ULL);
|
||||
value = ((value >> 4) & 0x0f0f0f0f0f0f0f0fULL) +
|
||||
(value & 0x0f0f0f0f0f0f0f0fULL);
|
||||
value = ((value >> 8) & 0x00ff00ff00ff00ffULL) +
|
||||
(value & 0x00ff00ff00ff00ffULL);
|
||||
value = ((value >> 16) & 0x0000ffff0000ffffULL) +
|
||||
(value & 0x0000ffff0000ffffULL);
|
||||
value = ((value >> 32) & 0x00000000ffffffffULL) +
|
||||
(value & 0x00000000ffffffffULL);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@
|
||||
#ifndef VIXL_UTILS_H
|
||||
#define VIXL_UTILS_H
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <string.h>
|
||||
#include "globals.h"
|
||||
|
||||
@@ -35,19 +35,19 @@ namespace vixl {
|
||||
|
||||
// Check number width.
|
||||
inline bool is_intn(unsigned n, int64_t x) {
|
||||
VIXL_ASSERT((0 < n) && (n < 64));
|
||||
int64_t limit = INT64_C(1) << (n - 1);
|
||||
ASSERT((0 < n) && (n < 64));
|
||||
int64_t limit = 1ULL << (n - 1);
|
||||
return (-limit <= x) && (x < limit);
|
||||
}
|
||||
|
||||
inline bool is_uintn(unsigned n, int64_t x) {
|
||||
VIXL_ASSERT((0 < n) && (n < 64));
|
||||
ASSERT((0 < n) && (n < 64));
|
||||
return !(x >> n);
|
||||
}
|
||||
|
||||
inline unsigned truncate_to_intn(unsigned n, int64_t x) {
|
||||
VIXL_ASSERT((0 < n) && (n < 64));
|
||||
return (x & ((INT64_C(1) << n) - 1));
|
||||
ASSERT((0 < n) && (n < 64));
|
||||
return (x & ((1ULL << n) - 1));
|
||||
}
|
||||
|
||||
#define INT_1_TO_63_LIST(V) \
|
||||
@@ -90,67 +90,13 @@ inline int64_t signed_bitextract_64(int msb, int lsb, int64_t x) {
|
||||
return (x << (63 - msb)) >> (lsb + 63 - msb);
|
||||
}
|
||||
|
||||
// Floating point representation.
|
||||
// floating point representation
|
||||
uint32_t float_to_rawbits(float value);
|
||||
uint64_t double_to_rawbits(double value);
|
||||
float rawbits_to_float(uint32_t bits);
|
||||
double rawbits_to_double(uint64_t bits);
|
||||
|
||||
|
||||
// NaN tests.
|
||||
inline bool IsSignallingNaN(double num) {
|
||||
const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000);
|
||||
uint64_t raw = double_to_rawbits(num);
|
||||
if (isnan(num) && ((raw & kFP64QuietNaNMask) == 0)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline bool IsSignallingNaN(float num) {
|
||||
const uint32_t kFP32QuietNaNMask = 0x00400000;
|
||||
uint32_t raw = float_to_rawbits(num);
|
||||
if (isnan(num) && ((raw & kFP32QuietNaNMask) == 0)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline bool IsQuietNaN(T num) {
|
||||
return isnan(num) && !IsSignallingNaN(num);
|
||||
}
|
||||
|
||||
|
||||
// Convert the NaN in 'num' to a quiet NaN.
|
||||
inline double ToQuietNaN(double num) {
|
||||
const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000);
|
||||
VIXL_ASSERT(isnan(num));
|
||||
return rawbits_to_double(double_to_rawbits(num) | kFP64QuietNaNMask);
|
||||
}
|
||||
|
||||
|
||||
inline float ToQuietNaN(float num) {
|
||||
const uint32_t kFP32QuietNaNMask = 0x00400000;
|
||||
VIXL_ASSERT(isnan(num));
|
||||
return rawbits_to_float(float_to_rawbits(num) | kFP32QuietNaNMask);
|
||||
}
|
||||
|
||||
|
||||
// Fused multiply-add.
|
||||
inline double FusedMultiplyAdd(double op1, double op2, double a) {
|
||||
return fma(op1, op2, a);
|
||||
}
|
||||
|
||||
|
||||
inline float FusedMultiplyAdd(float op1, float op2, float a) {
|
||||
return fmaf(op1, op2, a);
|
||||
}
|
||||
|
||||
|
||||
// Bit counting.
|
||||
// Bits counting.
|
||||
int CountLeadingZeros(uint64_t value, int width);
|
||||
int CountLeadingSignBits(int64_t value, int width);
|
||||
int CountTrailingZeros(uint64_t value, int width);
|
||||
@@ -160,30 +106,20 @@ int CountSetBits(uint64_t value, int width);
|
||||
// TODO: rename/refactor to make it specific to instructions.
|
||||
template<typename T>
|
||||
bool IsWordAligned(T pointer) {
|
||||
VIXL_ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof)
|
||||
ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof)
|
||||
return (reinterpret_cast<intptr_t>(pointer) & 3) == 0;
|
||||
}
|
||||
|
||||
// Increment a pointer until it has the specified alignment.
|
||||
template<class T>
|
||||
T AlignUp(T pointer, size_t alignment) {
|
||||
VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(uintptr_t));
|
||||
ASSERT(sizeof(pointer) == sizeof(uintptr_t));
|
||||
uintptr_t pointer_raw = reinterpret_cast<uintptr_t>(pointer);
|
||||
size_t align_step = (alignment - pointer_raw) % alignment;
|
||||
VIXL_ASSERT((pointer_raw + align_step) % alignment == 0);
|
||||
ASSERT((pointer_raw + align_step) % alignment == 0);
|
||||
return reinterpret_cast<T>(pointer_raw + align_step);
|
||||
}
|
||||
|
||||
// Decrement a pointer until it has the specified alignment.
|
||||
template<class T>
|
||||
T AlignDown(T pointer, size_t alignment) {
|
||||
VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(uintptr_t));
|
||||
uintptr_t pointer_raw = reinterpret_cast<uintptr_t>(pointer);
|
||||
size_t align_step = pointer_raw % alignment;
|
||||
VIXL_ASSERT((pointer_raw - align_step) % alignment == 0);
|
||||
return reinterpret_cast<T>(pointer_raw - align_step);
|
||||
}
|
||||
|
||||
|
||||
} // namespace vixl
|
||||
|
||||
|
@@ -143,12 +143,12 @@ static void dma_bdrv_cb(void *opaque, int ret)
|
||||
|
||||
dbs->acb = NULL;
|
||||
dbs->sector_num += dbs->iov.size / 512;
|
||||
dma_bdrv_unmap(dbs);
|
||||
|
||||
if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) {
|
||||
dma_complete(dbs, ret);
|
||||
return;
|
||||
}
|
||||
dma_bdrv_unmap(dbs);
|
||||
|
||||
while (dbs->sg_cur_index < dbs->sg->nsg) {
|
||||
cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
|
||||
|
@@ -232,8 +232,8 @@ various constraints can be supplied to control how these callbacks are called:
|
||||
(in bytes) supported by the *implementation*; other access sizes will be
|
||||
emulated using the ones available. For example a 4-byte write will be
|
||||
emulated using four 1-byte writes, if .impl.max_access_size = 1.
|
||||
- .impl.unaligned specifies that the *implementation* supports unaligned
|
||||
accesses; if false, unaligned accesses will be emulated by two aligned
|
||||
accesses.
|
||||
- .old_mmio can be used to ease porting from code using
|
||||
cpu_register_io_memory(). It should not be used in new code.
|
||||
- .impl.valid specifies that the *implementation* only supports unaligned
|
||||
accesses; unaligned accesses will be emulated by two aligned accesses.
|
||||
- .old_portio and .old_mmio can be used to ease porting from code using
|
||||
cpu_register_io_memory() and register_ioport(). They should not be used
|
||||
in new code.
|
||||
|
@@ -139,7 +139,8 @@ static const VMStateDescription vmstate_kbd = {
|
||||
.name = "pckbd",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 3,
|
||||
.fields = (VMStateField[]) {
|
||||
.minimum_version_id_old = 3,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_UINT8(write_cmd, KBDState),
|
||||
VMSTATE_UINT8(status, KBDState),
|
||||
VMSTATE_UINT8(mode, KBDState),
|
||||
@@ -167,13 +168,12 @@ You can see that there are several version fields:
|
||||
- minimum_version_id: the minimum version_id that VMState is able to understand
|
||||
for that device.
|
||||
- minimum_version_id_old: For devices that were not able to port to vmstate, we can
|
||||
assign a function that knows how to read this old state. This field is
|
||||
ignored if there is no load_state_old handler.
|
||||
assign a function that knows how to read this old state.
|
||||
|
||||
So, VMState is able to read versions from minimum_version_id to
|
||||
version_id. And the function load_state_old() (if present) is able to
|
||||
load state from minimum_version_id_old to minimum_version_id. This
|
||||
function is deprecated and will be removed when no more users are left.
|
||||
version_id. And the function load_state_old() is able to load state
|
||||
from minimum_version_id_old to minimum_version_id. This function is
|
||||
deprecated and will be removed when no more users are left.
|
||||
|
||||
=== Massaging functions ===
|
||||
|
||||
@@ -255,9 +255,10 @@ const VMStateDescription vmstate_ide_drive_pio_state = {
|
||||
.name = "ide_drive/pio_state",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.pre_save = ide_drive_pio_pre_save,
|
||||
.post_load = ide_drive_pio_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_INT32(req_nb_sectors, IDEState),
|
||||
VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
|
||||
vmstate_info_uint8, uint8_t),
|
||||
@@ -274,8 +275,9 @@ const VMStateDescription vmstate_ide_drive = {
|
||||
.name = "ide_drive",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.post_load = ide_drive_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField []) {
|
||||
.... several fields ....
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
|
@@ -1,102 +0,0 @@
|
||||
|
||||
multiseat howto (with some multihead coverage)
|
||||
==============================================
|
||||
|
||||
host side
|
||||
---------
|
||||
|
||||
First you must compile qemu with a user interface supporting
|
||||
multihead/multiseat and input event routing. Right now this
|
||||
list includes sdl2 and gtk (both 2+3):
|
||||
|
||||
./configure --enable-sdl --with-sdlabi=2.0
|
||||
|
||||
or
|
||||
|
||||
./configure --enable-gtk
|
||||
|
||||
|
||||
Next put together the qemu command line:
|
||||
|
||||
qemu -enable-kvm -usb $memory $disk $whatever \
|
||||
-display [ sdl | gtk ] \
|
||||
-vga std \
|
||||
-device usb-tablet
|
||||
|
||||
That is it for the first head, which will use the standard vga, the
|
||||
standard ps/2 keyboard (implicitly there) and the usb-tablet. Now the
|
||||
additional switches for the second head:
|
||||
|
||||
-device pci-bridge,addr=12.0,chassis_nr=2,id=head.2 \
|
||||
-device secondary-vga,bus=head.2,addr=02.0,id=video.2 \
|
||||
-device nec-usb-xhci,bus=head.2,addr=0f.0,id=usb.2 \
|
||||
-device usb-kbd,bus=usb.2.0,port=1,display=video.2 \
|
||||
-device usb-tablet,bus=usb.2.0,port=2,display=video.2
|
||||
|
||||
This places a pci bridge in slot 12, connects a display adapter and
|
||||
xhci (usb) controller to the bridge. Then it adds a usb keyboard and
|
||||
usb mouse, both connected to the xhci and linked to the display.
|
||||
|
||||
The "display=video2" sets up the input routing. Any input coming from
|
||||
the window which belongs to the video.2 display adapter will be routed
|
||||
to these input devices.
|
||||
|
||||
The sdl2 ui will start up with two windows, one for each display
|
||||
device. The gtk ui will start with a single window and each display
|
||||
in a separate tab. You can either simply switch tabs to switch heads,
|
||||
or use the "View / Detach tab" menu item to move one of the displays
|
||||
to its own window so you can see both display devices side-by-side.
|
||||
|
||||
Note on spice: Spice handles multihead just fine. But it can't do
|
||||
multiseat. For tablet events the event source is sent to the spice
|
||||
agent. But qemu can't figure it, so it can't do input routing.
|
||||
Fixing this needs a new or extended input interface between
|
||||
libspice-server and qemu. For keyboard events it is even worse: The
|
||||
event source isn't included in the spice protocol, so the wire
|
||||
protocol must be extended to support this.
|
||||
|
||||
|
||||
guest side
|
||||
----------
|
||||
|
||||
You need a pretty recent linux guest. systemd with loginctl. kernel
|
||||
3.14+ with CONFIG_DRM_BOCHS enabled. Fedora 20 will do. Must be
|
||||
fully updated for the new kernel though, i.e. the live iso doesn't cut
|
||||
it.
|
||||
|
||||
Now we'll have to configure the guest. Boot and login. "lspci -vt"
|
||||
should list the pci bridge with the display adapter and usb controller:
|
||||
|
||||
[root@fedora ~]# lspci -vt
|
||||
-[0000:00]-+-00.0 Intel Corporation 440FX - 82441FX PMC [Natoma]
|
||||
[ ... ]
|
||||
\-12.0-[01]--+-02.0 Device 1234:1111
|
||||
\-0f.0 NEC Corporation USB 3.0 Host Controller
|
||||
|
||||
Good. Now lets tell the system that the pci bridge and all devices
|
||||
below it belong to a separate seat by dropping a file into
|
||||
/etc/udev/rules.d:
|
||||
|
||||
[root@fedora ~]# cat /etc/udev/rules.d/70-qemu-autoseat.rules
|
||||
SUBSYSTEMS=="pci", DEVPATH=="*/0000:00:12.0", TAG+="seat", ENV{ID_AUTOSEAT}="1"
|
||||
|
||||
Reboot. System should come up with two seats. With loginctl you can
|
||||
check the configuration:
|
||||
|
||||
[root@fedora ~]# loginctl list-seats
|
||||
SEAT
|
||||
seat0
|
||||
seat-pci-pci-0000_00_12_0
|
||||
|
||||
2 seats listed.
|
||||
|
||||
You can use "loginctl seat-status seat-pci-pci-0000_00_12_0" to list
|
||||
the devices attached to the seat.
|
||||
|
||||
Background info is here:
|
||||
http://www.freedesktop.org/wiki/Software/systemd/multiseat/
|
||||
|
||||
Enjoy!
|
||||
|
||||
--
|
||||
Gerd Hoffmann <kraxel@redhat.com>
|
@@ -40,17 +40,6 @@ enumeration types and union types.
|
||||
Generally speaking, types definitions should always use CamelCase for the type
|
||||
names. Command names should be all lower case with words separated by a hyphen.
|
||||
|
||||
|
||||
=== Includes ===
|
||||
|
||||
The QAPI schema definitions can be modularized using the 'include' directive:
|
||||
|
||||
{ 'include': 'path/to/file.json'}
|
||||
|
||||
The directive is evaluated recursively, and include paths are relative to the
|
||||
file using the directive. Multiple includes of the same file are safe.
|
||||
|
||||
|
||||
=== Complex types ===
|
||||
|
||||
A complex type is a dictionary containing a single key whose value is a
|
||||
@@ -60,34 +49,10 @@ example of a complex type is:
|
||||
{ 'type': 'MyType',
|
||||
'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } }
|
||||
|
||||
The use of '*' as a prefix to the name means the member is optional.
|
||||
The use of '*' as a prefix to the name means the member is optional. Optional
|
||||
members should always be added to the end of the dictionary to preserve
|
||||
backwards compatibility.
|
||||
|
||||
The default initialization value of an optional argument should not be changed
|
||||
between versions of QEMU unless the new default maintains backward
|
||||
compatibility to the user-visible behavior of the old default.
|
||||
|
||||
With proper documentation, this policy still allows some flexibility; for
|
||||
example, documenting that a default of 0 picks an optimal buffer size allows
|
||||
one release to declare the optimal size at 512 while another release declares
|
||||
the optimal size at 4096 - the user-visible behavior is not the bytes used by
|
||||
the buffer, but the fact that the buffer was optimal size.
|
||||
|
||||
On input structures (only mentioned in the 'data' side of a command), changing
|
||||
from mandatory to optional is safe (older clients will supply the option, and
|
||||
newer clients can benefit from the default); changing from optional to
|
||||
mandatory is backwards incompatible (older clients may be omitting the option,
|
||||
and must continue to work).
|
||||
|
||||
On output structures (only mentioned in the 'returns' side of a command),
|
||||
changing from mandatory to optional is in general unsafe (older clients may be
|
||||
expecting the field, and could crash if it is missing), although it can be done
|
||||
if the only way that the optional argument will be omitted is when it is
|
||||
triggered by the presence of a new input flag to the command that older clients
|
||||
don't know to send. Changing from optional to mandatory is safe.
|
||||
|
||||
A structure that is used in both input and output of various commands
|
||||
must consider the backwards compatibility constraints of both directions
|
||||
of use.
|
||||
|
||||
A complex type definition can specify another complex type as its base.
|
||||
In this case, the fields of the base type are included as top-level fields
|
||||
@@ -230,13 +195,14 @@ node structure that can be used to chain together a list of such types in
|
||||
case we want to accept/return a list of this type with a command), and a
|
||||
command which takes that type as a parameter and returns the same type:
|
||||
|
||||
$ cat example-schema.json
|
||||
mdroth@illuin:~/w/qemu2.git$ cat example-schema.json
|
||||
{ 'type': 'UserDefOne',
|
||||
'data': { 'integer': 'int', 'string': 'str' } }
|
||||
|
||||
{ 'command': 'my-command',
|
||||
'data': {'arg1': 'UserDefOne'},
|
||||
'returns': 'UserDefOne' }
|
||||
mdroth@illuin:~/w/qemu2.git$
|
||||
|
||||
=== scripts/qapi-types.py ===
|
||||
|
||||
@@ -254,25 +220,14 @@ created code.
|
||||
|
||||
Example:
|
||||
|
||||
$ python scripts/qapi-types.py --output-dir="qapi-generated" \
|
||||
--prefix="example-" --input-file=example-schema.json
|
||||
$ cat qapi-generated/example-qapi-types.c
|
||||
[Uninteresting stuff omitted...]
|
||||
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \
|
||||
--output-dir="qapi-generated" --prefix="example-" < example-schema.json
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c
|
||||
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
void qapi_free_UserDefOneList(UserDefOneList * obj)
|
||||
{
|
||||
QapiDeallocVisitor *md;
|
||||
Visitor *v;
|
||||
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
md = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOneList(v, &obj, NULL, NULL);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
}
|
||||
#include "qapi/qapi-dealloc-visitor.h"
|
||||
#include "example-qapi-types.h"
|
||||
#include "example-qapi-visit.h"
|
||||
|
||||
void qapi_free_UserDefOne(UserDefOne * obj)
|
||||
{
|
||||
@@ -289,38 +244,32 @@ Example:
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
}
|
||||
|
||||
$ cat qapi-generated/example-qapi-types.h
|
||||
[Uninteresting stuff omitted...]
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h
|
||||
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES
|
||||
#define QAPI_GENERATED_EXAMPLE_QAPI_TYPES
|
||||
|
||||
#ifndef EXAMPLE_QAPI_TYPES_H
|
||||
#define EXAMPLE_QAPI_TYPES_H
|
||||
|
||||
[Builtin types omitted...]
|
||||
#include "qapi/qapi-types-core.h"
|
||||
|
||||
typedef struct UserDefOne UserDefOne;
|
||||
|
||||
typedef struct UserDefOneList
|
||||
{
|
||||
union {
|
||||
UserDefOne *value;
|
||||
uint64_t padding;
|
||||
};
|
||||
UserDefOne *value;
|
||||
struct UserDefOneList *next;
|
||||
} UserDefOneList;
|
||||
|
||||
[Functions on builtin types omitted...]
|
||||
|
||||
struct UserDefOne
|
||||
{
|
||||
int64_t integer;
|
||||
char * string;
|
||||
};
|
||||
|
||||
void qapi_free_UserDefOneList(UserDefOneList * obj);
|
||||
void qapi_free_UserDefOne(UserDefOne * obj);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
=== scripts/qapi-visit.py ===
|
||||
|
||||
Used to generate the visitor functions used to walk through and convert
|
||||
@@ -341,78 +290,51 @@ $(prefix)qapi-visit.h: declarations for previously mentioned visitor
|
||||
|
||||
Example:
|
||||
|
||||
$ python scripts/qapi-visit.py --output-dir="qapi-generated"
|
||||
--prefix="example-" --input-file=example-schema.json
|
||||
$ cat qapi-generated/example-qapi-visit.c
|
||||
[Uninteresting stuff omitted...]
|
||||
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \
|
||||
--output-dir="qapi-generated" --prefix="example-" < example-schema.json
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne ** obj, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
visit_type_int(m, &(*obj)->integer, "integer", &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
visit_type_str(m, &(*obj)->string, "string", &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
#include "example-qapi-visit.h"
|
||||
|
||||
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
|
||||
visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), &err);
|
||||
if (!err) {
|
||||
if (*obj) {
|
||||
visit_type_UserDefOne_fields(m, obj, errp);
|
||||
}
|
||||
visit_end_struct(m, &err);
|
||||
}
|
||||
error_propagate(errp, err);
|
||||
visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), errp);
|
||||
visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, "integer", errp);
|
||||
visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", errp);
|
||||
visit_end_struct(m, errp);
|
||||
}
|
||||
|
||||
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
GenericList *i, **prev;
|
||||
GenericList *i, **prev = (GenericList **)obj;
|
||||
|
||||
visit_start_list(m, name, &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
visit_start_list(m, name, errp);
|
||||
|
||||
for (prev = (GenericList **)obj;
|
||||
!err && (i = visit_next_list(m, prev, &err)) != NULL;
|
||||
prev = &i) {
|
||||
for (; (i = visit_next_list(m, prev, errp)) != NULL; prev = &i) {
|
||||
UserDefOneList *native_i = (UserDefOneList *)i;
|
||||
visit_type_UserDefOne(m, &native_i->value, NULL, &err);
|
||||
visit_type_UserDefOne(m, &native_i->value, NULL, errp);
|
||||
}
|
||||
|
||||
error_propagate(errp, err);
|
||||
err = NULL;
|
||||
visit_end_list(m, &err);
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
visit_end_list(m, errp);
|
||||
}
|
||||
$ python scripts/qapi-commands.py --output-dir="qapi-generated" \
|
||||
--prefix="example-" --input-file=example-schema.json
|
||||
$ cat qapi-generated/example-qapi-visit.h
|
||||
[Uninteresting stuff omitted...]
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
#ifndef EXAMPLE_QAPI_VISIT_H
|
||||
#define EXAMPLE_QAPI_VISIT_H
|
||||
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT
|
||||
#define QAPI_GENERATED_EXAMPLE_QAPI_VISIT
|
||||
|
||||
[Visitors for builtin types omitted...]
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
#include "example-qapi-types.h"
|
||||
|
||||
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
|
||||
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
|
||||
|
||||
#endif
|
||||
mdroth@illuin:~/w/qemu2.git$
|
||||
|
||||
(The actual structure of the visit_type_* functions is a bit more complex
|
||||
in order to propagate errors correctly and avoid leaking memory).
|
||||
|
||||
=== scripts/qapi-commands.py ===
|
||||
|
||||
@@ -433,80 +355,77 @@ $(prefix)qmp-commands.h: Function prototypes for the QMP commands
|
||||
|
||||
Example:
|
||||
|
||||
$ cat qapi-generated/example-qmp-marshal.c
|
||||
[Uninteresting stuff omitted...]
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
#include "qemu-objects.h"
|
||||
#include "qapi/qmp-core.h"
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
#include "qapi/qmp-input-visitor.h"
|
||||
#include "qapi/qapi-dealloc-visitor.h"
|
||||
#include "example-qapi-types.h"
|
||||
#include "example-qapi-visit.h"
|
||||
|
||||
#include "example-qmp-commands.h"
|
||||
static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
|
||||
QmpOutputVisitor *mo = qmp_output_visitor_new();
|
||||
QapiDeallocVisitor *md;
|
||||
Visitor *v;
|
||||
|
||||
v = qmp_output_get_visitor(mo);
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
*ret_out = qmp_output_get_qobject(mo);
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
qmp_output_visitor_cleanup(mo);
|
||||
md = qapi_dealloc_visitor_new();
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", errp);
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", NULL);
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", errp);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
|
||||
|
||||
*ret_out = qmp_output_get_qobject(mo);
|
||||
}
|
||||
|
||||
static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
|
||||
static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
UserDefOne * retval = NULL;
|
||||
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
|
||||
QmpInputVisitor *mi;
|
||||
QapiDeallocVisitor *md;
|
||||
Visitor *v;
|
||||
UserDefOne * arg1 = NULL;
|
||||
|
||||
mi = qmp_input_visitor_new(QOBJECT(args));
|
||||
v = qmp_input_get_visitor(mi);
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", &local_err);
|
||||
if (local_err) {
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", errp);
|
||||
|
||||
if (error_is_set(errp)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
retval = qmp_my_command(arg1, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
qmp_marshal_output_my_command(retval, ret, &local_err);
|
||||
retval = qmp_my_command(arg1, errp);
|
||||
qmp_marshal_output_my_command(retval, ret, errp);
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
qmp_input_visitor_cleanup(mi);
|
||||
md = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", NULL);
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", errp);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
return;
|
||||
}
|
||||
|
||||
static void qmp_init_marshal(void)
|
||||
{
|
||||
qmp_register_command("my-command", qmp_marshal_input_my_command, QCO_NO_OPTIONS);
|
||||
qmp_register_command("my-command", qmp_marshal_input_my_command);
|
||||
}
|
||||
|
||||
qapi_init(qmp_init_marshal);
|
||||
$ cat qapi-generated/example-qmp-commands.h
|
||||
[Uninteresting stuff omitted...]
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
#ifndef EXAMPLE_QMP_COMMANDS_H
|
||||
#define EXAMPLE_QMP_COMMANDS_H
|
||||
#ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
|
||||
#define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
|
||||
|
||||
#include "example-qapi-types.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/error.h"
|
||||
#include "error.h"
|
||||
|
||||
UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
|
||||
|
||||
#endif
|
||||
mdroth@illuin:~/w/qemu2.git$
|
||||
|
@@ -107,9 +107,8 @@ in the description of a field.
|
||||
|
||||
96 - 99: refcount_order
|
||||
Describes the width of a reference count block entry (width
|
||||
in bits: refcount_bits = 1 << refcount_order). For version 2
|
||||
images, the order is always assumed to be 4
|
||||
(i.e. refcount_bits = 16).
|
||||
in bits = 1 << refcount_order). For version 2 images, the
|
||||
order is always assumed to be 4 (i.e. the width is 16 bits).
|
||||
|
||||
100 - 103: header_length
|
||||
Length of the header structure in bytes. For version 2
|
||||
|
@@ -5,10 +5,9 @@ QEMU Standard VGA
|
||||
Exists in two variants, for isa and pci.
|
||||
|
||||
command line switches:
|
||||
-vga std [ picks isa for -M isapc, otherwise pci ]
|
||||
-device VGA [ pci variant ]
|
||||
-device isa-vga [ isa variant ]
|
||||
-device secondary-vga [ legacy-free pci variant ]
|
||||
-vga std [ picks isa for -M isapc, otherwise pci ]
|
||||
-device VGA [ pci variant ]
|
||||
-device isa-vga [ isa variant ]
|
||||
|
||||
|
||||
PCI spec
|
||||
@@ -32,15 +31,9 @@ PCI ROM Region:
|
||||
Holds the vgabios (qemu 0.14+).
|
||||
|
||||
|
||||
The legacy-free variant has no ROM and has PCI_CLASS_DISPLAY_OTHER
|
||||
instead of PCI_CLASS_DISPLAY_VGA.
|
||||
|
||||
|
||||
IO ports used
|
||||
-------------
|
||||
|
||||
Doesn't apply to the legacy-free pci variant, use the MMIO bar instead.
|
||||
|
||||
03c0 - 03df : standard vga ports
|
||||
01ce : bochs vbe interface index port
|
||||
01cf : bochs vbe interface data port (x86 only)
|
||||
|
@@ -9,7 +9,7 @@ for debugging, profiling, and observing execution.
|
||||
|
||||
1. Build with the 'simple' trace backend:
|
||||
|
||||
./configure --enable-trace-backends=simple
|
||||
./configure --enable-trace-backend=simple
|
||||
make
|
||||
|
||||
2. Create a file with the events you want to trace:
|
||||
@@ -142,7 +142,7 @@ script.
|
||||
The trace backend is chosen at configure time and only one trace backend can
|
||||
be built into the binary:
|
||||
|
||||
./configure --trace-backends=simple
|
||||
./configure --trace-backend=simple
|
||||
|
||||
For a list of supported trace backends, try ./configure --help or see below.
|
||||
|
||||
|
@@ -35,8 +35,7 @@ which will return a dictionary containing:
|
||||
|
||||
o A key named last-update, which contains the last stats update
|
||||
timestamp in seconds. Since this timestamp is generated by the host,
|
||||
a buggy guest can't influence its value. The value is 0 if the guest
|
||||
has not updated the stats (yet).
|
||||
a buggy guest can't influence its value
|
||||
|
||||
It's also important to note the following:
|
||||
|
||||
@@ -50,7 +49,7 @@ It's also important to note the following:
|
||||
|
||||
- Polling can be enabled even if the guest doesn't have stats support
|
||||
or the balloon driver wasn't loaded in the guest. If this is the case
|
||||
and stats are queried, last-update will be 0.
|
||||
and stats are queried, an error will be returned
|
||||
|
||||
- The polling timer is only re-armed when the guest responds to the
|
||||
statistics request. This means that if a (buggy) guest doesn't ever
|
||||
|
@@ -308,12 +308,12 @@ Here's the implementation of the "hello-world" HMP command:
|
||||
void hmp_hello_world(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *message = qdict_get_try_str(qdict, "message");
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_hello_world(!!message, message, &err);
|
||||
if (err) {
|
||||
monitor_printf(mon, "%s\n", error_get_pretty(err));
|
||||
error_free(err);
|
||||
qmp_hello_world(!!message, message, &errp);
|
||||
if (error_is_set(&errp)) {
|
||||
monitor_printf(mon, "%s\n", error_get_pretty(errp));
|
||||
error_free(errp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -328,7 +328,7 @@ There are three important points to be noticed:
|
||||
2. hmp_hello_world() performs error checking. In this example we just print
|
||||
the error description to the user, but we could do more, like taking
|
||||
different actions depending on the error qmp_hello_world() returns
|
||||
3. The "err" variable must be initialized to NULL before performing the
|
||||
3. The "errp" variable must be initialized to NULL before performing the
|
||||
QMP call
|
||||
|
||||
There's one last step to actually make the command available to monitor users,
|
||||
@@ -480,12 +480,12 @@ Here's the HMP counterpart of the query-alarm-clock command:
|
||||
void hmp_info_alarm_clock(Monitor *mon)
|
||||
{
|
||||
QemuAlarmClock *clock;
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
clock = qmp_query_alarm_clock(&err);
|
||||
if (err) {
|
||||
clock = qmp_query_alarm_clock(&errp);
|
||||
if (error_is_set(&errp)) {
|
||||
monitor_printf(mon, "Could not query alarm clock information\n");
|
||||
error_free(err);
|
||||
error_free(errp);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -631,12 +631,12 @@ has to traverse the list, it's shown below for reference:
|
||||
void hmp_info_alarm_methods(Monitor *mon)
|
||||
{
|
||||
TimerAlarmMethodList *method_list, *method;
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
method_list = qmp_query_alarm_methods(&err);
|
||||
if (err) {
|
||||
method_list = qmp_query_alarm_methods(&errp);
|
||||
if (error_is_set(&errp)) {
|
||||
monitor_printf(mon, "Could not query alarm methods\n");
|
||||
error_free(err);
|
||||
error_free(errp);
|
||||
return;
|
||||
}
|
||||
|
||||
|
6
dump.c
6
dump.c
@@ -86,6 +86,7 @@ typedef struct DumpState {
|
||||
bool has_filter;
|
||||
int64_t begin;
|
||||
int64_t length;
|
||||
Error **errp;
|
||||
|
||||
uint8_t *note_buf; /* buffer for notes */
|
||||
size_t note_buf_offset; /* the writing place in note_buf */
|
||||
@@ -1569,6 +1570,7 @@ static int dump_init(DumpState *s, int fd, bool has_format,
|
||||
nr_cpus++;
|
||||
}
|
||||
|
||||
s->errp = errp;
|
||||
s->fd = fd;
|
||||
s->has_filter = has_filter;
|
||||
s->begin = begin;
|
||||
@@ -1778,11 +1780,11 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
|
||||
}
|
||||
|
||||
if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
|
||||
if (create_kdump_vmcore(s) < 0) {
|
||||
if (create_kdump_vmcore(s) < 0 && !error_is_set(s->errp)) {
|
||||
error_set(errp, QERR_IO_ERROR);
|
||||
}
|
||||
} else {
|
||||
if (create_vmcore(s) < 0) {
|
||||
if (create_vmcore(s) < 0 && !error_is_set(s->errp)) {
|
||||
error_set(errp, QERR_IO_ERROR);
|
||||
}
|
||||
}
|
||||
|
5
exec.c
5
exec.c
@@ -380,7 +380,7 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||
as = iotlb.target_as;
|
||||
}
|
||||
|
||||
if (xen_enabled() && memory_access_is_direct(mr, is_write)) {
|
||||
if (memory_access_is_direct(mr, is_write)) {
|
||||
hwaddr page = ((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr;
|
||||
len = MIN(page, len);
|
||||
}
|
||||
@@ -429,8 +429,9 @@ const VMStateDescription vmstate_cpu_common = {
|
||||
.name = "cpu_common",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = cpu_common_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_UINT32(halted, CPUState),
|
||||
VMSTATE_UINT32(interrupt_request, CPUState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
|
@@ -55,7 +55,7 @@ these four paragraphs for those parts of this code that are retained.
|
||||
| The result is stored in the location pointed to by `zPtr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void shift32RightJamming(uint32_t a, int_fast16_t count, uint32_t *zPtr)
|
||||
static inline void shift32RightJamming(uint32_t a, int_fast16_t count, uint32_t *zPtr)
|
||||
{
|
||||
uint32_t z;
|
||||
|
||||
@@ -81,7 +81,7 @@ INLINE void shift32RightJamming(uint32_t a, int_fast16_t count, uint32_t *zPtr)
|
||||
| The result is stored in the location pointed to by `zPtr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void shift64RightJamming(uint64_t a, int_fast16_t count, uint64_t *zPtr)
|
||||
static inline void shift64RightJamming(uint64_t a, int_fast16_t count, uint64_t *zPtr)
|
||||
{
|
||||
uint64_t z;
|
||||
|
||||
@@ -115,7 +115,7 @@ INLINE void shift64RightJamming(uint64_t a, int_fast16_t count, uint64_t *zPtr)
|
||||
| described above, and is returned at the location pointed to by `z1Ptr'.)
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void
|
||||
static inline void
|
||||
shift64ExtraRightJamming(
|
||||
uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr)
|
||||
{
|
||||
@@ -152,7 +152,7 @@ INLINE void
|
||||
| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void
|
||||
static inline void
|
||||
shift128Right(
|
||||
uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr)
|
||||
{
|
||||
@@ -187,7 +187,7 @@ INLINE void
|
||||
| the locations pointed to by `z0Ptr' and `z1Ptr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void
|
||||
static inline void
|
||||
shift128RightJamming(
|
||||
uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr)
|
||||
{
|
||||
@@ -238,7 +238,7 @@ INLINE void
|
||||
| `z2Ptr'.)
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void
|
||||
static inline void
|
||||
shift128ExtraRightJamming(
|
||||
uint64_t a0,
|
||||
uint64_t a1,
|
||||
@@ -296,7 +296,7 @@ INLINE void
|
||||
| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void
|
||||
static inline void
|
||||
shortShift128Left(
|
||||
uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr)
|
||||
{
|
||||
@@ -315,7 +315,7 @@ INLINE void
|
||||
| `z1Ptr', and `z2Ptr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void
|
||||
static inline void
|
||||
shortShift192Left(
|
||||
uint64_t a0,
|
||||
uint64_t a1,
|
||||
@@ -350,7 +350,7 @@ INLINE void
|
||||
| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void
|
||||
static inline void
|
||||
add128(
|
||||
uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, uint64_t *z0Ptr, uint64_t *z1Ptr )
|
||||
{
|
||||
@@ -370,7 +370,7 @@ INLINE void
|
||||
| `z1Ptr', and `z2Ptr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void
|
||||
static inline void
|
||||
add192(
|
||||
uint64_t a0,
|
||||
uint64_t a1,
|
||||
@@ -408,7 +408,7 @@ INLINE void
|
||||
| `z1Ptr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void
|
||||
static inline void
|
||||
sub128(
|
||||
uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, uint64_t *z0Ptr, uint64_t *z1Ptr )
|
||||
{
|
||||
@@ -426,7 +426,7 @@ INLINE void
|
||||
| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void
|
||||
static inline void
|
||||
sub192(
|
||||
uint64_t a0,
|
||||
uint64_t a1,
|
||||
@@ -462,7 +462,7 @@ INLINE void
|
||||
| `z0Ptr' and `z1Ptr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void mul64To128( uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr )
|
||||
static inline void mul64To128( uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr )
|
||||
{
|
||||
uint32_t aHigh, aLow, bHigh, bLow;
|
||||
uint64_t z0, zMiddleA, zMiddleB, z1;
|
||||
@@ -492,7 +492,7 @@ INLINE void mul64To128( uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr
|
||||
| `z2Ptr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void
|
||||
static inline void
|
||||
mul128By64To192(
|
||||
uint64_t a0,
|
||||
uint64_t a1,
|
||||
@@ -520,7 +520,7 @@ INLINE void
|
||||
| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE void
|
||||
static inline void
|
||||
mul128To256(
|
||||
uint64_t a0,
|
||||
uint64_t a1,
|
||||
@@ -702,7 +702,7 @@ static int8 countLeadingZeros64( uint64_t a )
|
||||
| Otherwise, returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE flag eq128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
|
||||
static inline flag eq128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
|
||||
{
|
||||
|
||||
return ( a0 == b0 ) && ( a1 == b1 );
|
||||
@@ -715,7 +715,7 @@ INLINE flag eq128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
|
||||
| Otherwise, returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE flag le128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
|
||||
static inline flag le128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
|
||||
{
|
||||
|
||||
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
|
||||
@@ -728,7 +728,7 @@ INLINE flag le128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
|
||||
| returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE flag lt128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
|
||||
static inline flag lt128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
|
||||
{
|
||||
|
||||
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
|
||||
@@ -741,7 +741,7 @@ INLINE flag lt128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
|
||||
| Otherwise, returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE flag ne128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
|
||||
static inline flag ne128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
|
||||
{
|
||||
|
||||
return ( a0 != b0 ) || ( a1 != b1 );
|
||||
|
@@ -66,7 +66,7 @@ these four paragraphs for those parts of this code that are retained.
|
||||
| Returns the fraction bits of the half-precision floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE uint32_t extractFloat16Frac(float16 a)
|
||||
static inline uint32_t extractFloat16Frac(float16 a)
|
||||
{
|
||||
return float16_val(a) & 0x3ff;
|
||||
}
|
||||
@@ -75,7 +75,7 @@ INLINE uint32_t extractFloat16Frac(float16 a)
|
||||
| Returns the exponent bits of the half-precision floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE int_fast16_t extractFloat16Exp(float16 a)
|
||||
static inline int_fast16_t extractFloat16Exp(float16 a)
|
||||
{
|
||||
return (float16_val(a) >> 10) & 0x1f;
|
||||
}
|
||||
@@ -84,7 +84,7 @@ INLINE int_fast16_t extractFloat16Exp(float16 a)
|
||||
| Returns the sign bit of the single-precision floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE flag extractFloat16Sign(float16 a)
|
||||
static inline flag extractFloat16Sign(float16 a)
|
||||
{
|
||||
return float16_val(a)>>15;
|
||||
}
|
||||
@@ -255,7 +255,7 @@ static int64 roundAndPackUint64(flag zSign, uint64_t absZ0,
|
||||
| Returns the fraction bits of the single-precision floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE uint32_t extractFloat32Frac( float32 a )
|
||||
static inline uint32_t extractFloat32Frac( float32 a )
|
||||
{
|
||||
|
||||
return float32_val(a) & 0x007FFFFF;
|
||||
@@ -266,7 +266,7 @@ INLINE uint32_t extractFloat32Frac( float32 a )
|
||||
| Returns the exponent bits of the single-precision floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE int_fast16_t extractFloat32Exp(float32 a)
|
||||
static inline int_fast16_t extractFloat32Exp(float32 a)
|
||||
{
|
||||
|
||||
return ( float32_val(a)>>23 ) & 0xFF;
|
||||
@@ -277,7 +277,7 @@ INLINE int_fast16_t extractFloat32Exp(float32 a)
|
||||
| Returns the sign bit of the single-precision floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE flag extractFloat32Sign( float32 a )
|
||||
static inline flag extractFloat32Sign( float32 a )
|
||||
{
|
||||
|
||||
return float32_val(a)>>31;
|
||||
@@ -328,7 +328,7 @@ static void
|
||||
| significand.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE float32 packFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig)
|
||||
static inline float32 packFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig)
|
||||
{
|
||||
|
||||
return make_float32(
|
||||
@@ -440,7 +440,7 @@ static float32
|
||||
| Returns the fraction bits of the double-precision floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE uint64_t extractFloat64Frac( float64 a )
|
||||
static inline uint64_t extractFloat64Frac( float64 a )
|
||||
{
|
||||
|
||||
return float64_val(a) & LIT64( 0x000FFFFFFFFFFFFF );
|
||||
@@ -451,7 +451,7 @@ INLINE uint64_t extractFloat64Frac( float64 a )
|
||||
| Returns the exponent bits of the double-precision floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE int_fast16_t extractFloat64Exp(float64 a)
|
||||
static inline int_fast16_t extractFloat64Exp(float64 a)
|
||||
{
|
||||
|
||||
return ( float64_val(a)>>52 ) & 0x7FF;
|
||||
@@ -462,7 +462,7 @@ INLINE int_fast16_t extractFloat64Exp(float64 a)
|
||||
| Returns the sign bit of the double-precision floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE flag extractFloat64Sign( float64 a )
|
||||
static inline flag extractFloat64Sign( float64 a )
|
||||
{
|
||||
|
||||
return float64_val(a)>>63;
|
||||
@@ -513,7 +513,7 @@ static void
|
||||
| significand.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE float64 packFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig)
|
||||
static inline float64 packFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig)
|
||||
{
|
||||
|
||||
return make_float64(
|
||||
@@ -625,7 +625,7 @@ static float64
|
||||
| value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE uint64_t extractFloatx80Frac( floatx80 a )
|
||||
static inline uint64_t extractFloatx80Frac( floatx80 a )
|
||||
{
|
||||
|
||||
return a.low;
|
||||
@@ -637,7 +637,7 @@ INLINE uint64_t extractFloatx80Frac( floatx80 a )
|
||||
| value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE int32 extractFloatx80Exp( floatx80 a )
|
||||
static inline int32 extractFloatx80Exp( floatx80 a )
|
||||
{
|
||||
|
||||
return a.high & 0x7FFF;
|
||||
@@ -649,7 +649,7 @@ INLINE int32 extractFloatx80Exp( floatx80 a )
|
||||
| `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE flag extractFloatx80Sign( floatx80 a )
|
||||
static inline flag extractFloatx80Sign( floatx80 a )
|
||||
{
|
||||
|
||||
return a.high>>15;
|
||||
@@ -679,7 +679,7 @@ static void
|
||||
| extended double-precision floating-point value, returning the result.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE floatx80 packFloatx80( flag zSign, int32 zExp, uint64_t zSig )
|
||||
static inline floatx80 packFloatx80( flag zSign, int32 zExp, uint64_t zSig )
|
||||
{
|
||||
floatx80 z;
|
||||
|
||||
@@ -921,7 +921,7 @@ static floatx80
|
||||
| floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE uint64_t extractFloat128Frac1( float128 a )
|
||||
static inline uint64_t extractFloat128Frac1( float128 a )
|
||||
{
|
||||
|
||||
return a.low;
|
||||
@@ -933,7 +933,7 @@ INLINE uint64_t extractFloat128Frac1( float128 a )
|
||||
| floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE uint64_t extractFloat128Frac0( float128 a )
|
||||
static inline uint64_t extractFloat128Frac0( float128 a )
|
||||
{
|
||||
|
||||
return a.high & LIT64( 0x0000FFFFFFFFFFFF );
|
||||
@@ -945,7 +945,7 @@ INLINE uint64_t extractFloat128Frac0( float128 a )
|
||||
| `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE int32 extractFloat128Exp( float128 a )
|
||||
static inline int32 extractFloat128Exp( float128 a )
|
||||
{
|
||||
|
||||
return ( a.high>>48 ) & 0x7FFF;
|
||||
@@ -956,7 +956,7 @@ INLINE int32 extractFloat128Exp( float128 a )
|
||||
| Returns the sign bit of the quadruple-precision floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE flag extractFloat128Sign( float128 a )
|
||||
static inline flag extractFloat128Sign( float128 a )
|
||||
{
|
||||
|
||||
return a.high>>63;
|
||||
@@ -1017,7 +1017,7 @@ static void
|
||||
| significand.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
INLINE float128
|
||||
static inline float128
|
||||
packFloat128( flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1 )
|
||||
{
|
||||
float128 z;
|
||||
@@ -7088,7 +7088,7 @@ uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM)
|
||||
}
|
||||
|
||||
#define COMPARE(s, nan_exp) \
|
||||
INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \
|
||||
static inline int float ## s ## _compare_internal( float ## s a, float ## s b, \
|
||||
int is_quiet STATUS_PARAM ) \
|
||||
{ \
|
||||
flag aSign, bSign; \
|
||||
@@ -7140,7 +7140,7 @@ int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \
|
||||
COMPARE(32, 0xff)
|
||||
COMPARE(64, 0x7ff)
|
||||
|
||||
INLINE int floatx80_compare_internal( floatx80 a, floatx80 b,
|
||||
static inline int floatx80_compare_internal( floatx80 a, floatx80 b,
|
||||
int is_quiet STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
@@ -7186,7 +7186,7 @@ int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
return floatx80_compare_internal(a, b, 1 STATUS_VAR);
|
||||
}
|
||||
|
||||
INLINE int float128_compare_internal( float128 a, float128 b,
|
||||
static inline int float128_compare_internal( float128 a, float128 b,
|
||||
int is_quiet STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
@@ -7242,7 +7242,7 @@ int float128_compare_quiet( float128 a, float128 b STATUS_PARAM )
|
||||
* semantics provided by many CPUs which predate that specification.
|
||||
*/
|
||||
#define MINMAX(s) \
|
||||
INLINE float ## s float ## s ## _minmax(float ## s a, float ## s b, \
|
||||
static inline float ## s float ## s ## _minmax(float ## s a, float ## s b, \
|
||||
int ismin, int isieee STATUS_PARAM) \
|
||||
{ \
|
||||
flag aSign, bSign; \
|
||||
|
@@ -760,7 +760,6 @@ static int proxy_socket(const char *path, uid_t uid, gid_t gid)
|
||||
return -1;
|
||||
}
|
||||
|
||||
size = sizeof(qemu);
|
||||
client = accept(sock, (struct sockaddr *)&qemu, &size);
|
||||
if (client < 0) {
|
||||
do_perror("accept");
|
||||
|
@@ -176,7 +176,7 @@ ETEXI
|
||||
|
||||
{
|
||||
.name = "drive_del",
|
||||
.args_type = "id:B",
|
||||
.args_type = "id:s",
|
||||
.params = "device",
|
||||
.help = "remove host block device",
|
||||
.user_print = monitor_user_noop,
|
||||
@@ -556,7 +556,6 @@ ETEXI
|
||||
.params = "keys [hold_ms]",
|
||||
.help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)",
|
||||
.mhandler.cmd = hmp_send_key,
|
||||
.command_completion = sendkey_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -659,7 +658,6 @@ ETEXI
|
||||
.help = "add device, like -device on the command line",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_new = do_device_add,
|
||||
.command_completion = device_add_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -675,7 +673,6 @@ ETEXI
|
||||
.params = "device",
|
||||
.help = "remove device",
|
||||
.mhandler.cmd = hmp_device_del,
|
||||
.command_completion = device_del_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1001,34 +998,26 @@ ETEXI
|
||||
|
||||
{
|
||||
.name = "dump-guest-memory",
|
||||
.args_type = "paging:-p,zlib:-z,lzo:-l,snappy:-s,filename:F,begin:i?,length:i?",
|
||||
.params = "[-p] [-z|-l|-s] filename [begin length]",
|
||||
.help = "dump guest memory into file 'filename'.\n\t\t\t"
|
||||
"-p: do paging to get guest's memory mapping.\n\t\t\t"
|
||||
"-z: dump in kdump-compressed format, with zlib compression.\n\t\t\t"
|
||||
"-l: dump in kdump-compressed format, with lzo compression.\n\t\t\t"
|
||||
"-s: dump in kdump-compressed format, with snappy compression.\n\t\t\t"
|
||||
"begin: the starting physical address.\n\t\t\t"
|
||||
"length: the memory size, in bytes.",
|
||||
.args_type = "paging:-p,filename:F,begin:i?,length:i?",
|
||||
.params = "[-p] filename [begin] [length]",
|
||||
.help = "dump guest memory to file"
|
||||
"\n\t\t\t begin(optional): the starting physical address"
|
||||
"\n\t\t\t length(optional): the memory size, in bytes",
|
||||
.mhandler.cmd = hmp_dump_guest_memory,
|
||||
},
|
||||
|
||||
|
||||
STEXI
|
||||
@item dump-guest-memory [-p] @var{filename} @var{begin} @var{length}
|
||||
@item dump-guest-memory [-z|-l|-s] @var{filename}
|
||||
@item dump-guest-memory [-p] @var{protocol} @var{begin} @var{length}
|
||||
@findex dump-guest-memory
|
||||
Dump guest memory to @var{protocol}. The file can be processed with crash or
|
||||
gdb. Without -z|-l|-s, the dump format is ELF.
|
||||
-p: do paging to get guest's memory mapping.
|
||||
-z: dump in kdump-compressed format, with zlib compression.
|
||||
-l: dump in kdump-compressed format, with lzo compression.
|
||||
-s: dump in kdump-compressed format, with snappy compression.
|
||||
filename: dump file name.
|
||||
gdb.
|
||||
filename: dump file name
|
||||
paging: do paging to get guest's memory mapping
|
||||
begin: the starting physical address. It's optional, and should be
|
||||
specified together with length.
|
||||
specified with length together.
|
||||
length: the memory size, in bytes. It's optional, and should be specified
|
||||
together with begin.
|
||||
with begin together.
|
||||
ETEXI
|
||||
|
||||
{
|
||||
@@ -1234,10 +1223,9 @@ ETEXI
|
||||
{
|
||||
.name = "netdev_add",
|
||||
.args_type = "netdev:O",
|
||||
.params = "[user|tap|socket|vde|bridge|hubport|netmap],id=str[,prop=value][,...]",
|
||||
.params = "[user|tap|socket|hubport|netmap],id=str[,prop=value][,...]",
|
||||
.help = "add host network device",
|
||||
.mhandler.cmd = hmp_netdev_add,
|
||||
.command_completion = netdev_add_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1252,7 +1240,6 @@ ETEXI
|
||||
.params = "id",
|
||||
.help = "remove host network device",
|
||||
.mhandler.cmd = hmp_netdev_del,
|
||||
.command_completion = netdev_del_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1267,7 +1254,6 @@ ETEXI
|
||||
.params = "[qom-type=]type,id=str[,prop=value][,...]",
|
||||
.help = "create QOM object",
|
||||
.mhandler.cmd = hmp_object_add,
|
||||
.command_completion = object_add_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1282,7 +1268,6 @@ ETEXI
|
||||
.params = "id",
|
||||
.help = "destroy QOM object",
|
||||
.mhandler.cmd = hmp_object_del,
|
||||
.command_completion = object_del_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1342,7 +1327,6 @@ ETEXI
|
||||
.params = "name on|off",
|
||||
.help = "change the link status of a network adapter",
|
||||
.mhandler.cmd = hmp_set_link,
|
||||
.command_completion = set_link_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1626,7 +1610,6 @@ ETEXI
|
||||
.params = "args",
|
||||
.help = "add chardev",
|
||||
.mhandler.cmd = hmp_chardev_add,
|
||||
.command_completion = chardev_add_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1643,7 +1626,6 @@ ETEXI
|
||||
.params = "id",
|
||||
.help = "remove chardev",
|
||||
.mhandler.cmd = hmp_chardev_remove,
|
||||
.command_completion = chardev_remove_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
|
185
hmp.c
185
hmp.c
@@ -28,8 +28,7 @@
|
||||
|
||||
static void hmp_handle_error(Monitor *mon, Error **errp)
|
||||
{
|
||||
assert(errp);
|
||||
if (*errp) {
|
||||
if (error_is_set(errp)) {
|
||||
monitor_printf(mon, "%s\n", error_get_pretty(*errp));
|
||||
error_free(*errp);
|
||||
}
|
||||
@@ -189,8 +188,6 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
||||
info->ram->normal);
|
||||
monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n",
|
||||
info->ram->normal_bytes >> 10);
|
||||
monitor_printf(mon, "dirty sync count: %" PRIu64 "\n",
|
||||
info->ram->dirty_sync_count);
|
||||
if (info->ram->dirty_pages_rate) {
|
||||
monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n",
|
||||
info->ram->dirty_pages_rate);
|
||||
@@ -215,8 +212,6 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
||||
info->xbzrle_cache->pages);
|
||||
monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
|
||||
info->xbzrle_cache->cache_miss);
|
||||
monitor_printf(mon, "xbzrle cache miss rate: %0.2f\n",
|
||||
info->xbzrle_cache->cache_miss_rate);
|
||||
monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
|
||||
info->xbzrle_cache->overflow);
|
||||
}
|
||||
@@ -341,11 +336,6 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
|
||||
info->value->inserted->backing_file_depth);
|
||||
}
|
||||
|
||||
if (info->value->inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
|
||||
monitor_printf(mon, " Detect zeroes: %s\n",
|
||||
BlockdevDetectZeroesOptions_lookup[info->value->inserted->detect_zeroes]);
|
||||
}
|
||||
|
||||
if (info->value->inserted->bps
|
||||
|| info->value->inserted->bps_rd
|
||||
|| info->value->inserted->bps_wr
|
||||
@@ -760,10 +750,10 @@ void hmp_memsave(Monitor *mon, const QDict *qdict)
|
||||
uint32_t size = qdict_get_int(qdict, "size");
|
||||
const char *filename = qdict_get_str(qdict, "filename");
|
||||
uint64_t addr = qdict_get_int(qdict, "val");
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_memsave(addr, size, filename, true, monitor_get_cpu_index(), &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
qmp_memsave(addr, size, filename, true, monitor_get_cpu_index(), &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_pmemsave(Monitor *mon, const QDict *qdict)
|
||||
@@ -771,21 +761,21 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict)
|
||||
uint32_t size = qdict_get_int(qdict, "size");
|
||||
const char *filename = qdict_get_str(qdict, "filename");
|
||||
uint64_t addr = qdict_get_int(qdict, "val");
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_pmemsave(addr, size, filename, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
qmp_pmemsave(addr, size, filename, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_ringbuf_write(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *chardev = qdict_get_str(qdict, "device");
|
||||
const char *data = qdict_get_str(qdict, "data");
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_ringbuf_write(chardev, data, false, 0, &err);
|
||||
qmp_ringbuf_write(chardev, data, false, 0, &errp);
|
||||
|
||||
hmp_handle_error(mon, &err);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_ringbuf_read(Monitor *mon, const QDict *qdict)
|
||||
@@ -793,13 +783,13 @@ void hmp_ringbuf_read(Monitor *mon, const QDict *qdict)
|
||||
uint32_t size = qdict_get_int(qdict, "size");
|
||||
const char *chardev = qdict_get_str(qdict, "device");
|
||||
char *data;
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
int i;
|
||||
|
||||
data = qmp_ringbuf_read(chardev, size, false, 0, &err);
|
||||
if (err) {
|
||||
monitor_printf(mon, "%s\n", error_get_pretty(err));
|
||||
error_free(err);
|
||||
data = qmp_ringbuf_read(chardev, size, false, 0, &errp);
|
||||
if (errp) {
|
||||
monitor_printf(mon, "%s\n", error_get_pretty(errp));
|
||||
error_free(errp);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -834,7 +824,7 @@ static bool key_is_missing(const BlockInfo *bdev)
|
||||
void hmp_cont(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
BlockInfoList *bdev_list, *bdev;
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
bdev_list = qmp_query_block(NULL);
|
||||
for (bdev = bdev_list; bdev; bdev = bdev->next) {
|
||||
@@ -845,8 +835,8 @@ void hmp_cont(Monitor *mon, const QDict *qdict)
|
||||
}
|
||||
}
|
||||
|
||||
qmp_cont(&err);
|
||||
hmp_handle_error(mon, &err);
|
||||
qmp_cont(&errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
|
||||
out:
|
||||
qapi_free_BlockInfoList(bdev_list);
|
||||
@@ -859,41 +849,41 @@ void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
|
||||
|
||||
void hmp_inject_nmi(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_inject_nmi(&err);
|
||||
hmp_handle_error(mon, &err);
|
||||
qmp_inject_nmi(&errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_set_link(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *name = qdict_get_str(qdict, "name");
|
||||
int up = qdict_get_bool(qdict, "up");
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_set_link(name, up, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
qmp_set_link(name, up, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_block_passwd(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *device = qdict_get_str(qdict, "device");
|
||||
const char *password = qdict_get_str(qdict, "password");
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_block_passwd(true, device, false, NULL, password, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
qmp_block_passwd(true, device, false, NULL, password, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_balloon(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
int64_t value = qdict_get_int(qdict, "value");
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_balloon(value, &err);
|
||||
if (err) {
|
||||
monitor_printf(mon, "balloon: %s\n", error_get_pretty(err));
|
||||
error_free(err);
|
||||
qmp_balloon(value, &errp);
|
||||
if (errp) {
|
||||
monitor_printf(mon, "balloon: %s\n", error_get_pretty(errp));
|
||||
error_free(errp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -901,10 +891,10 @@ void hmp_block_resize(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *device = qdict_get_str(qdict, "device");
|
||||
int64_t size = qdict_get_int(qdict, "size");
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_block_resize(true, device, false, NULL, size, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
qmp_block_resize(true, device, false, NULL, size, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
||||
@@ -915,11 +905,11 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
||||
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
|
||||
int full = qdict_get_try_bool(qdict, "full", 0);
|
||||
enum NewImageMode mode;
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
if (!filename) {
|
||||
error_set(&err, QERR_MISSING_PARAMETER, "target");
|
||||
hmp_handle_error(mon, &err);
|
||||
error_set(&errp, QERR_MISSING_PARAMETER, "target");
|
||||
hmp_handle_error(mon, &errp);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -932,8 +922,8 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
||||
qmp_drive_mirror(device, filename, !!format, format,
|
||||
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
||||
true, mode, false, 0, false, 0, false, 0,
|
||||
false, 0, false, 0, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
false, 0, false, 0, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
||||
@@ -944,11 +934,11 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
||||
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
|
||||
int full = qdict_get_try_bool(qdict, "full", 0);
|
||||
enum NewImageMode mode;
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
if (!filename) {
|
||||
error_set(&err, QERR_MISSING_PARAMETER, "target");
|
||||
hmp_handle_error(mon, &err);
|
||||
error_set(&errp, QERR_MISSING_PARAMETER, "target");
|
||||
hmp_handle_error(mon, &errp);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -960,8 +950,8 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
||||
|
||||
qmp_drive_backup(device, filename, !!format, format,
|
||||
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
||||
true, mode, false, 0, false, 0, false, 0, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
true, mode, false, 0, false, 0, false, 0, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
|
||||
@@ -971,13 +961,13 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
|
||||
const char *format = qdict_get_try_str(qdict, "format");
|
||||
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
|
||||
enum NewImageMode mode;
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
if (!filename) {
|
||||
/* In the future, if 'snapshot-file' is not specified, the snapshot
|
||||
will be taken internally. Today it's actually required. */
|
||||
error_set(&err, QERR_MISSING_PARAMETER, "snapshot-file");
|
||||
hmp_handle_error(mon, &err);
|
||||
error_set(&errp, QERR_MISSING_PARAMETER, "snapshot-file");
|
||||
hmp_handle_error(mon, &errp);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -985,18 +975,18 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
|
||||
qmp_blockdev_snapshot_sync(true, device, false, NULL,
|
||||
filename, false, NULL,
|
||||
!!format, format,
|
||||
true, mode, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
true, mode, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *device = qdict_get_str(qdict, "device");
|
||||
const char *name = qdict_get_str(qdict, "name");
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_blockdev_snapshot_internal_sync(device, name, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
qmp_blockdev_snapshot_internal_sync(device, name, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
|
||||
@@ -1004,11 +994,11 @@ void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
|
||||
const char *device = qdict_get_str(qdict, "device");
|
||||
const char *name = qdict_get_str(qdict, "name");
|
||||
const char *id = qdict_get_try_str(qdict, "id");
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_blockdev_snapshot_delete_internal_sync(device, !!id, id,
|
||||
true, name, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
true, name, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
|
||||
@@ -1316,37 +1306,18 @@ void hmp_device_del(Monitor *mon, const QDict *qdict)
|
||||
|
||||
void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
int paging = qdict_get_try_bool(qdict, "paging", 0);
|
||||
int zlib = qdict_get_try_bool(qdict, "zlib", 0);
|
||||
int lzo = qdict_get_try_bool(qdict, "lzo", 0);
|
||||
int snappy = qdict_get_try_bool(qdict, "snappy", 0);
|
||||
const char *file = qdict_get_str(qdict, "filename");
|
||||
bool has_begin = qdict_haskey(qdict, "begin");
|
||||
bool has_length = qdict_haskey(qdict, "length");
|
||||
/* kdump-compressed format is not supported for HMP */
|
||||
bool has_format = false;
|
||||
int64_t begin = 0;
|
||||
int64_t length = 0;
|
||||
enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
|
||||
char *prot;
|
||||
|
||||
if (zlib + lzo + snappy > 1) {
|
||||
error_setg(&err, "only one of '-z|-l|-s' can be set");
|
||||
hmp_handle_error(mon, &err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (zlib) {
|
||||
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB;
|
||||
}
|
||||
|
||||
if (lzo) {
|
||||
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO;
|
||||
}
|
||||
|
||||
if (snappy) {
|
||||
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY;
|
||||
}
|
||||
|
||||
if (has_begin) {
|
||||
begin = qdict_get_int(qdict, "begin");
|
||||
}
|
||||
@@ -1357,8 +1328,8 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
||||
prot = g_strconcat("file:", file, NULL);
|
||||
|
||||
qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
|
||||
true, dump_format, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
has_format, dump_format, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
g_free(prot);
|
||||
}
|
||||
|
||||
@@ -1393,7 +1364,6 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict)
|
||||
void hmp_object_add(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *err = NULL;
|
||||
Error *err_end = NULL;
|
||||
QemuOpts *opts;
|
||||
char *type = NULL;
|
||||
char *id = NULL;
|
||||
@@ -1417,23 +1387,24 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
|
||||
qdict_del(pdict, "qom-type");
|
||||
visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err);
|
||||
if (err) {
|
||||
goto out_end;
|
||||
goto out_clean;
|
||||
}
|
||||
|
||||
qdict_del(pdict, "id");
|
||||
visit_type_str(opts_get_visitor(ov), &id, "id", &err);
|
||||
if (err) {
|
||||
goto out_end;
|
||||
goto out_clean;
|
||||
}
|
||||
|
||||
object_add(type, id, pdict, opts_get_visitor(ov), &err);
|
||||
|
||||
out_end:
|
||||
visit_end_struct(opts_get_visitor(ov), &err_end);
|
||||
if (!err && err_end) {
|
||||
if (err) {
|
||||
goto out_clean;
|
||||
}
|
||||
visit_end_struct(opts_get_visitor(ov), &err);
|
||||
if (err) {
|
||||
qmp_object_del(id, NULL);
|
||||
}
|
||||
error_propagate(&err, err_end);
|
||||
|
||||
out_clean:
|
||||
opts_visitor_cleanup(ov);
|
||||
|
||||
@@ -1450,19 +1421,19 @@ out:
|
||||
void hmp_getfd(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *fdname = qdict_get_str(qdict, "fdname");
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_getfd(fdname, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
qmp_getfd(fdname, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_closefd(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *fdname = qdict_get_str(qdict, "fdname");
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_closefd(fdname, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
qmp_closefd(fdname, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_send_key(Monitor *mon, const QDict *qdict)
|
||||
@@ -1612,10 +1583,10 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict)
|
||||
|
||||
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *err = NULL;
|
||||
Error *errp = NULL;
|
||||
|
||||
qmp_nbd_server_stop(&err);
|
||||
hmp_handle_error(mon, &err);
|
||||
qmp_nbd_server_stop(&errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_cpu_add(Monitor *mon, const QDict *qdict)
|
||||
|
11
hmp.h
11
hmp.h
@@ -15,7 +15,6 @@
|
||||
#define HMP_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/readline.h"
|
||||
#include "qapi-types.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
|
||||
@@ -93,15 +92,5 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict);
|
||||
void hmp_cpu_add(Monitor *mon, const QDict *qdict);
|
||||
void hmp_object_add(Monitor *mon, const QDict *qdict);
|
||||
void hmp_object_del(Monitor *mon, const QDict *qdict);
|
||||
void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void device_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void sendkey_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void set_link_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
|
||||
#endif
|
||||
|
@@ -34,7 +34,7 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
|
||||
|
||||
len = strlen(s->tag);
|
||||
cfg = g_malloc0(sizeof(struct virtio_9p_config) + len);
|
||||
stw_p(&cfg->tag_len, len);
|
||||
stw_raw(&cfg->tag_len, len);
|
||||
/* We don't copy the terminating null to config space */
|
||||
memcpy(cfg->tag, s->tag, len);
|
||||
memcpy(config, cfg, s->config_size);
|
||||
|
@@ -14,7 +14,6 @@
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "virtio-9p.h"
|
||||
#include "virtio-9p-xattr.h"
|
||||
#include "fsdev/qemu-fsdev.h" /* local_ops */
|
||||
#include <arpa/inet.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user