Merge commit 'b1999e8' into xbox

Conflicts:
	blockdev.c
	configure
	hw/pci/pci_ids.h
	qemu-config.c
This commit is contained in:
espes 2013-03-19 05:21:23 +11:00
commit 82a4db30c9
1222 changed files with 67279 additions and 31751 deletions

13
.gitignore vendored
View File

@ -3,10 +3,11 @@ config-all-devices.*
config-all-disas.*
config-host.*
config-target.*
trace.h
trace.c
trace-dtrace.h
trace-dtrace.dtrace
trace/generated-tracers.h
trace/generated-tracers.c
trace/generated-tracers-dtrace.h
trace/generated-tracers-dtrace.dtrace
libcacard/trace/generated-tracers.c
*-timestamp
*-softmmu
*-darwin-user
@ -70,6 +71,7 @@ fsdev/virtfs-proxy-helper.pod
*.tp
*.vr
*.d
!scripts/qemu-guest-agent/fsfreeze-hook.d
*.o
*.lo
*.la
@ -81,12 +83,15 @@ fsdev/virtfs-proxy-helper.pod
patches
pc-bios/bios-pq/status
pc-bios/vgabios-pq/status
pc-bios/optionrom/linuxboot.asm
pc-bios/optionrom/linuxboot.bin
pc-bios/optionrom/linuxboot.raw
pc-bios/optionrom/linuxboot.img
pc-bios/optionrom/multiboot.asm
pc-bios/optionrom/multiboot.bin
pc-bios/optionrom/multiboot.raw
pc-bios/optionrom/multiboot.img
pc-bios/optionrom/kvmvapic.asm
pc-bios/optionrom/kvmvapic.bin
pc-bios/optionrom/kvmvapic.raw
pc-bios/optionrom/kvmvapic.img

View File

@ -98,6 +98,7 @@ S: Maintained
F: target-ppc/
S390
M: Richard Henderson <rth@twiddle.net>
M: Alexander Graf <agraf@suse.de>
S: Maintained
F: target-s390x/
@ -132,13 +133,18 @@ Guest CPU Cores (KVM):
----------------------
Overall
M: Avi Kivity <avi@redhat.com>
M: Gleb Natapov <gleb@redhat.com>
M: Marcelo Tosatti <mtosatti@redhat.com>
L: kvm@vger.kernel.org
S: Supported
F: kvm-*
F: */kvm.*
ARM
M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
F: target-arm/kvm.c
PPC
M: Alexander Graf <agraf@suse.de>
S: Maintained
@ -150,7 +156,7 @@ S: Maintained
F: target-s390x/kvm.c
X86
M: Avi Kivity <avi@redhat.com>
M: Gleb Natapov <gleb@redhat.com>
M: Marcelo Tosatti <mtosatti@redhat.com>
L: kvm@vger.kernel.org
S: Supported
@ -379,7 +385,7 @@ New World
M: Alexander Graf <agraf@suse.de>
L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc_newworld.c
F: hw/ppc/mac_newworld.c
F: hw/unin_pci.c
F: hw/dec_pci.[hc]
@ -387,15 +393,16 @@ Old World
M: Alexander Graf <agraf@suse.de>
L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc_oldworld.c
F: hw/ppc/mac_oldworld.c
F: hw/grackle_pci.c
PReP
M: Andreas Färber <andreas.faerber@web.de>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc_prep.c
F: hw/ppc/prep.c
F: hw/prep_pci.[hc]
F: hw/pc87312.[hc]
sPAPR
M: David Gibson <david@gibson.dropbear.id.au>
@ -447,6 +454,14 @@ M: Alexander Graf <agraf@suse.de>
S: Maintained
F: hw/s390-*.c
S390 Virtio-ccw
M: Cornelia Huck <cornelia.huck@de.ibm.com>
M: Alexander Graf <agraf@suse.de>
S: Supported
F: hw/s390x/s390-virtio-ccw.c
F: hw/s390x/css.[hc]
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
UniCore32 Machines
-------------
PKUnity-3 SoC initramfs-with-busybox
@ -558,6 +573,12 @@ M: Stefan Hajnoczi <stefanha@redhat.com>
S: Supported
F: hw/virtio-blk*
virtio-ccw
M: Cornelia Huck <cornelia.huck@de.ibm.com>
S: Supported
F: hw/s390x/virtio-ccw.[hc]
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
virtio-serial
M: Amit Shah <amit.shah@redhat.com>
S: Supported
@ -600,6 +621,7 @@ M: Andreas Färber <afaerber@suse.de>
S: Supported
F: qom/cpu.c
F: include/qemu/cpu.h
F: target-i386/cpu.c
Device Tree
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>

View File

@ -31,12 +31,15 @@ ifneq ($(filter-out %clean,$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail))
endif
endif
GENERATED_HEADERS = config-host.h trace.h qemu-options.def
ifeq ($(TRACE_BACKEND),dtrace)
GENERATED_HEADERS += trace-dtrace.h
endif
GENERATED_HEADERS = config-host.h qemu-options.def
GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h
GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c trace.c
GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c
GENERATED_HEADERS += trace/generated-tracers.h
ifeq ($(TRACE_BACKEND),dtrace)
GENERATED_HEADERS += trace/generated-tracers-dtrace.h
endif
GENERATED_SOURCES += trace/generated-tracers.c
# Don't try to regenerate Makefile or configure
# We don't generate any of them
@ -63,7 +66,7 @@ endif
SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR)
SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS))
SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %-config-devices.mak.d, $(TARGET_DIRS))
ifeq ($(SUBDIR_DEVICES_MAK),)
config-all-devices.mak:
@ -100,6 +103,17 @@ defconfig:
-include config-all-devices.mak
-include config-all-disas.mak
CONFIG_SOFTMMU := $(if $(filter %-softmmu,$(TARGET_DIRS)),y)
CONFIG_USER_ONLY := $(if $(filter %-user,$(TARGET_DIRS)),y)
CONFIG_ALL=y
ifneq ($(wildcard config-host.mak),)
include $(SRC_PATH)/Makefile.objs
include $(SRC_PATH)/tests/Makefile
endif
ifeq ($(CONFIG_SMARTCARD_NSS),y)
include $(SRC_PATH)/libcacard/Makefile
endif
all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all
@ -109,30 +123,23 @@ qemu-options.def: $(SRC_PATH)/qemu-options.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@")
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
subdir-%:
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
ifneq ($(wildcard config-host.mak),)
include $(SRC_PATH)/Makefile.objs
endif
subdir-libcacard: $(oslib-obj-y) $(trace-obj-y) qemu-timer-common.o
subdir-pixman: pixman/Makefile
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pixman V="$(V)" all,)
pixman/Makefile: $(SRC_PATH)/pixman/configure
(cd pixman; CFLAGS="$(CFLAGS) -fPIC" $(SRC_PATH)/pixman/configure $(AUTOCONF_HOST) --disable-gtk --disable-shared --enable-static)
(cd pixman; CFLAGS="$(CFLAGS) -fPIC $(extra_cflags) $(extra_ldflags)" $(SRC_PATH)/pixman/configure $(AUTOCONF_HOST) --disable-gtk --disable-shared --enable-static)
$(SRC_PATH)/pixman/configure:
(cd $(SRC_PATH)/pixman; autoreconf -v --install)
$(SUBDIR_RULES): libqemustub.a
$(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(common-obj-y) $(extra-obj-y)
$(filter %-user,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(user-obj-y)
$(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y)
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
romsubdir-%:
@ -148,41 +155,25 @@ version.o: $(SRC_PATH)/version.rc config-host.h
$(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@")
version-obj-$(CONFIG_WIN32) += version.o
Makefile: $(version-obj-y)
######################################################################
# Build library with stubs
# Build libraries
libqemustub.a: $(stub-obj-y)
######################################################################
# Support building shared library libcacard
.PHONY: libcacard.la install-libcacard
libcacard.la: $(oslib-obj-y) qemu-timer-common.o $(trace-obj-y)
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" libcacard.la,)
install-libcacard: libcacard.la
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,)
libqemuutil.a: $(util-obj-y)
######################################################################
qemu-img.o: qemu-img-cmds.h
tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
main-loop.o iohandler.o error.o
tools-obj-$(CONFIG_POSIX) += compatfd.o
qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) libqemustub.a
qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) libqemustub.a
qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) libqemustub.a
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a
qemu-io$(EXESUF): qemu-io.o cmd.o $(block-obj-y) libqemuutil.a libqemustub.a
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
vscclient$(EXESUF): LIBS += $(libcacard_libs)
vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) libcacard/vscclient.o libqemustub.a
$(call LINK, $^)
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o libqemuutil.a libqemustub.a
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
@ -193,10 +184,6 @@ qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated
gen-out-type = $(subst .,-,$(suffix $@))
ifneq ($(wildcard config-host.mak),)
include $(SRC_PATH)/tests/Makefile
endif
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 :\
@ -222,26 +209,27 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
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)
qemu-ga$(EXESUF): $(qga-obj-y) $(oslib-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) libqemustub.a
qemu-ga$(EXESUF): $(qga-obj-y) libqemuutil.a libqemustub.a
$(call LINK, $^)
clean:
# avoid old build problems by removing potentially incorrect old files
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
rm -f qemu-options.def
find . -name '*.[od]' -exec rm -f {} +
rm -f *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
find . -name '*.[oda]' -type f -exec rm -f {} +
find . -name '*.l[oa]' -type f -exec rm -f {} +
rm -f $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
rm -Rf .libs
rm -f qemu-img-cmds.h
rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
@# May not be present in GENERATED_HEADERS
rm -f trace-dtrace.h trace-dtrace.h-timestamp
rm -f trace/generated-tracers-dtrace.dtrace*
rm -f trace/generated-tracers-dtrace.h*
rm -f $(foreach f,$(GENERATED_HEADERS),$(f) $(f)-timestamp)
rm -f $(foreach f,$(GENERATED_SOURCES),$(f) $(f)-timestamp)
rm -rf qapi-generated
rm -rf qga/qapi-generated
$(MAKE) -C tests/tcg clean
for d in $(ALL_SUBDIRS) libcacard; do \
for d in $(ALL_SUBDIRS); do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
rm -f $$d/qemu-options.def; \
done
@ -277,6 +265,7 @@ bepo
ifdef INSTALL_BLOBS
BLOBS=bios.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
acpi-dsdt.aml q35-acpi-dsdt.aml \
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
@ -327,6 +316,9 @@ ifneq ($(BLOBS),)
set -e; for x in $(BLOBS); do \
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
done
endif
ifeq ($(CONFIG_GTK),y)
$(MAKE) -C po $@
endif
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
set -e; for x in $(KEYMAPS); do \
@ -342,7 +334,8 @@ test speed: all
.PHONY: TAGS
TAGS:
find "$(SRC_PATH)" -name '*.[hc]' -print0 | xargs -0 etags
rm -f $@
find "$(SRC_PATH)" -name '*.[hc]' -exec etags --append {} +
cscope:
rm -f ./cscope.*

View File

@ -1,58 +1,31 @@
#######################################################################
# Stub library, linked in tools
# Common libraries for tools and emulators
stub-obj-y = stubs/
#######################################################################
# Target-independent parts used in system and user emulation
universal-obj-y =
universal-obj-y += qemu-log.o
#######################################################################
# QObject
qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
qobject-obj-y += qerror.o error.o qemu-error.o
universal-obj-y += $(qobject-obj-y)
#######################################################################
# QOM
qom-obj-y = qom/
universal-obj-y += $(qom-obj-y)
#######################################################################
# oslib-obj-y is code depending on the OS (win32 vs posix)
oslib-obj-y = osdep.o cutils.o qemu-timer-common.o
oslib-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o
oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
#######################################################################
# coroutines
coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
coroutine-obj-y += qemu-coroutine-sleep.o
ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
else
ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y)
coroutine-obj-$(CONFIG_POSIX) += coroutine-sigaltstack.o
else
coroutine-obj-$(CONFIG_POSIX) += coroutine-gthread.o
endif
endif
coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o
util-obj-y = util/ qobject/ qapi/ trace/
#######################################################################
# block-obj-y is code used by both qemu system emulation and qemu-img
block-obj-y = iov.o cache-utils.o qemu-option.o module.o async.o
block-obj-y += nbd.o block.o blockjob.o aes.o qemu-config.o
block-obj-y += thread-pool.o qemu-progress.o qemu-sockets.o uri.o notify.o
block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
block-obj-$(CONFIG_POSIX) += event_notifier-posix.o aio-posix.o
block-obj-$(CONFIG_WIN32) += event_notifier-win32.o aio-win32.o
block-obj-y = async.o thread-pool.o
block-obj-y += nbd.o block.o blockjob.o
block-obj-y += main-loop.o iohandler.o qemu-timer.o
block-obj-$(CONFIG_POSIX) += aio-posix.o
block-obj-$(CONFIG_WIN32) += aio-win32.o
block-obj-y += block/
block-obj-y += $(qapi-obj-y) qapi-types.o qapi-visit.o
block-obj-y += qapi-types.o qapi-visit.o
block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
block-obj-y += qemu-coroutine-sleep.o
ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
block-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
else
ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y)
block-obj-$(CONFIG_POSIX) += coroutine-sigaltstack.o
else
block-obj-$(CONFIG_POSIX) += coroutine-gthread.o
endif
endif
block-obj-$(CONFIG_WIN32) += coroutine-win32.o
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
@ -60,142 +33,6 @@ ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
CONFIG_REALLY_VIRTFS=y
endif
######################################################################
# Target independent part of system emulation. The long term path is to
# suppress *all* target specific code in case of system emulation, i.e. a
# single QEMU executable should support all CPUs and machines.
common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/
common-obj-y += net/
common-obj-y += qom/
common-obj-y += readline.o
common-obj-y += $(oslib-obj-y)
common-obj-$(CONFIG_WIN32) += os-win32.o
common-obj-$(CONFIG_POSIX) += os-posix.o
common-obj-$(CONFIG_LINUX) += fsdev/
extra-obj-$(CONFIG_LINUX) += fsdev/
common-obj-y += tcg-runtime.o host-utils.o main-loop.o
common-obj-y += migration.o migration-tcp.o
common-obj-y += migration.o migration-tcp.o
common-obj-y += qemu-char.o #aio.o
common-obj-y += block-migration.o iohandler.o
common-obj-y += bitmap.o bitops.o
common-obj-y += page_cache.o
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
common-obj-$(CONFIG_WIN32) += version.o
common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
common-obj-y += audio/
common-obj-y += hw/
extra-obj-y += hw/
common-obj-y += ui/
common-obj-y += bt-host.o bt-vhci.o
common-obj-y += dma-helpers.o
common-obj-y += acl.o
common-obj-$(CONFIG_POSIX) += compatfd.o
common-obj-y += qemu-timer.o qemu-timer-common.o
common-obj-y += qtest.o
common-obj-y += vl.o
common-obj-$(CONFIG_SLIRP) += slirp/
common-obj-y += backends/
######################################################################
# libseccomp
ifeq ($(CONFIG_SECCOMP),y)
common-obj-y += qemu-seccomp.o
endif
######################################################################
# libuser
user-obj-y =
user-obj-y += envlist.o path.o
user-obj-y += tcg-runtime.o host-utils.o
user-obj-y += cache-utils.o
user-obj-y += module.o
user-obj-y += qemu-user.o
user-obj-y += qom/
######################################################################
# disassemblers
# NOTE: the disassembler code is only needed for debugging
universal-obj-y += disas/
######################################################################
# trace
ifeq ($(TRACE_BACKEND),dtrace)
TRACE_H_EXTRA_DEPS=trace-dtrace.h
endif
trace.h: trace.h-timestamp $(TRACE_H_EXTRA_DEPS)
trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
$(call quiet-command,$(TRACETOOL) \
--format=h \
--backend=$(TRACE_BACKEND) \
< $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ trace.h
trace.c: trace.c-timestamp
trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
$(call quiet-command,$(TRACETOOL) \
--format=c \
--backend=$(TRACE_BACKEND) \
< $< > $@," GEN trace.c")
@cmp -s $@ trace.c || cp $@ trace.c
trace.o: trace.c $(GENERATED_HEADERS)
trace-dtrace.h: trace-dtrace.dtrace
$(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h")
# Normal practice is to name DTrace probe file with a '.d' extension
# but that gets picked up by QEMU's Makefile as an external dependency
# rule file. So we use '.dtrace' instead
trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
$(call quiet-command,$(TRACETOOL) \
--format=d \
--backend=$(TRACE_BACKEND) \
< $< > $@," GEN trace-dtrace.dtrace")
@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
$(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o")
ifeq ($(LIBTOOL),)
trace-dtrace.lo: trace-dtrace.dtrace
@echo "missing libtool. please install and rerun configure."; exit 1
else
trace-dtrace.lo: trace-dtrace.dtrace
$(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC dtrace -o $@ -G -s $<, " lt GEN trace-dtrace.o")
endif
trace/simple.o: trace/simple.c $(GENERATED_HEADERS)
trace-obj-$(CONFIG_TRACE_DTRACE) += trace-dtrace.o
ifneq ($(TRACE_BACKEND),dtrace)
trace-obj-y = trace.o
endif
trace-obj-$(CONFIG_TRACE_DEFAULT) += trace/default.o
trace-obj-$(CONFIG_TRACE_SIMPLE) += trace/simple.o
trace-obj-$(CONFIG_TRACE_SIMPLE) += qemu-timer-common.o
trace-obj-$(CONFIG_TRACE_STDERR) += trace/stderr.o
trace-obj-y += trace/control.o
$(trace-obj-y): $(GENERATED_HEADERS)
universal-obj-y += $(trace-obj-y)
######################################################################
# smartcard
@ -205,24 +42,69 @@ libcacard-y += libcacard/vcard_emul_nss.o
libcacard-y += libcacard/vcard_emul_type.o
libcacard-y += libcacard/card_7816.o
######################################################################
# Target independent part of system emulation. The long term path is to
# suppress *all* target specific code in case of system emulation, i.e. a
# single QEMU executable should support all CPUs and machines.
ifeq ($(CONFIG_SOFTMMU),y)
common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/
common-obj-y += net/
common-obj-y += readline.o
common-obj-y += qdev-monitor.o device-hotplug.o
common-obj-$(CONFIG_WIN32) += os-win32.o
common-obj-$(CONFIG_POSIX) += os-posix.o
common-obj-$(CONFIG_LINUX) += fsdev/
common-obj-y += migration.o migration-tcp.o
common-obj-y += qemu-char.o #aio.o
common-obj-y += block-migration.o
common-obj-y += page_cache.o xbzrle.o
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
common-obj-y += audio/
common-obj-y += hw/
common-obj-y += ui/
common-obj-y += bt-host.o bt-vhci.o
common-obj-y += dma-helpers.o
common-obj-y += vl.o
common-obj-y += tpm/
common-obj-$(CONFIG_SLIRP) += slirp/
common-obj-y += backends/
common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o
common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
######################################################################
# qapi
qapi-obj-y = qapi/
qapi-obj-y += qapi-types.o qapi-visit.o
common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o
common-obj-y += qmp.o hmp.o
endif
universal-obj-y += $(qapi-obj-y)
#######################################################################
# Target-independent parts used in system and user emulation
common-obj-y += qemu-log.o
common-obj-y += tcg-runtime.o
common-obj-y += hw/
common-obj-y += qom/
common-obj-y += disas/
######################################################################
# guest agent
qga-obj-y = qga/ module.o qemu-tool.o
qga-obj-$(CONFIG_POSIX) += qemu-sockets.o qemu-option.o
# FIXME: a few definitions from qapi-types.o/qapi-visit.o are needed
# by libqemuutil.a. These should be moved to a separate .json schema.
qga-obj-y = qga/ qapi-types.o qapi-visit.o
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
@ -232,12 +114,8 @@ QEMU_CFLAGS+=$(GLIB_CFLAGS)
nested-vars += \
stub-obj-y \
util-obj-y \
qga-obj-y \
qom-obj-y \
qapi-obj-y \
block-obj-y \
user-obj-y \
common-obj-y \
universal-obj-y \
extra-obj-y
common-obj-y
dummy := $(call unnest-vars)

View File

@ -54,7 +54,7 @@ $(QEMU_PROG).stp: $(SRC_PATH)/trace-events
--binary=$(bindir)/$(QEMU_PROG) \
--target-arch=$(TARGET_ARCH) \
--target-type=$(TARGET_TYPE) \
< $< > $@," GEN $(QEMU_PROG).stp")
< $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG).stp")
else
stap:
endif
@ -69,13 +69,12 @@ all: $(PROGS) stap
obj-y = exec.o translate-all.o cpu-exec.o
obj-y += tcg/tcg.o tcg/optimize.o
obj-$(CONFIG_TCG_INTERPRETER) += tci.o
obj-$(CONFIG_TCG_INTERPRETER) += disas/tci.o
obj-y += fpu/softfloat.o
obj-y += target-$(TARGET_BASE_ARCH)/
obj-y += disas.o
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
tci-dis.o: QEMU_CFLAGS += -I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/tci
#########################################################
# Linux user emulator target
@ -84,7 +83,7 @@ ifdef CONFIG_LINUX_USER
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user
obj-y += linux-user/
obj-y += gdbstub.o thunk.o user-exec.o $(oslib-obj-y)
obj-y += gdbstub.o thunk.o user-exec.o
endif #CONFIG_LINUX_USER
@ -96,7 +95,7 @@ ifdef CONFIG_BSD_USER
QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH)
obj-y += bsd-user/
obj-y += gdbstub.o user-exec.o $(oslib-obj-y)
obj-y += gdbstub.o user-exec.o
endif #CONFIG_BSD_USER
@ -110,7 +109,9 @@ CONFIG_NO_GET_MEMORY_MAPPING = $(if $(subst n,,$(CONFIG_HAVE_GET_MEMORY_MAPPING)
CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y)
obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o
obj-y += qtest.o
obj-y += hw/
obj-$(CONFIG_FDT) += device_tree.o
obj-$(CONFIG_KVM) += kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
obj-y += memory.o savevm.o cputlb.o
@ -146,22 +147,16 @@ nested-vars += obj-y
include $(SRC_PATH)/Makefile.objs
all-obj-y = $(obj-y)
all-obj-y += $(addprefix ../, $(universal-obj-y))
ifdef CONFIG_SOFTMMU
all-obj-y += $(addprefix ../, $(common-obj-y))
else
all-obj-y += $(addprefix ../, $(user-obj-y))
endif #CONFIG_LINUX_USER
ifdef QEMU_PROGW
# The linker builds a windows executable. Make also a console executable.
$(QEMU_PROGW): $(all-obj-y) ../libqemustub.a
$(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) ../libqemustub.a
$(QEMU_PROG): $(all-obj-y) ../libqemuutil.a ../libqemustub.a
$(call LINK,$^)
endif

37
TODO
View File

@ -1,37 +0,0 @@
General:
-------
- cycle counter for all archs
- cpu_interrupt() win32/SMP fix
- merge PIC spurious interrupt patch
- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
- config file (at least for windows/Mac OS X)
- update doc: PCI infos.
- basic VGA optimizations
- better code fetch
- do not resize vga if invalid size.
- TLB code protection support for PPC
- disable SMC handling for ARM/SPARC/PPC (not finished)
- see undefined flags for BTx insn
- keyboard output buffer filling timing emulation
- tests for each target CPU
- fix all remaining thread lock issues (must put TBs in a specific invalid
state, find a solution for tb_flush()).
ppc specific:
------------
- TLB invalidate not needed if msr_pr changes
- enable shift optimizations ?
linux-user specific:
-------------------
- remove threading support as it cannot work at this point
- improve IPC syscalls
- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
issues, fix 16 bit uid issues)
- use kernel traps for unaligned accesses on ARM ?
lower priority:
--------------
- int15 ah=86: use better timing
- use -msoft-float on ARM

View File

@ -1 +1 @@
1.3.50
1.4.50

View File

@ -25,6 +25,7 @@ struct AioHandler
IOHandler *io_write;
AioFlushHandler *io_flush;
int deleted;
int pollfds_idx;
void *opaque;
QLIST_ENTRY(AioHandler) node;
};
@ -85,9 +86,10 @@ void aio_set_fd_handler(AioContext *ctx,
node->io_write = io_write;
node->io_flush = io_flush;
node->opaque = opaque;
node->pollfds_idx = -1;
node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP : 0);
node->pfd.events |= (io_write ? G_IO_OUT : 0);
node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0);
node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
}
aio_notify(ctx);
@ -110,13 +112,6 @@ bool aio_pending(AioContext *ctx)
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
int revents;
/*
* FIXME: right now we cannot get G_IO_HUP and G_IO_ERR because
* main-loop.c is still select based (due to the slirp legacy).
* If main-loop.c ever switches to poll, G_IO_ERR should be
* tested too. Dispatching G_IO_ERR to both handlers should be
* okay, since handlers need to be ready for spurious wakeups.
*/
revents = node->pfd.revents & node->pfd.events;
if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
return true;
@ -129,30 +124,12 @@ bool aio_pending(AioContext *ctx)
return false;
}
bool aio_poll(AioContext *ctx, bool blocking)
static bool aio_dispatch(AioContext *ctx)
{
static struct timeval tv0;
AioHandler *node;
fd_set rdfds, wrfds;
int max_fd = -1;
int ret;
bool busy, progress;
progress = false;
bool progress = false;
/*
* If there are callbacks left that have been queued, we need to call then.
* Do not call select in this case, because it is possible that the caller
* does not need a complete flush (as is the case for qemu_aio_wait loops).
*/
if (aio_bh_poll(ctx)) {
blocking = false;
progress = true;
}
/*
* Then dispatch any pending callbacks from the GSource.
*
* We have to walk very carefully in case qemu_aio_set_fd_handler is
* called while we're walking.
*/
@ -166,12 +143,15 @@ bool aio_poll(AioContext *ctx, bool blocking)
revents = node->pfd.revents & node->pfd.events;
node->pfd.revents = 0;
/* See comment in aio_pending. */
if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
if (!node->deleted &&
(revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) &&
node->io_read) {
node->io_read(node->opaque);
progress = true;
}
if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
if (!node->deleted &&
(revents & (G_IO_OUT | G_IO_ERR)) &&
node->io_write) {
node->io_write(node->opaque);
progress = true;
}
@ -186,6 +166,30 @@ bool aio_poll(AioContext *ctx, bool blocking)
g_free(tmp);
}
}
return progress;
}
bool aio_poll(AioContext *ctx, bool blocking)
{
AioHandler *node;
int ret;
bool busy, progress;
progress = false;
/*
* If there are callbacks left that have been queued, we need to call them.
* Do not call select in this case, because it is possible that the caller
* does not need a complete flush (as is the case for qemu_aio_wait loops).
*/
if (aio_bh_poll(ctx)) {
blocking = false;
progress = true;
}
if (aio_dispatch(ctx)) {
progress = true;
}
if (progress && !blocking) {
return true;
@ -193,12 +197,13 @@ bool aio_poll(AioContext *ctx, bool blocking)
ctx->walking_handlers++;
FD_ZERO(&rdfds);
FD_ZERO(&wrfds);
g_array_set_size(ctx->pollfds, 0);
/* fill fd sets */
/* fill pollfds */
busy = false;
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
node->pollfds_idx = -1;
/* If there aren't pending AIO operations, don't invoke callbacks.
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
* wait indefinitely.
@ -209,13 +214,13 @@ bool aio_poll(AioContext *ctx, bool blocking)
}
busy = true;
}
if (!node->deleted && node->io_read) {
FD_SET(node->pfd.fd, &rdfds);
max_fd = MAX(max_fd, node->pfd.fd + 1);
}
if (!node->deleted && node->io_write) {
FD_SET(node->pfd.fd, &wrfds);
max_fd = MAX(max_fd, node->pfd.fd + 1);
if (!node->deleted && node->pfd.events) {
GPollFD pfd = {
.fd = node->pfd.fd,
.events = node->pfd.events,
};
node->pollfds_idx = ctx->pollfds->len;
g_array_append_val(ctx->pollfds, pfd);
}
}
@ -227,42 +232,24 @@ bool aio_poll(AioContext *ctx, bool blocking)
}
/* wait until next event */
ret = select(max_fd, &rdfds, &wrfds, NULL, blocking ? NULL : &tv0);
ret = g_poll((GPollFD *)ctx->pollfds->data,
ctx->pollfds->len,
blocking ? -1 : 0);
/* if we have any readable fds, dispatch event */
if (ret > 0) {
/* we have to walk very carefully in case
* qemu_aio_set_fd_handler is called while we're walking */
node = QLIST_FIRST(&ctx->aio_handlers);
while (node) {
AioHandler *tmp;
ctx->walking_handlers++;
if (!node->deleted &&
FD_ISSET(node->pfd.fd, &rdfds) &&
node->io_read) {
node->io_read(node->opaque);
progress = true;
}
if (!node->deleted &&
FD_ISSET(node->pfd.fd, &wrfds) &&
node->io_write) {
node->io_write(node->opaque);
progress = true;
}
tmp = node;
node = QLIST_NEXT(node, node);
ctx->walking_handlers--;
if (!ctx->walking_handlers && tmp->deleted) {
QLIST_REMOVE(tmp, node);
g_free(tmp);
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
if (node->pollfds_idx != -1) {
GPollFD *pfd = &g_array_index(ctx->pollfds, GPollFD,
node->pollfds_idx);
node->pfd.revents = pfd->revents;
}
}
if (aio_dispatch(ctx)) {
progress = true;
}
}
return progress;
assert(progress || busy);
return true;
}

View File

@ -214,5 +214,6 @@ bool aio_poll(AioContext *ctx, bool blocking)
events[ret - WAIT_OBJECT_0] = events[--count];
}
return progress;
assert(progress || busy);
return true;
}

View File

@ -293,8 +293,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
if (!last_stage) {
cache_insert(XBZRLE.cache, current_addr,
g_memdup(current_data, TARGET_PAGE_SIZE));
cache_insert(XBZRLE.cache, current_addr, current_data);
}
acct_info.xbzrle_cache_miss++;
return -1;
@ -379,6 +378,8 @@ static inline bool migration_bitmap_set_dirty(MemoryRegion *mr,
return ret;
}
/* Needs iothread lock! */
static void migration_bitmap_sync(void)
{
RAMBlock *block;
@ -414,6 +415,7 @@ static void migration_bitmap_sync(void)
if (end_time > start_time + 1000) {
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;
}
@ -567,10 +569,6 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
bitmap_set(migration_bitmap, 0, ram_pages);
migration_dirty_pages = ram_pages;
qemu_mutex_lock_ramlist();
bytes_transferred = 0;
reset_ram_globals();
if (migrate_use_xbzrle()) {
XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
TARGET_PAGE_SIZE,
@ -584,8 +582,14 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
acct_clear();
}
qemu_mutex_lock_iothread();
qemu_mutex_lock_ramlist();
bytes_transferred = 0;
reset_ram_globals();
memory_global_dirty_log_start();
migration_bitmap_sync();
qemu_mutex_unlock_iothread();
qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
@ -642,12 +646,13 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
i++;
}
qemu_mutex_unlock_ramlist();
if (ret < 0) {
bytes_transferred += total_sent;
return ret;
}
qemu_mutex_unlock_ramlist();
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
total_sent += 8;
bytes_transferred += total_sent;
@ -657,9 +662,8 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
static int ram_save_complete(QEMUFile *f, void *opaque)
{
migration_bitmap_sync();
qemu_mutex_lock_ramlist();
migration_bitmap_sync();
/* try transferring iterative blocks of memory */
@ -689,7 +693,9 @@ static uint64_t ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE;
if (remaining_size < max_size) {
qemu_mutex_lock_iothread();
migration_bitmap_sync();
qemu_mutex_unlock_iothread();
remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE;
}
return remaining_size;
@ -851,9 +857,6 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
} else if (flags & RAM_SAVE_FLAG_XBZRLE) {
if (!migrate_use_xbzrle()) {
return -EINVAL;
}
void *host = host_from_stream_offset(f, addr, flags);
if (!host) {
return -EINVAL;

13
async.c
View File

@ -24,6 +24,7 @@
#include "qemu-common.h"
#include "block/aio.h"
#include "block/thread-pool.h"
#include "qemu/main-loop.h"
/***********************************************************/
@ -172,8 +173,10 @@ aio_ctx_finalize(GSource *source)
{
AioContext *ctx = (AioContext *) source;
thread_pool_free(ctx->thread_pool);
aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL);
event_notifier_cleanup(&ctx->notifier);
g_array_free(ctx->pollfds, TRUE);
}
static GSourceFuncs aio_source_funcs = {
@ -189,6 +192,14 @@ GSource *aio_get_g_source(AioContext *ctx)
return &ctx->source;
}
ThreadPool *aio_get_thread_pool(AioContext *ctx)
{
if (!ctx->thread_pool) {
ctx->thread_pool = thread_pool_new(ctx);
}
return ctx->thread_pool;
}
void aio_notify(AioContext *ctx)
{
event_notifier_set(&ctx->notifier);
@ -198,6 +209,8 @@ AioContext *aio_context_new(void)
{
AioContext *ctx;
ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
ctx->thread_pool = NULL;
event_notifier_init(&ctx->notifier, false);
aio_set_event_notifier(ctx, &ctx->notifier,
(EventNotifierHandler *)

View File

@ -828,8 +828,9 @@ static int audio_attach_capture (HWVoiceOut *hw)
QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
QLIST_INSERT_HEAD (&hw->cap_head, sc, entries);
#ifdef DEBUG_CAPTURE
asprintf (&sw->name, "for %p %d,%d,%d",
hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
sw->name = g_strdup_printf ("for %p %d,%d,%d",
hw, sw->info.freq, sw->info.bits,
sw->info.nchannels);
dolog ("Added %s active = %d\n", sw->name, sw->active);
#endif
if (sw->active) {

View File

@ -1,2 +1,6 @@
common-obj-y += rng.o rng-egd.o
common-obj-$(CONFIG_POSIX) += rng-random.o
common-obj-y += msmouse.o
common-obj-$(CONFIG_BRLAPI) += baum.o
$(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)

View File

@ -24,8 +24,7 @@
#include "qemu-common.h"
#include "char/char.h"
#include "qemu/timer.h"
#include "usb.h"
#include "baum.h"
#include "hw/usb.h"
#include <brlapi.h>
#include <brlapi_constants.h>
#include <brlapi_keycodes.h>
@ -562,7 +561,7 @@ static void baum_close(struct CharDriverState *chr)
g_free(baum);
}
CharDriverState *chr_baum_init(QemuOpts *opts)
CharDriverState *chr_baum_init(void)
{
BaumDriverState *baum;
CharDriverState *chr;
@ -625,3 +624,10 @@ fail_handle:
g_free(baum);
return NULL;
}
static void register_types(void)
{
register_char_driver_qapi("braille", CHARDEV_BACKEND_KIND_BRAILLE, NULL);
}
type_init(register_types);

View File

@ -25,7 +25,6 @@
#include "qemu-common.h"
#include "char/char.h"
#include "ui/console.h"
#include "msmouse.h"
#define MSMOUSE_LO6(n) ((n) & 0x3f)
#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6)
@ -64,7 +63,7 @@ static void msmouse_chr_close (struct CharDriverState *chr)
g_free (chr);
}
CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
CharDriverState *qemu_chr_open_msmouse(void)
{
CharDriverState *chr;
@ -76,3 +75,10 @@ CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
return chr;
}
static void register_types(void)
{
register_char_driver_qapi("msmouse", CHARDEV_BACKEND_KIND_MSMOUSE, NULL);
}
type_init(register_types);

View File

@ -207,7 +207,7 @@ static void rng_egd_class_init(ObjectClass *klass, void *data)
rbc->opened = rng_egd_opened;
}
static TypeInfo rng_egd_info = {
static const TypeInfo rng_egd_info = {
.name = TYPE_RNG_EGD,
.parent = TYPE_RNG_BACKEND,
.instance_size = sizeof(RngEgd),

View File

@ -74,7 +74,7 @@ static void rng_random_opened(RngBackend *b, Error **errp)
error_set(errp, QERR_INVALID_PARAMETER_VALUE,
"filename", "a valid filename");
} else {
s->fd = open(s->filename, O_RDONLY | O_NONBLOCK);
s->fd = qemu_open(s->filename, O_RDONLY | O_NONBLOCK);
if (s->fd == -1) {
error_set(errp, QERR_OPEN_FILE_FAILED, s->filename);
@ -130,7 +130,7 @@ static void rng_random_finalize(Object *obj)
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
if (s->fd != -1) {
close(s->fd);
qemu_close(s->fd);
}
g_free(s->filename);
@ -144,7 +144,7 @@ static void rng_random_class_init(ObjectClass *klass, void *data)
rbc->opened = rng_random_opened;
}
static TypeInfo rng_random_info = {
static const TypeInfo rng_random_info = {
.name = TYPE_RNG_RANDOM,
.parent = TYPE_RNG_BACKEND,
.instance_size = sizeof(RndRandom),

View File

@ -76,7 +76,7 @@ static void rng_backend_init(Object *obj)
NULL);
}
static TypeInfo rng_backend_info = {
static const TypeInfo rng_backend_info = {
.name = TYPE_RNG_BACKEND,
.parent = TYPE_OBJECT,
.instance_size = sizeof(RngBackend),

View File

@ -23,7 +23,8 @@
#include "sysemu/blockdev.h"
#include <assert.h>
#define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS)
#define BLOCK_SIZE (1 << 20)
#define BDRV_SECTORS_PER_DIRTY_CHUNK (BLOCK_SIZE >> BDRV_SECTOR_BITS)
#define BLK_MIG_FLAG_DEVICE_BLOCK 0x01
#define BLK_MIG_FLAG_EOS 0x02
@ -42,19 +43,24 @@
#endif
typedef struct BlkMigDevState {
/* Written during setup phase. Can be read without a lock. */
BlockDriverState *bs;
int bulk_completed;
int shared_base;
int64_t total_sectors;
QSIMPLEQ_ENTRY(BlkMigDevState) entry;
/* Only used by migration thread. Does not need a lock. */
int bulk_completed;
int64_t cur_sector;
int64_t cur_dirty;
int64_t completed_sectors;
int64_t total_sectors;
int64_t dirty;
QSIMPLEQ_ENTRY(BlkMigDevState) entry;
/* Protected by block migration lock. */
unsigned long *aio_bitmap;
int64_t completed_sectors;
} BlkMigDevState;
typedef struct BlkMigBlock {
/* Only used by migration thread. */
uint8_t *buf;
BlkMigDevState *bmds;
int64_t sector;
@ -62,26 +68,49 @@ typedef struct BlkMigBlock {
struct iovec iov;
QEMUIOVector qiov;
BlockDriverAIOCB *aiocb;
/* Protected by block migration lock. */
int ret;
QSIMPLEQ_ENTRY(BlkMigBlock) entry;
} BlkMigBlock;
typedef struct BlkMigState {
/* Written during setup phase. Can be read without a lock. */
int blk_enable;
int shared_base;
QSIMPLEQ_HEAD(bmds_list, BlkMigDevState) bmds_list;
int64_t total_sector_sum;
/* Protected by lock. */
QSIMPLEQ_HEAD(blk_list, BlkMigBlock) blk_list;
int submitted;
int read_done;
/* Only used by migration thread. Does not need a lock. */
int transferred;
int64_t total_sector_sum;
int prev_progress;
int bulk_completed;
long double prev_time_offset;
/* Lock must be taken _inside_ the iothread lock. */
QemuMutex lock;
} BlkMigState;
static BlkMigState block_mig_state;
static void blk_mig_lock(void)
{
qemu_mutex_lock(&block_mig_state.lock);
}
static void blk_mig_unlock(void)
{
qemu_mutex_unlock(&block_mig_state.lock);
}
/* Must run outside of the iothread lock during the bulk phase,
* or the VM will stall.
*/
static void blk_send(QEMUFile *f, BlkMigBlock * blk)
{
int len;
@ -108,9 +137,11 @@ uint64_t blk_mig_bytes_transferred(void)
BlkMigDevState *bmds;
uint64_t sum = 0;
blk_mig_lock();
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
sum += bmds->completed_sectors;
}
blk_mig_unlock();
return sum << BDRV_SECTOR_BITS;
}
@ -130,6 +161,9 @@ uint64_t blk_mig_bytes_total(void)
return sum << BDRV_SECTOR_BITS;
}
/* Called with migration lock held. */
static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
{
int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
@ -142,6 +176,8 @@ static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
}
}
/* Called with migration lock held. */
static void bmds_set_aio_inflight(BlkMigDevState *bmds, int64_t sector_num,
int nb_sectors, int set)
{
@ -176,23 +212,26 @@ static void alloc_aio_bitmap(BlkMigDevState *bmds)
bmds->aio_bitmap = g_malloc0(bitmap_size);
}
/* Never hold migration lock when yielding to the main loop! */
static void blk_mig_read_cb(void *opaque, int ret)
{
long double curr_time = qemu_get_clock_ns(rt_clock);
BlkMigBlock *blk = opaque;
blk_mig_lock();
blk->ret = ret;
block_mig_state.prev_time_offset = curr_time;
QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0);
block_mig_state.submitted--;
block_mig_state.read_done++;
assert(block_mig_state.submitted >= 0);
blk_mig_unlock();
}
/* Called with no lock taken. */
static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
{
int64_t total_sectors = bmds->total_sectors;
@ -202,11 +241,13 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
int nr_sectors;
if (bmds->shared_base) {
qemu_mutex_lock_iothread();
while (cur_sector < total_sectors &&
!bdrv_is_allocated(bs, cur_sector, MAX_IS_ALLOCATED_SEARCH,
&nr_sectors)) {
cur_sector += nr_sectors;
}
qemu_mutex_unlock_iothread();
}
if (cur_sector >= total_sectors) {
@ -235,26 +276,29 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
if (block_mig_state.submitted == 0) {
block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
}
blk_mig_lock();
block_mig_state.submitted++;
blk_mig_unlock();
qemu_mutex_lock_iothread();
blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
nr_sectors, blk_mig_read_cb, blk);
block_mig_state.submitted++;
bdrv_reset_dirty(bs, cur_sector, nr_sectors);
bmds->cur_sector = cur_sector + nr_sectors;
qemu_mutex_unlock_iothread();
bmds->cur_sector = cur_sector + nr_sectors;
return (bmds->cur_sector >= total_sectors);
}
/* Called with iothread lock taken. */
static void set_dirty_tracking(int enable)
{
BlkMigDevState *bmds;
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
bdrv_set_dirty_tracking(bmds->bs, enable);
bdrv_set_dirty_tracking(bmds->bs, enable ? BLOCK_SIZE : 0);
}
}
@ -304,6 +348,8 @@ static void init_blk_migration(QEMUFile *f)
bdrv_iterate(init_blk_migration_it, NULL);
}
/* Called with no lock taken. */
static int blk_mig_save_bulked_block(QEMUFile *f)
{
int64_t completed_sector_sum = 0;
@ -350,6 +396,8 @@ static void blk_mig_reset_dirty_cursor(void)
}
}
/* Called with iothread lock taken. */
static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
int is_async)
{
@ -360,8 +408,12 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
int ret = -EIO;
for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
blk_mig_lock();
if (bmds_aio_inflight(bmds, sector)) {
blk_mig_unlock();
bdrv_drain_all();
} else {
blk_mig_unlock();
}
if (bdrv_get_dirty(bmds->bs, sector)) {
@ -381,14 +433,13 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
if (block_mig_state.submitted == 0) {
block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
}
blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov,
nr_sectors, blk_mig_read_cb, blk);
blk_mig_lock();
block_mig_state.submitted++;
bmds_set_aio_inflight(bmds, sector, nr_sectors, 1);
blk_mig_unlock();
} else {
ret = bdrv_read(bmds->bs, sector, blk->buf, nr_sectors);
if (ret < 0) {
@ -416,7 +467,9 @@ error:
return ret;
}
/* return value:
/* Called with iothread lock taken.
*
* return value:
* 0: too much data for max_downtime
* 1: few enough data for max_downtime
*/
@ -435,6 +488,8 @@ static int blk_mig_save_dirty_block(QEMUFile *f, int is_async)
return ret;
}
/* Called with no locks taken. */
static int flush_blks(QEMUFile *f)
{
BlkMigBlock *blk;
@ -444,6 +499,7 @@ static int flush_blks(QEMUFile *f)
__FUNCTION__, block_mig_state.submitted, block_mig_state.read_done,
block_mig_state.transferred);
blk_mig_lock();
while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) {
if (qemu_file_rate_limit(f)) {
break;
@ -452,9 +508,12 @@ static int flush_blks(QEMUFile *f)
ret = blk->ret;
break;
}
blk_send(f, blk);
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
blk_mig_unlock();
blk_send(f, blk);
blk_mig_lock();
g_free(blk->buf);
g_free(blk);
@ -462,6 +521,7 @@ static int flush_blks(QEMUFile *f)
block_mig_state.transferred++;
assert(block_mig_state.read_done >= 0);
}
blk_mig_unlock();
DPRINTF("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__,
block_mig_state.submitted, block_mig_state.read_done,
@ -469,6 +529,8 @@ static int flush_blks(QEMUFile *f)
return ret;
}
/* Called with iothread lock taken. */
static int64_t get_remaining_dirty(void)
{
BlkMigDevState *bmds;
@ -478,9 +540,11 @@ static int64_t get_remaining_dirty(void)
dirty += bdrv_get_dirty_count(bmds->bs);
}
return dirty * BLOCK_SIZE;
return dirty << BDRV_SECTOR_BITS;
}
/* Called with iothread lock taken. */
static void blk_mig_cleanup(void)
{
BlkMigDevState *bmds;
@ -490,6 +554,7 @@ static void blk_mig_cleanup(void)
set_dirty_tracking(0);
blk_mig_lock();
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
bdrv_set_in_use(bmds->bs, 0);
@ -503,6 +568,7 @@ static void blk_mig_cleanup(void)
g_free(blk->buf);
g_free(blk);
}
blk_mig_unlock();
}
static void block_migration_cancel(void *opaque)
@ -517,73 +583,78 @@ static int block_save_setup(QEMUFile *f, void *opaque)
DPRINTF("Enter save live setup submitted %d transferred %d\n",
block_mig_state.submitted, block_mig_state.transferred);
qemu_mutex_lock_iothread();
init_blk_migration(f);
/* start track dirty blocks */
set_dirty_tracking(1);
qemu_mutex_unlock_iothread();
ret = flush_blks(f);
if (ret) {
blk_mig_cleanup();
return ret;
}
blk_mig_reset_dirty_cursor();
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
return 0;
return ret;
}
static int block_save_iterate(QEMUFile *f, void *opaque)
{
int ret;
int64_t last_ftell = qemu_ftell(f);
DPRINTF("Enter save live iterate submitted %d transferred %d\n",
block_mig_state.submitted, block_mig_state.transferred);
ret = flush_blks(f);
if (ret) {
blk_mig_cleanup();
return ret;
}
blk_mig_reset_dirty_cursor();
/* control the rate of transfer */
blk_mig_lock();
while ((block_mig_state.submitted +
block_mig_state.read_done) * BLOCK_SIZE <
qemu_file_get_rate_limit(f)) {
blk_mig_unlock();
if (block_mig_state.bulk_completed == 0) {
/* first finish the bulk phase */
if (blk_mig_save_bulked_block(f) == 0) {
/* finished saving bulk on all devices */
block_mig_state.bulk_completed = 1;
}
ret = 0;
} else {
/* Always called with iothread lock taken for
* simplicity, block_save_complete also calls it.
*/
qemu_mutex_lock_iothread();
ret = blk_mig_save_dirty_block(f, 1);
if (ret != 0) {
/* no more dirty blocks */
break;
}
qemu_mutex_unlock_iothread();
}
if (ret < 0) {
return ret;
}
blk_mig_lock();
if (ret != 0) {
/* no more dirty blocks */
break;
}
}
if (ret) {
blk_mig_cleanup();
return ret;
}
blk_mig_unlock();
ret = flush_blks(f);
if (ret) {
blk_mig_cleanup();
return ret;
}
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
return 0;
return qemu_ftell(f) - last_ftell;
}
/* Called with iothread lock taken. */
static int block_save_complete(QEMUFile *f, void *opaque)
{
int ret;
@ -593,7 +664,6 @@ static int block_save_complete(QEMUFile *f, void *opaque)
ret = flush_blks(f);
if (ret) {
blk_mig_cleanup();
return ret;
}
@ -601,16 +671,17 @@ static int block_save_complete(QEMUFile *f, void *opaque)
/* we know for sure that save bulk is completed and
all async read completed */
blk_mig_lock();
assert(block_mig_state.submitted == 0);
blk_mig_unlock();
do {
ret = blk_mig_save_dirty_block(f, 0);
if (ret < 0) {
return ret;
}
} while (ret == 0);
blk_mig_cleanup();
if (ret) {
return ret;
}
/* report completion */
qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
@ -618,15 +689,30 @@ static int block_save_complete(QEMUFile *f, void *opaque)
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
blk_mig_cleanup();
return 0;
}
static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
{
/* Estimate pending number of bytes to send */
uint64_t pending;
DPRINTF("Enter save live pending %ld\n", get_remaining_dirty());
qemu_mutex_lock_iothread();
blk_mig_lock();
pending = get_remaining_dirty() +
block_mig_state.submitted * BLOCK_SIZE +
block_mig_state.read_done * BLOCK_SIZE;
return get_remaining_dirty();
/* Report at least one block pending during bulk phase */
if (pending == 0 && !block_mig_state.bulk_completed) {
pending = BLOCK_SIZE;
}
blk_mig_unlock();
qemu_mutex_unlock_iothread();
DPRINTF("Enter save live pending %" PRIu64 "\n", pending);
return pending;
}
static int block_load(QEMUFile *f, void *opaque, int version_id)
@ -694,7 +780,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
(addr == 100) ? '\n' : '\r');
fflush(stdout);
} else if (!(flags & BLK_MIG_FLAG_EOS)) {
fprintf(stderr, "Unknown flags\n");
fprintf(stderr, "Unknown block migration flags: %#x\n", flags);
return -EINVAL;
}
ret = qemu_file_get_error(f);
@ -735,6 +821,7 @@ void blk_mig_init(void)
{
QSIMPLEQ_INIT(&block_mig_state.bmds_list);
QSIMPLEQ_INIT(&block_mig_state.blk_list);
qemu_mutex_init(&block_mig_state.lock);
register_savevm_live(NULL, "block", 0, 1, &savevm_block_handlers,
&block_mig_state);

341
block.c
View File

@ -155,10 +155,6 @@ void bdrv_io_limits_enable(BlockDriverState *bs)
{
qemu_co_queue_init(&bs->throttled_reqs);
bs->block_timer = qemu_new_timer_ns(vm_clock, bdrv_block_timer, bs);
bs->slice_time = 5 * BLOCK_IO_SLICE_TIME;
bs->slice_start = qemu_get_clock_ns(vm_clock);
bs->slice_end = bs->slice_start + bs->slice_time;
memset(&bs->io_base, 0, sizeof(bs->io_base));
bs->io_limits_enabled = true;
}
@ -527,7 +523,7 @@ static int find_image_format(BlockDriverState *bs, const char *filename,
int ret = 0;
/* Return the raw BlockDriver * to scsi-generic devices or empty drives */
if (bs->sg || !bdrv_is_inserted(bs)) {
if (bs->sg || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) {
drv = bdrv_find_format("raw");
if (!drv) {
ret = -ENOENT;
@ -584,6 +580,26 @@ static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
return 0;
}
/**
* Set open flags for a given discard mode
*
* Return 0 on success, -1 if the discard mode was invalid.
*/
int bdrv_parse_discard_flags(const char *mode, int *flags)
{
*flags &= ~BDRV_O_UNMAP;
if (!strcmp(mode, "off") || !strcmp(mode, "ignore")) {
/* do nothing */
} else if (!strcmp(mode, "on") || !strcmp(mode, "unmap")) {
*flags |= BDRV_O_UNMAP;
} else {
return -1;
}
return 0;
}
/**
* Set open flags for a given cache mode
*
@ -649,15 +665,18 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
/*
* Common part for opening disk images and files
*
* Removes all processed options from *options.
*/
static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
const char *filename,
const char *filename, QDict *options,
int flags, BlockDriver *drv)
{
int ret, open_flags;
assert(drv != NULL);
assert(bs->file == NULL);
assert(options == NULL || bs->options != options);
trace_bdrv_open_common(bs, filename, flags, drv->format_name);
@ -694,7 +713,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
} else {
assert(file != NULL);
bs->file = file;
ret = drv->bdrv_open(bs, open_flags);
ret = drv->bdrv_open(bs, options, open_flags);
}
if (ret < 0) {
@ -736,7 +755,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
}
bs = bdrv_new("");
ret = bdrv_open_common(bs, NULL, filename, flags, drv);
ret = bdrv_open_common(bs, NULL, filename, NULL, flags, drv);
if (ret < 0) {
bdrv_delete(bs);
return ret;
@ -772,7 +791,8 @@ int bdrv_open_backing_file(BlockDriverState *bs)
/* backing files always opened read-only */
back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT);
ret = bdrv_open(bs->backing_hd, backing_filename, back_flags, back_drv);
ret = bdrv_open(bs->backing_hd, backing_filename, NULL,
back_flags, back_drv);
if (ret < 0) {
bdrv_delete(bs->backing_hd);
bs->backing_hd = NULL;
@ -784,15 +804,29 @@ int bdrv_open_backing_file(BlockDriverState *bs)
/*
* Opens a disk image (raw, qcow2, vmdk, ...)
*
* options is a QDict of options to pass to the block drivers, or NULL for an
* empty set of options. The reference to the QDict belongs to the block layer
* after the call (even on failure), so if the caller intends to reuse the
* dictionary, it needs to use QINCREF() before calling bdrv_open.
*/
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
BlockDriver *drv)
int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
int flags, BlockDriver *drv)
{
int ret;
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
char tmp_filename[PATH_MAX + 1];
BlockDriverState *file = NULL;
/* NULL means an empty set of options */
if (options == NULL) {
options = qdict_new();
}
bs->options = options;
options = qdict_clone_shallow(options);
/* For snapshot=on, create a temporary qcow2 overlay */
if (flags & BDRV_O_SNAPSHOT) {
BlockDriverState *bs1;
int64_t total_size;
@ -806,10 +840,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
/* if there is a backing file, use it */
bs1 = bdrv_new("");
ret = bdrv_open(bs1, filename, 0, drv);
ret = bdrv_open(bs1, filename, NULL, 0, drv);
if (ret < 0) {
bdrv_delete(bs1);
return ret;
goto fail;
}
total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
@ -820,15 +854,17 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
if (ret < 0) {
return ret;
goto fail;
}
/* Real path is meaningless for protocols */
if (is_protocol)
if (is_protocol) {
snprintf(backing_filename, sizeof(backing_filename),
"%s", filename);
else if (!realpath(filename, backing_filename))
return -errno;
} else if (!realpath(filename, backing_filename)) {
ret = -errno;
goto fail;
}
bdrv_qcow2 = bdrv_find_format("qcow2");
options = parse_option_parameters("", bdrv_qcow2->create_options, NULL);
@ -843,7 +879,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
ret = bdrv_create(bdrv_qcow2, tmp_filename, options);
free_option_parameters(options);
if (ret < 0) {
return ret;
goto fail;
}
filename = tmp_filename;
@ -858,7 +894,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
ret = bdrv_file_open(&file, filename, bdrv_open_flags(bs, flags));
if (ret < 0) {
return ret;
goto fail;
}
/* Find the right image format driver */
@ -871,7 +907,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
}
/* Open the image */
ret = bdrv_open_common(bs, file, filename, flags, drv);
ret = bdrv_open_common(bs, file, filename, options, flags, drv);
if (ret < 0) {
goto unlink_and_fail;
}
@ -885,11 +921,22 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
if ((flags & BDRV_O_NO_BACKING) == 0) {
ret = bdrv_open_backing_file(bs);
if (ret < 0) {
bdrv_close(bs);
return ret;
goto close_and_fail;
}
}
/* Check if any unknown options were used */
if (qdict_size(options) != 0) {
const QDictEntry *entry = qdict_first(options);
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Block format '%s' used by "
"device '%s' doesn't support the option '%s'",
drv->format_name, bs->device_name, entry->key);
ret = -EINVAL;
goto close_and_fail;
}
QDECREF(options);
if (!bdrv_key_required(bs)) {
bdrv_dev_change_media_cb(bs, true);
}
@ -908,6 +955,15 @@ unlink_and_fail:
if (bs->is_temporary) {
unlink(filename);
}
fail:
QDECREF(bs->options);
QDECREF(options);
bs->options = NULL;
return ret;
close_and_fail:
bdrv_close(bs);
QDECREF(options);
return ret;
}
@ -1177,6 +1233,8 @@ void bdrv_close(BlockDriverState *bs)
bs->valid_key = 0;
bs->sg = 0;
bs->growable = 0;
QDECREF(bs->options);
bs->options = NULL;
if (bs->file != NULL) {
bdrv_delete(bs->file);
@ -1290,7 +1348,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
bs_dest->iostatus = bs_src->iostatus;
/* dirty bitmap */
bs_dest->dirty_count = bs_src->dirty_count;
bs_dest->dirty_bitmap = bs_src->dirty_bitmap;
/* job */
@ -1625,9 +1682,11 @@ int bdrv_commit_all(void)
BlockDriverState *bs;
QTAILQ_FOREACH(bs, &bdrv_states, list) {
int ret = bdrv_commit(bs);
if (ret < 0) {
return ret;
if (bs->drv && bs->backing_hd) {
int ret = bdrv_commit(bs);
if (ret < 0) {
return ret;
}
}
}
return 0;
@ -1678,10 +1737,10 @@ static void tracked_request_begin(BdrvTrackedRequest *req,
/**
* Round a region to cluster boundaries
*/
static void round_to_clusters(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
int64_t *cluster_sector_num,
int *cluster_nb_sectors)
void bdrv_round_to_clusters(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
int64_t *cluster_sector_num,
int *cluster_nb_sectors)
{
BlockDriverInfo bdi;
@ -1723,8 +1782,8 @@ static void coroutine_fn wait_for_overlapping_requests(BlockDriverState *bs,
* CoR read and write operations are atomic and guest writes cannot
* interleave between them.
*/
round_to_clusters(bs, sector_num, nb_sectors,
&cluster_sector_num, &cluster_nb_sectors);
bdrv_round_to_clusters(bs, sector_num, nb_sectors,
&cluster_sector_num, &cluster_nb_sectors);
do {
retry = false;
@ -2039,36 +2098,6 @@ int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num,
return ret;
}
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int dirty)
{
int64_t start, end;
unsigned long val, idx, bit;
start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK;
end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK;
for (; start <= end; start++) {
idx = start / BITS_PER_LONG;
bit = start % BITS_PER_LONG;
val = bs->dirty_bitmap[idx];
if (dirty) {
if (!(val & (1UL << bit))) {
bs->dirty_count++;
val |= 1UL << bit;
}
} else {
if (val & (1UL << bit)) {
bs->dirty_count--;
val &= ~(1UL << bit);
}
}
bs->dirty_bitmap[idx] = val;
}
}
/* Return < 0 if error. Important errors are:
-EIO generic I/O error (may happen for all errors)
-ENOMEDIUM No media inserted.
@ -2220,8 +2249,8 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
/* Cover entire cluster so no additional backing file I/O is required when
* allocating cluster in the image file.
*/
round_to_clusters(bs, sector_num, nb_sectors,
&cluster_sector_num, &cluster_nb_sectors);
bdrv_round_to_clusters(bs, sector_num, nb_sectors,
&cluster_sector_num, &cluster_nb_sectors);
trace_bdrv_co_do_copy_on_readv(bs, sector_num, nb_sectors,
cluster_sector_num, cluster_nb_sectors);
@ -2462,6 +2491,10 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
return -EACCES;
if (bdrv_in_use(bs))
return -EBUSY;
/* There better not be any in-flight IOs when we truncate the device. */
bdrv_drain_all();
ret = drv->bdrv_truncate(bs, offset);
if (ret == 0) {
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
@ -2716,6 +2749,7 @@ int bdrv_has_zero_init(BlockDriverState *bs)
typedef struct BdrvCoIsAllocatedData {
BlockDriverState *bs;
BlockDriverState *base;
int64_t sector_num;
int nb_sectors;
int *pnum;
@ -2835,7 +2869,9 @@ int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
*
* [sector_num+x, nr_sectors] allocated.
*/
if (n > pnum_inter) {
if (n > pnum_inter &&
(intermediate == top ||
sector_num + pnum_inter < intermediate->total_sectors)) {
n = pnum_inter;
}
@ -2846,6 +2882,44 @@ int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
return 0;
}
/* Coroutine wrapper for bdrv_is_allocated_above() */
static void coroutine_fn bdrv_is_allocated_above_co_entry(void *opaque)
{
BdrvCoIsAllocatedData *data = opaque;
BlockDriverState *top = data->bs;
BlockDriverState *base = data->base;
data->ret = bdrv_co_is_allocated_above(top, base, data->sector_num,
data->nb_sectors, data->pnum);
data->done = true;
}
/*
* Synchronous wrapper around bdrv_co_is_allocated_above().
*
* See bdrv_co_is_allocated_above() for details.
*/
int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
int64_t sector_num, int nb_sectors, int *pnum)
{
Coroutine *co;
BdrvCoIsAllocatedData data = {
.bs = top,
.base = base,
.sector_num = sector_num,
.nb_sectors = nb_sectors,
.pnum = pnum,
.done = false,
};
co = qemu_coroutine_create(bdrv_is_allocated_above_co_entry);
qemu_coroutine_enter(co, &data);
while (!data.done) {
qemu_aio_wait();
}
return data.ret;
}
BlockInfo *bdrv_query_info(BlockDriverState *bs)
{
BlockInfo *info = g_malloc0(sizeof(*info));
@ -2867,8 +2941,9 @@ BlockInfo *bdrv_query_info(BlockDriverState *bs)
if (bs->dirty_bitmap) {
info->has_dirty = true;
info->dirty = g_malloc0(sizeof(*info->dirty));
info->dirty->count = bdrv_get_dirty_count(bs) *
BDRV_SECTORS_PER_DIRTY_CHUNK * BDRV_SECTOR_SIZE;
info->dirty->count = bdrv_get_dirty_count(bs) * BDRV_SECTOR_SIZE;
info->dirty->granularity =
((int64_t) BDRV_SECTOR_SIZE << hbitmap_granularity(bs->dirty_bitmap));
}
if (bs->drv) {
@ -3157,7 +3232,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
if (bs->file) {
drv->bdrv_close(bs);
ret = bdrv_snapshot_goto(bs->file, snapshot_id);
open_ret = drv->bdrv_open(bs, bs->open_flags);
open_ret = drv->bdrv_open(bs, NULL, bs->open_flags);
if (open_ret < 0) {
bdrv_delete(bs->file);
bs->drv = NULL;
@ -3338,11 +3413,7 @@ char *get_human_readable_size(char *buf, int buf_size, int64_t size)
char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn)
{
char buf1[128], date_buf[128], clock_buf[128];
#ifdef _WIN32
struct tm *ptm;
#else
struct tm tm;
#endif
time_t ti;
int64_t secs;
@ -3352,15 +3423,9 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn)
"ID", "TAG", "VM SIZE", "DATE", "VM CLOCK");
} else {
ti = sn->date_sec;
#ifdef _WIN32
ptm = localtime(&ti);
strftime(date_buf, sizeof(date_buf),
"%Y-%m-%d %H:%M:%S", ptm);
#else
localtime_r(&ti, &tm);
strftime(date_buf, sizeof(date_buf),
"%Y-%m-%d %H:%M:%S", &tm);
#endif
secs = sn->vm_clock_nsec / 1000000000;
snprintf(clock_buf, sizeof(clock_buf),
"%02d:%02d:%02d.%03d",
@ -4184,7 +4249,18 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
return -EIO;
} else if (bs->read_only) {
return -EROFS;
} else if (bs->drv->bdrv_co_discard) {
}
if (bs->dirty_bitmap) {
bdrv_reset_dirty(bs, sector_num, nb_sectors);
}
/* Do nothing if disabled. */
if (!(bs->open_flags & BDRV_O_UNMAP)) {
return 0;
}
if (bs->drv->bdrv_co_discard) {
return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors);
} else if (bs->drv->bdrv_aio_discard) {
BlockDriverAIOCB *acb;
@ -4323,22 +4399,36 @@ void *qemu_blockalign(BlockDriverState *bs, size_t size)
return qemu_memalign((bs && bs->buffer_alignment) ? bs->buffer_alignment : 512, size);
}
void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable)
/*
* Check if all memory in this vector is sector aligned.
*/
bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
{
int i;
for (i = 0; i < qiov->niov; i++) {
if ((uintptr_t) qiov->iov[i].iov_base % bs->buffer_alignment) {
return false;
}
}
return true;
}
void bdrv_set_dirty_tracking(BlockDriverState *bs, int granularity)
{
int64_t bitmap_size;
bs->dirty_count = 0;
if (enable) {
if (!bs->dirty_bitmap) {
bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) +
BDRV_SECTORS_PER_DIRTY_CHUNK * BITS_PER_LONG - 1;
bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * BITS_PER_LONG;
assert((granularity & (granularity - 1)) == 0);
bs->dirty_bitmap = g_new0(unsigned long, bitmap_size);
}
if (granularity) {
granularity >>= BDRV_SECTOR_BITS;
assert(!bs->dirty_bitmap);
bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS);
bs->dirty_bitmap = hbitmap_alloc(bitmap_size, ffs(granularity) - 1);
} else {
if (bs->dirty_bitmap) {
g_free(bs->dirty_bitmap);
hbitmap_free(bs->dirty_bitmap);
bs->dirty_bitmap = NULL;
}
}
@ -4346,67 +4436,37 @@ void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable)
int bdrv_get_dirty(BlockDriverState *bs, int64_t sector)
{
int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
if (bs->dirty_bitmap &&
(sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) {
return !!(bs->dirty_bitmap[chunk / BITS_PER_LONG] &
(1UL << (chunk % BITS_PER_LONG)));
if (bs->dirty_bitmap) {
return hbitmap_get(bs->dirty_bitmap, sector);
} else {
return 0;
}
}
int64_t bdrv_get_next_dirty(BlockDriverState *bs, int64_t sector)
void bdrv_dirty_iter_init(BlockDriverState *bs, HBitmapIter *hbi)
{
int64_t chunk;
int bit, elem;
/* Avoid an infinite loop. */
assert(bs->dirty_count > 0);
sector = (sector | (BDRV_SECTORS_PER_DIRTY_CHUNK - 1)) + 1;
chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
QEMU_BUILD_BUG_ON(sizeof(bs->dirty_bitmap[0]) * 8 != BITS_PER_LONG);
elem = chunk / BITS_PER_LONG;
bit = chunk % BITS_PER_LONG;
for (;;) {
if (sector >= bs->total_sectors) {
sector = 0;
bit = elem = 0;
}
if (bit == 0 && bs->dirty_bitmap[elem] == 0) {
sector += BDRV_SECTORS_PER_DIRTY_CHUNK * BITS_PER_LONG;
elem++;
} else {
if (bs->dirty_bitmap[elem] & (1UL << bit)) {
return sector;
}
sector += BDRV_SECTORS_PER_DIRTY_CHUNK;
if (++bit == BITS_PER_LONG) {
bit = 0;
elem++;
}
}
}
hbitmap_iter_init(hbi, bs->dirty_bitmap, 0);
}
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
int nr_sectors)
{
set_dirty_bitmap(bs, cur_sector, nr_sectors, 1);
hbitmap_set(bs->dirty_bitmap, cur_sector, nr_sectors);
}
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
int nr_sectors)
{
set_dirty_bitmap(bs, cur_sector, nr_sectors, 0);
hbitmap_reset(bs->dirty_bitmap, cur_sector, nr_sectors);
}
int64_t bdrv_get_dirty_count(BlockDriverState *bs)
{
return bs->dirty_count;
if (bs->dirty_bitmap) {
return hbitmap_count(bs->dirty_bitmap);
} else {
return 0;
}
}
void bdrv_set_in_use(BlockDriverState *bs, int in_use)
@ -4483,7 +4543,8 @@ bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie)
void bdrv_img_create(const char *filename, const char *fmt,
const char *base_filename, const char *base_fmt,
char *options, uint64_t img_size, int flags, Error **errp)
char *options, uint64_t img_size, int flags,
Error **errp, bool quiet)
{
QEMUOptionParameter *param = NULL, *create_options = NULL;
QEMUOptionParameter *backing_fmt, *backing_file, *size;
@ -4575,7 +4636,8 @@ void bdrv_img_create(const char *filename, const char *fmt,
bs = bdrv_new("");
ret = bdrv_open(bs, backing_file->value.s, back_flags, backing_drv);
ret = bdrv_open(bs, backing_file->value.s, NULL, back_flags,
backing_drv);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not open '%s'",
backing_file->value.s);
@ -4592,10 +4654,11 @@ void bdrv_img_create(const char *filename, const char *fmt,
}
}
printf("Formatting '%s', fmt=%s ", filename, fmt);
print_option_parameters(param);
puts("");
if (!quiet) {
printf("Formatting '%s', fmt=%s ", filename, fmt);
print_option_parameters(param);
puts("");
}
ret = bdrv_create(drv, filename, param);
if (ret < 0) {
if (ret == -ENOTSUP) {
@ -4618,3 +4681,9 @@ out:
bdrv_delete(bs);
}
}
AioContext *bdrv_get_aio_context(BlockDriverState *bs)
{
/* Currently BlockDriverState always uses the main loop AioContext */
return qemu_get_aio_context();
}

View File

@ -98,7 +98,7 @@ static int blkverify_open(BlockDriverState *bs, const char *filename, int flags)
/* Open the test file */
s->test_file = bdrv_new("");
ret = bdrv_open(s->test_file, filename, flags, NULL);
ret = bdrv_open(s->test_file, filename, NULL, flags, NULL);
if (ret < 0) {
bdrv_delete(s->test_file);
s->test_file = NULL;

View File

@ -108,17 +108,19 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int bochs_open(BlockDriverState *bs, int flags)
static int bochs_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVBochsState *s = bs->opaque;
int i;
struct bochs_header bochs;
struct bochs_header_v1 header_v1;
int ret;
bs->read_only = 1; // no write support yet
if (bdrv_pread(bs->file, 0, &bochs, sizeof(bochs)) != sizeof(bochs)) {
goto fail;
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
if (ret < 0) {
return ret;
}
if (strcmp(bochs.magic, HEADER_MAGIC) ||
@ -126,7 +128,7 @@ static int bochs_open(BlockDriverState *bs, int flags)
strcmp(bochs.subtype, GROWING_TYPE) ||
((le32_to_cpu(bochs.version) != HEADER_VERSION) &&
(le32_to_cpu(bochs.version) != HEADER_V1))) {
goto fail;
return -EMEDIUMTYPE;
}
if (le32_to_cpu(bochs.version) == HEADER_V1) {
@ -138,9 +140,13 @@ static int bochs_open(BlockDriverState *bs, int flags)
s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
if (bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
s->catalog_size * 4) != s->catalog_size * 4)
goto fail;
ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
s->catalog_size * 4);
if (ret < 0) {
goto fail;
}
for (i = 0; i < s->catalog_size; i++)
le32_to_cpus(&s->catalog_bitmap[i]);
@ -153,8 +159,10 @@ static int bochs_open(BlockDriverState *bs, int flags)
qemu_co_mutex_init(&s->lock);
return 0;
fail:
return -1;
fail:
g_free(s->catalog_bitmap);
return ret;
}
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)

View File

@ -53,31 +53,36 @@ static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int cloop_open(BlockDriverState *bs, int flags)
static int cloop_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVCloopState *s = bs->opaque;
uint32_t offsets_size, max_compressed_block_size = 1, i;
int ret;
bs->read_only = 1;
/* read header */
if (bdrv_pread(bs->file, 128, &s->block_size, 4) < 4) {
goto cloop_close;
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
if (ret < 0) {
return ret;
}
s->block_size = be32_to_cpu(s->block_size);
if (bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4) < 4) {
goto cloop_close;
ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
if (ret < 0) {
return ret;
}
s->n_blocks = be32_to_cpu(s->n_blocks);
/* read offsets */
offsets_size = s->n_blocks * sizeof(uint64_t);
s->offsets = g_malloc(offsets_size);
if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) <
offsets_size) {
goto cloop_close;
ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
if (ret < 0) {
goto fail;
}
for(i=0;i<s->n_blocks;i++) {
s->offsets[i] = be64_to_cpu(s->offsets[i]);
if (i > 0) {
@ -92,7 +97,8 @@ static int cloop_open(BlockDriverState *bs, int flags)
s->compressed_block = g_malloc(max_compressed_block_size + 1);
s->uncompressed_block = g_malloc(s->block_size);
if (inflateInit(&s->zstream) != Z_OK) {
goto cloop_close;
ret = -EINVAL;
goto fail;
}
s->current_block = s->n_blocks;
@ -101,8 +107,11 @@ static int cloop_open(BlockDriverState *bs, int flags)
qemu_co_mutex_init(&s->lock);
return 0;
cloop_close:
return -1;
fail:
g_free(s->offsets);
g_free(s->compressed_block);
g_free(s->uncompressed_block);
return ret;
}
static inline int cloop_read_block(BlockDriverState *bs, int block_num)

View File

@ -65,7 +65,7 @@ static void coroutine_fn commit_run(void *opaque)
BlockDriverState *active = s->active;
BlockDriverState *top = s->top;
BlockDriverState *base = s->base;
BlockDriverState *overlay_bs = NULL;
BlockDriverState *overlay_bs;
int64_t sector_num, end;
int ret = 0;
int n = 0;
@ -92,8 +92,6 @@ static void coroutine_fn commit_run(void *opaque)
}
}
overlay_bs = bdrv_find_overlay(active, top);
end = s->common.len >> BDRV_SECTOR_BITS;
buf = qemu_blockalign(top, COMMIT_BUFFER_SIZE);
@ -156,7 +154,8 @@ exit_restore_reopen:
if (s->base_flags != bdrv_get_flags(base)) {
bdrv_reopen(base, s->base_flags, NULL);
}
if (s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) {
overlay_bs = bdrv_find_overlay(active, top);
if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) {
bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL);
}

View File

@ -58,7 +58,7 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int cow_open(BlockDriverState *bs, int flags)
static int cow_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVCowState *s = bs->opaque;
struct cow_header_v2 cow_header;
@ -73,7 +73,7 @@ static int cow_open(BlockDriverState *bs, int flags)
}
if (be32_to_cpu(cow_header.magic) != COW_MAGIC) {
ret = -EINVAL;
ret = -EMEDIUMTYPE;
goto fail;
}

View File

@ -34,6 +34,10 @@
#define DPRINTF(fmt, ...) do { } while (0)
#endif
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
CURLPROTO_FTP | CURLPROTO_FTPS | \
CURLPROTO_TFTP)
#define CURL_NUM_STATES 8
#define CURL_NUM_ACB 8
#define SECTOR_SIZE 512
@ -302,6 +306,17 @@ static CURLState *curl_init_state(BDRVCURLState *s)
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);
#endif
#ifdef DEBUG_VERBOSE
curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
#endif

View File

@ -57,29 +57,42 @@ static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static off_t read_off(BlockDriverState *bs, int64_t offset)
static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result)
{
uint64_t buffer;
if (bdrv_pread(bs->file, offset, &buffer, 8) < 8)
return 0;
return be64_to_cpu(buffer);
uint64_t buffer;
int ret;
ret = bdrv_pread(bs->file, offset, &buffer, 8);
if (ret < 0) {
return ret;
}
*result = be64_to_cpu(buffer);
return 0;
}
static off_t read_uint32(BlockDriverState *bs, int64_t offset)
static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
{
uint32_t buffer;
if (bdrv_pread(bs->file, offset, &buffer, 4) < 4)
return 0;
return be32_to_cpu(buffer);
uint32_t buffer;
int ret;
ret = bdrv_pread(bs->file, offset, &buffer, 4);
if (ret < 0) {
return ret;
}
*result = be32_to_cpu(buffer);
return 0;
}
static int dmg_open(BlockDriverState *bs, int flags)
static int dmg_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVDMGState *s = bs->opaque;
off_t info_begin,info_end,last_in_offset,last_out_offset;
uint32_t count;
uint64_t info_begin,info_end,last_in_offset,last_out_offset;
uint32_t count, tmp;
uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
int64_t offset;
int ret;
bs->read_only = 1;
s->n_chunks = 0;
@ -88,21 +101,32 @@ static int dmg_open(BlockDriverState *bs, int flags)
/* read offset of info blocks */
offset = bdrv_getlength(bs->file);
if (offset < 0) {
ret = offset;
goto fail;
}
offset -= 0x1d8;
info_begin = read_off(bs, offset);
if (info_begin == 0) {
goto fail;
}
if (read_uint32(bs, info_begin) != 0x100) {
ret = read_uint64(bs, offset, &info_begin);
if (ret < 0) {
goto fail;
} else if (info_begin == 0) {
ret = -EINVAL;
goto fail;
}
count = read_uint32(bs, info_begin + 4);
if (count == 0) {
ret = read_uint32(bs, info_begin, &tmp);
if (ret < 0) {
goto fail;
} else if (tmp != 0x100) {
ret = -EINVAL;
goto fail;
}
ret = read_uint32(bs, info_begin + 4, &count);
if (ret < 0) {
goto fail;
} else if (count == 0) {
ret = -EINVAL;
goto fail;
}
info_end = info_begin + count;
@ -114,12 +138,20 @@ static int dmg_open(BlockDriverState *bs, int flags)
while (offset < info_end) {
uint32_t type;
count = read_uint32(bs, offset);
if(count==0)
goto fail;
ret = read_uint32(bs, offset, &count);
if (ret < 0) {
goto fail;
} else if (count == 0) {
ret = -EINVAL;
goto fail;
}
offset += 4;
type = read_uint32(bs, offset);
ret = read_uint32(bs, offset, &type);
if (ret < 0) {
goto fail;
}
if (type == 0x6d697368 && count >= 244) {
int new_size, chunk_count;
@ -134,8 +166,11 @@ static int dmg_open(BlockDriverState *bs, int flags)
s->sectors = g_realloc(s->sectors, new_size);
s->sectorcounts = g_realloc(s->sectorcounts, new_size);
for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
s->types[i] = read_uint32(bs, offset);
for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) {
ret = read_uint32(bs, offset, &s->types[i]);
if (ret < 0) {
goto fail;
}
offset += 4;
if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
if(s->types[i]==0xffffffff) {
@ -149,17 +184,31 @@ static int dmg_open(BlockDriverState *bs, int flags)
}
offset += 4;
s->sectors[i] = last_out_offset+read_off(bs, offset);
offset += 8;
ret = read_uint64(bs, offset, &s->sectors[i]);
if (ret < 0) {
goto fail;
}
s->sectors[i] += last_out_offset;
offset += 8;
s->sectorcounts[i] = read_off(bs, offset);
offset += 8;
ret = read_uint64(bs, offset, &s->sectorcounts[i]);
if (ret < 0) {
goto fail;
}
offset += 8;
s->offsets[i] = last_in_offset+read_off(bs, offset);
offset += 8;
ret = read_uint64(bs, offset, &s->offsets[i]);
if (ret < 0) {
goto fail;
}
s->offsets[i] += last_in_offset;
offset += 8;
s->lengths[i] = read_off(bs, offset);
offset += 8;
ret = read_uint64(bs, offset, &s->lengths[i]);
if (ret < 0) {
goto fail;
}
offset += 8;
if(s->lengths[i]>max_compressed_size)
max_compressed_size = s->lengths[i];
@ -173,15 +222,25 @@ static int dmg_open(BlockDriverState *bs, int flags)
/* initialize zlib engine */
s->compressed_chunk = g_malloc(max_compressed_size+1);
s->uncompressed_chunk = g_malloc(512*max_sectors_per_chunk);
if(inflateInit(&s->zstream) != Z_OK)
goto fail;
if(inflateInit(&s->zstream) != Z_OK) {
ret = -EINVAL;
goto fail;
}
s->current_chunk = s->n_chunks;
qemu_co_mutex_init(&s->lock);
return 0;
fail:
return -1;
g_free(s->types);
g_free(s->offsets);
g_free(s->lengths);
g_free(s->sectors);
g_free(s->sectorcounts);
g_free(s->compressed_chunk);
g_free(s->uncompressed_chunk);
return ret;
}
static inline int is_sector_in_chunk(BDRVDMGState* s,
@ -296,15 +355,15 @@ static coroutine_fn int dmg_co_read(BlockDriverState *bs, int64_t sector_num,
static void dmg_close(BlockDriverState *bs)
{
BDRVDMGState *s = bs->opaque;
if(s->n_chunks>0) {
free(s->types);
free(s->offsets);
free(s->lengths);
free(s->sectors);
free(s->sectorcounts);
}
free(s->compressed_chunk);
free(s->uncompressed_chunk);
g_free(s->types);
g_free(s->offsets);
g_free(s->lengths);
g_free(s->sectors);
g_free(s->sectorcounts);
g_free(s->compressed_chunk);
g_free(s->uncompressed_chunk);
inflateEnd(&s->zstream);
}

View File

@ -217,7 +217,7 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename)
ret = glfs_init(glfs);
if (ret) {
error_report("Gluster connection failed for server=%s port=%d "
"volume=%s image=%s transport=%s\n", gconf->server, gconf->port,
"volume=%s image=%s transport=%s", gconf->server, gconf->port,
gconf->volname, gconf->image, gconf->transport);
goto out;
}

View File

@ -48,6 +48,7 @@ typedef struct IscsiLun {
int block_size;
uint64_t num_blocks;
int events;
QEMUTimer *nop_timer;
} IscsiLun;
typedef struct IscsiAIOCB {
@ -59,13 +60,20 @@ typedef struct IscsiAIOCB {
uint8_t *buf;
int status;
int canceled;
int retries;
size_t read_size;
size_t read_offset;
int64_t sector_num;
int nb_sectors;
#ifdef __linux__
sg_io_hdr_t *ioh;
#endif
} IscsiAIOCB;
#define NOP_INTERVAL 5000
#define MAX_NOP_FAILURES 3
#define ISCSI_CMD_RETRIES 5
static void
iscsi_bh_cb(void *p)
{
@ -73,6 +81,9 @@ iscsi_bh_cb(void *p)
qemu_bh_delete(acb->bh);
g_free(acb->buf);
acb->buf = NULL;
if (acb->canceled == 0) {
acb->common.cb(acb->common.opaque, acb->status);
}
@ -184,6 +195,8 @@ iscsi_process_write(void *arg)
iscsi_set_events(iscsilun);
}
static int
iscsi_aio_writev_acb(IscsiAIOCB *acb);
static void
iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
@ -194,13 +207,26 @@ iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
trace_iscsi_aio_write16_cb(iscsi, status, acb, acb->canceled);
g_free(acb->buf);
acb->buf = NULL;
if (acb->canceled != 0) {
return;
}
acb->status = 0;
if (status < 0) {
if (status != 0) {
if (status == SCSI_STATUS_CHECK_CONDITION
&& acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
&& acb->retries-- > 0) {
if (acb->task != NULL) {
scsi_free_scsi_task(acb->task);
acb->task = NULL;
}
if (iscsi_aio_writev_acb(acb) == 0) {
iscsi_set_events(acb->iscsilun);
return;
}
}
error_report("Failed to write16 data to iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
@ -214,6 +240,80 @@ static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
}
static int
iscsi_aio_writev_acb(IscsiAIOCB *acb)
{
struct iscsi_context *iscsi = acb->iscsilun->iscsi;
size_t size;
uint32_t num_sectors;
uint64_t lba;
#if !defined(LIBISCSI_FEATURE_IOVECTOR)
struct iscsi_data data;
#endif
int ret;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
/* this will allow us to get rid of 'buf' completely */
size = acb->nb_sectors * BDRV_SECTOR_SIZE;
#if !defined(LIBISCSI_FEATURE_IOVECTOR)
data.size = MIN(size, acb->qiov->size);
/* if the iovec only contains one buffer we can pass it directly */
if (acb->qiov->niov == 1) {
data.data = acb->qiov->iov[0].iov_base;
} else {
acb->buf = g_malloc(data.size);
qemu_iovec_to_buf(acb->qiov, 0, acb->buf, data.size);
data.data = acb->buf;
}
#endif
acb->task = malloc(sizeof(struct scsi_task));
if (acb->task == NULL) {
error_report("iSCSI: Failed to allocate task for scsi WRITE16 "
"command. %s", iscsi_get_error(iscsi));
return -1;
}
memset(acb->task, 0, sizeof(struct scsi_task));
acb->task->xfer_dir = SCSI_XFER_WRITE;
acb->task->cdb_size = 16;
acb->task->cdb[0] = 0x8a;
lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
*(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
*(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff);
num_sectors = size / acb->iscsilun->block_size;
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
acb->task->expxferlen = size;
#if defined(LIBISCSI_FEATURE_IOVECTOR)
ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task,
iscsi_aio_write16_cb,
NULL,
acb);
#else
ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task,
iscsi_aio_write16_cb,
&data,
acb);
#endif
if (ret != 0) {
g_free(acb->buf);
return -1;
}
#if defined(LIBISCSI_FEATURE_IOVECTOR)
scsi_task_set_iov_out(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->niov);
#endif
return 0;
}
static BlockDriverAIOCB *
iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
@ -221,66 +321,32 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
void *opaque)
{
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
IscsiAIOCB *acb;
size_t size;
uint32_t num_sectors;
uint64_t lba;
struct iscsi_data data;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
trace_iscsi_aio_writev(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
acb->iscsilun = iscsilun;
acb->qiov = qiov;
acb->iscsilun = iscsilun;
acb->qiov = qiov;
acb->nb_sectors = nb_sectors;
acb->sector_num = sector_num;
acb->retries = ISCSI_CMD_RETRIES;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
/* XXX we should pass the iovec to write16 to avoid the extra copy */
/* this will allow us to get rid of 'buf' completely */
size = nb_sectors * BDRV_SECTOR_SIZE;
acb->buf = g_malloc(size);
qemu_iovec_to_buf(acb->qiov, 0, acb->buf, size);
acb->task = malloc(sizeof(struct scsi_task));
if (acb->task == NULL) {
error_report("iSCSI: Failed to allocate task for scsi WRITE16 "
"command. %s", iscsi_get_error(iscsi));
qemu_aio_release(acb);
return NULL;
}
memset(acb->task, 0, sizeof(struct scsi_task));
acb->task->xfer_dir = SCSI_XFER_WRITE;
acb->task->cdb_size = 16;
acb->task->cdb[0] = 0x8a;
lba = sector_qemu2lun(sector_num, iscsilun);
*(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
*(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff);
num_sectors = size / iscsilun->block_size;
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
acb->task->expxferlen = size;
data.data = acb->buf;
data.size = size;
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
iscsi_aio_write16_cb,
&data,
acb) != 0) {
scsi_free_scsi_task(acb->task);
g_free(acb->buf);
if (iscsi_aio_writev_acb(acb) != 0) {
if (acb->task) {
scsi_free_scsi_task(acb->task);
}
qemu_aio_release(acb);
return NULL;
}
iscsi_set_events(iscsilun);
return &acb->common;
}
static int
iscsi_aio_readv_acb(IscsiAIOCB *acb);
static void
iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
@ -295,6 +361,18 @@ iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
acb->status = 0;
if (status != 0) {
if (status == SCSI_STATUS_CHECK_CONDITION
&& acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
&& acb->retries-- > 0) {
if (acb->task != NULL) {
scsi_free_scsi_task(acb->task);
acb->task = NULL;
}
if (iscsi_aio_readv_acb(acb) == 0) {
iscsi_set_events(acb->iscsilun);
return;
}
}
error_report("Failed to read16 data from iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
@ -303,32 +381,20 @@ iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
iscsi_schedule_bh(acb);
}
static BlockDriverAIOCB *
iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
static int
iscsi_aio_readv_acb(IscsiAIOCB *acb)
{
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
IscsiAIOCB *acb;
size_t qemu_read_size;
int i;
struct iscsi_context *iscsi = acb->iscsilun->iscsi;
uint64_t lba;
uint32_t num_sectors;
qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
acb->iscsilun = iscsilun;
acb->qiov = qiov;
int ret;
#if !defined(LIBISCSI_FEATURE_IOVECTOR)
int i;
#endif
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->read_size = qemu_read_size;
acb->buf = NULL;
/* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU
@ -336,30 +402,29 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
* data.
*/
acb->read_offset = 0;
if (iscsilun->block_size > BDRV_SECTOR_SIZE) {
uint64_t bdrv_offset = BDRV_SECTOR_SIZE * sector_num;
if (acb->iscsilun->block_size > BDRV_SECTOR_SIZE) {
uint64_t bdrv_offset = BDRV_SECTOR_SIZE * acb->sector_num;
acb->read_offset = bdrv_offset % iscsilun->block_size;
acb->read_offset = bdrv_offset % acb->iscsilun->block_size;
}
num_sectors = (qemu_read_size + iscsilun->block_size
num_sectors = (acb->read_size + acb->iscsilun->block_size
+ acb->read_offset - 1)
/ iscsilun->block_size;
/ acb->iscsilun->block_size;
acb->task = malloc(sizeof(struct scsi_task));
if (acb->task == NULL) {
error_report("iSCSI: Failed to allocate task for scsi READ16 "
"command. %s", iscsi_get_error(iscsi));
qemu_aio_release(acb);
return NULL;
return -1;
}
memset(acb->task, 0, sizeof(struct scsi_task));
acb->task->xfer_dir = SCSI_XFER_READ;
lba = sector_qemu2lun(sector_num, iscsilun);
acb->task->expxferlen = qemu_read_size;
lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
acb->task->expxferlen = acb->read_size;
switch (iscsilun->type) {
switch (acb->iscsilun->type) {
case TYPE_DISK:
acb->task->cdb_size = 16;
acb->task->cdb[0] = 0x88;
@ -375,26 +440,59 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
break;
}
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
iscsi_aio_read16_cb,
NULL,
acb) != 0) {
scsi_free_scsi_task(acb->task);
qemu_aio_release(acb);
return NULL;
ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task,
iscsi_aio_read16_cb,
NULL,
acb);
if (ret != 0) {
return -1;
}
#if defined(LIBISCSI_FEATURE_IOVECTOR)
scsi_task_set_iov_in(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->niov);
#else
for (i = 0; i < acb->qiov->niov; i++) {
scsi_task_add_data_in_buffer(acb->task,
acb->qiov->iov[i].iov_len,
acb->qiov->iov[i].iov_base);
}
#endif
return 0;
}
static BlockDriverAIOCB *
iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
{
IscsiLun *iscsilun = bs->opaque;
IscsiAIOCB *acb;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
trace_iscsi_aio_readv(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
acb->nb_sectors = nb_sectors;
acb->sector_num = sector_num;
acb->iscsilun = iscsilun;
acb->qiov = qiov;
acb->read_size = BDRV_SECTOR_SIZE * (size_t)acb->nb_sectors;
acb->retries = ISCSI_CMD_RETRIES;
if (iscsi_aio_readv_acb(acb) != 0) {
if (acb->task) {
scsi_free_scsi_task(acb->task);
}
qemu_aio_release(acb);
return NULL;
}
iscsi_set_events(iscsilun);
return &acb->common;
}
static int
iscsi_aio_flush_acb(IscsiAIOCB *acb);
static void
iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
@ -407,7 +505,19 @@ iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
}
acb->status = 0;
if (status < 0) {
if (status != 0) {
if (status == SCSI_STATUS_CHECK_CONDITION
&& acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
&& acb->retries-- > 0) {
if (acb->task != NULL) {
scsi_free_scsi_task(acb->task);
acb->task = NULL;
}
if (iscsi_aio_flush_acb(acb) == 0) {
iscsi_set_events(acb->iscsilun);
return;
}
}
error_report("Failed to sync10 data on iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
@ -416,28 +526,43 @@ iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
iscsi_schedule_bh(acb);
}
static BlockDriverAIOCB *
iscsi_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
static int
iscsi_aio_flush_acb(IscsiAIOCB *acb)
{
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
IscsiAIOCB *acb;
struct iscsi_context *iscsi = acb->iscsilun->iscsi;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun,
acb->task = iscsi_synchronizecache10_task(iscsi, acb->iscsilun->lun,
0, 0, 0, 0,
iscsi_synccache10_cb,
acb);
if (acb->task == NULL) {
error_report("iSCSI: Failed to send synchronizecache10 command. %s",
iscsi_get_error(iscsi));
return -1;
}
return 0;
}
static BlockDriverAIOCB *
iscsi_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
IscsiLun *iscsilun = bs->opaque;
IscsiAIOCB *acb;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->retries = ISCSI_CMD_RETRIES;
if (iscsi_aio_flush_acb(acb) != 0) {
qemu_aio_release(acb);
return NULL;
}
@ -447,6 +572,8 @@ iscsi_aio_flush(BlockDriverState *bs,
return &acb->common;
}
static int iscsi_aio_discard_acb(IscsiAIOCB *acb);
static void
iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
@ -458,7 +585,19 @@ iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
}
acb->status = 0;
if (status < 0) {
if (status != 0) {
if (status == SCSI_STATUS_CHECK_CONDITION
&& acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
&& acb->retries-- > 0) {
if (acb->task != NULL) {
scsi_free_scsi_task(acb->task);
acb->task = NULL;
}
if (iscsi_aio_discard_acb(acb) == 0) {
iscsi_set_events(acb->iscsilun);
return;
}
}
error_report("Failed to unmap data on iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
@ -467,33 +606,50 @@ iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
iscsi_schedule_bh(acb);
}
static BlockDriverAIOCB *
iscsi_aio_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
IscsiAIOCB *acb;
static int iscsi_aio_discard_acb(IscsiAIOCB *acb) {
struct iscsi_context *iscsi = acb->iscsilun->iscsi;
struct unmap_list list[1];
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
list[0].lba = sector_qemu2lun(sector_num, iscsilun);
list[0].num = nb_sectors * BDRV_SECTOR_SIZE / iscsilun->block_size;
list[0].lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
list[0].num = acb->nb_sectors * BDRV_SECTOR_SIZE / acb->iscsilun->block_size;
acb->task = iscsi_unmap_task(iscsi, iscsilun->lun,
acb->task = iscsi_unmap_task(iscsi, acb->iscsilun->lun,
0, 0, &list[0], 1,
iscsi_unmap_cb,
acb);
if (acb->task == NULL) {
error_report("iSCSI: Failed to send unmap command. %s",
iscsi_get_error(iscsi));
return -1;
}
return 0;
}
static BlockDriverAIOCB *
iscsi_aio_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
IscsiLun *iscsilun = bs->opaque;
IscsiAIOCB *acb;
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->nb_sectors = nb_sectors;
acb->sector_num = sector_num;
acb->retries = ISCSI_CMD_RETRIES;
if (iscsi_aio_discard_acb(acb) != 0) {
if (acb->task) {
scsi_free_scsi_task(acb->task);
}
qemu_aio_release(acb);
return NULL;
}
@ -762,6 +918,91 @@ static char *parse_initiator_name(const char *target)
}
}
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
static void iscsi_nop_timed_event(void *opaque)
{
IscsiLun *iscsilun = opaque;
if (iscsi_get_nops_in_flight(iscsilun->iscsi) > MAX_NOP_FAILURES) {
error_report("iSCSI: NOP timeout. Reconnecting...");
iscsi_reconnect(iscsilun->iscsi);
}
if (iscsi_nop_out_async(iscsilun->iscsi, NULL, NULL, 0, NULL) != 0) {
error_report("iSCSI: failed to sent NOP-Out. Disabling NOP messages.");
return;
}
qemu_mod_timer(iscsilun->nop_timer, qemu_get_clock_ms(rt_clock) + NOP_INTERVAL);
iscsi_set_events(iscsilun);
}
#endif
static int iscsi_readcapacity_sync(IscsiLun *iscsilun)
{
struct scsi_task *task = NULL;
struct scsi_readcapacity10 *rc10 = NULL;
struct scsi_readcapacity16 *rc16 = NULL;
int ret = 0;
int retries = ISCSI_CMD_RETRIES;
try_again:
switch (iscsilun->type) {
case TYPE_DISK:
task = iscsi_readcapacity16_sync(iscsilun->iscsi, iscsilun->lun);
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
if (task != NULL && task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_UNIT_ATTENTION
&& retries-- > 0) {
scsi_free_scsi_task(task);
goto try_again;
}
error_report("iSCSI: failed to send readcapacity16 command.");
ret = -EINVAL;
goto out;
}
rc16 = scsi_datain_unmarshall(task);
if (rc16 == NULL) {
error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
ret = -EINVAL;
goto out;
}
iscsilun->block_size = rc16->block_length;
iscsilun->num_blocks = rc16->returned_lba + 1;
break;
case TYPE_ROM:
task = iscsi_readcapacity10_sync(iscsilun->iscsi, iscsilun->lun, 0, 0);
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
error_report("iSCSI: failed to send readcapacity10 command.");
ret = -EINVAL;
goto out;
}
rc10 = scsi_datain_unmarshall(task);
if (rc10 == NULL) {
error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
ret = -EINVAL;
goto out;
}
iscsilun->block_size = rc10->block_size;
if (rc10->lba == 0) {
/* blank disk loaded */
iscsilun->num_blocks = 0;
} else {
iscsilun->num_blocks = rc10->lba + 1;
}
break;
default:
break;
}
out:
if (task) {
scsi_free_scsi_task(task);
}
return ret;
}
/*
* We support iscsi url's on the form
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
@ -773,8 +1014,6 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
struct iscsi_url *iscsi_url = NULL;
struct scsi_task *task = NULL;
struct scsi_inquiry_standard *inq = NULL;
struct scsi_readcapacity10 *rc10 = NULL;
struct scsi_readcapacity16 *rc16 = NULL;
char *initiator_name = NULL;
int ret;
@ -864,50 +1103,9 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
iscsilun->type = inq->periperal_device_type;
scsi_free_scsi_task(task);
switch (iscsilun->type) {
case TYPE_DISK:
task = iscsi_readcapacity16_sync(iscsi, iscsilun->lun);
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
error_report("iSCSI: failed to send readcapacity16 command.");
ret = -EINVAL;
goto out;
}
rc16 = scsi_datain_unmarshall(task);
if (rc16 == NULL) {
error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
ret = -EINVAL;
goto out;
}
iscsilun->block_size = rc16->block_length;
iscsilun->num_blocks = rc16->returned_lba + 1;
break;
case TYPE_ROM:
task = iscsi_readcapacity10_sync(iscsi, iscsilun->lun, 0, 0);
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
error_report("iSCSI: failed to send readcapacity10 command.");
ret = -EINVAL;
goto out;
}
rc10 = scsi_datain_unmarshall(task);
if (rc10 == NULL) {
error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
ret = -EINVAL;
goto out;
}
iscsilun->block_size = rc10->block_size;
if (rc10->lba == 0) {
/* blank disk loaded */
iscsilun->num_blocks = 0;
} else {
iscsilun->num_blocks = rc10->lba + 1;
}
break;
default:
break;
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
goto out;
}
bs->total_sectors = iscsilun->num_blocks *
iscsilun->block_size / BDRV_SECTOR_SIZE ;
@ -920,7 +1118,11 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
bs->sg = 1;
}
ret = 0;
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
/* Set up a timer for sending out iSCSI NOPs */
iscsilun->nop_timer = qemu_new_timer_ms(rt_clock, iscsi_nop_timed_event, iscsilun);
qemu_mod_timer(iscsilun->nop_timer, qemu_get_clock_ms(rt_clock) + NOP_INTERVAL);
#endif
out:
if (initiator_name != NULL) {
@ -947,16 +1149,94 @@ static void iscsi_close(BlockDriverState *bs)
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
if (iscsilun->nop_timer) {
qemu_del_timer(iscsilun->nop_timer);
qemu_free_timer(iscsilun->nop_timer);
}
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL);
iscsi_destroy_context(iscsi);
memset(iscsilun, 0, sizeof(IscsiLun));
}
static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
{
IscsiLun *iscsilun = bs->opaque;
int ret = 0;
if (iscsilun->type != TYPE_DISK) {
return -ENOTSUP;
}
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
return ret;
}
if (offset > iscsi_getlength(bs)) {
return -EINVAL;
}
return 0;
}
static int iscsi_has_zero_init(BlockDriverState *bs)
{
return 0;
}
static int iscsi_create(const char *filename, QEMUOptionParameter *options)
{
int ret = 0;
int64_t total_size = 0;
BlockDriverState bs;
IscsiLun *iscsilun = NULL;
memset(&bs, 0, sizeof(BlockDriverState));
/* Read out options */
while (options && options->name) {
if (!strcmp(options->name, "size")) {
total_size = options->value.n / BDRV_SECTOR_SIZE;
}
options++;
}
bs.opaque = g_malloc0(sizeof(struct IscsiLun));
iscsilun = bs.opaque;
ret = iscsi_open(&bs, filename, 0);
if (ret != 0) {
goto out;
}
if (iscsilun->nop_timer) {
qemu_del_timer(iscsilun->nop_timer);
qemu_free_timer(iscsilun->nop_timer);
}
if (iscsilun->type != TYPE_DISK) {
ret = -ENODEV;
goto out;
}
if (bs.total_sectors < total_size) {
ret = -ENOSPC;
}
ret = 0;
out:
if (iscsilun->iscsi != NULL) {
iscsi_destroy_context(iscsilun->iscsi);
}
g_free(bs.opaque);
return ret;
}
static QEMUOptionParameter iscsi_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
.type = OPT_SIZE,
.help = "Virtual disk size"
},
{ NULL }
};
static BlockDriver bdrv_iscsi = {
.format_name = "iscsi",
.protocol_name = "iscsi",
@ -964,8 +1244,11 @@ static BlockDriver bdrv_iscsi = {
.instance_size = sizeof(IscsiLun),
.bdrv_file_open = iscsi_open,
.bdrv_close = iscsi_close,
.bdrv_create = iscsi_create,
.create_options = iscsi_create_options,
.bdrv_getlength = iscsi_getlength,
.bdrv_truncate = iscsi_truncate,
.bdrv_aio_readv = iscsi_aio_readv,
.bdrv_aio_writev = iscsi_aio_writev,
@ -980,9 +1263,36 @@ static BlockDriver bdrv_iscsi = {
#endif
};
static QemuOptsList qemu_iscsi_opts = {
.name = "iscsi",
.head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head),
.desc = {
{
.name = "user",
.type = QEMU_OPT_STRING,
.help = "username for CHAP authentication to target",
},{
.name = "password",
.type = QEMU_OPT_STRING,
.help = "password for CHAP authentication to target",
},{
.name = "header-digest",
.type = QEMU_OPT_STRING,
.help = "HeaderDigest setting. "
"{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}",
},{
.name = "initiator-name",
.type = QEMU_OPT_STRING,
.help = "Initiator iqn name to use when connecting",
},
{ /* end of list */ }
},
};
static void iscsi_block_init(void)
{
bdrv_register(&bdrv_iscsi);
qemu_add_opts(&qemu_iscsi_opts);
}
block_init(iscsi_block_init);

View File

@ -15,17 +15,17 @@
#include "block/blockjob.h"
#include "block/block_int.h"
#include "qemu/ratelimit.h"
#include "qemu/bitmap.h"
enum {
/*
* Size of data buffer for populating the image file. This should be large
* enough to process multiple clusters in a single call, so that populating
* contiguous regions of the image is efficient.
*/
BLOCK_SIZE = 512 * BDRV_SECTORS_PER_DIRTY_CHUNK, /* in bytes */
};
#define SLICE_TIME 100000000ULL /* ns */
#define MAX_IN_FLIGHT 16
#define SLICE_TIME 100000000ULL /* ns */
/* The mirroring buffer is a list of granularity-sized chunks.
* Free chunks are organized in a list.
*/
typedef struct MirrorBuffer {
QSIMPLEQ_ENTRY(MirrorBuffer) next;
} MirrorBuffer;
typedef struct MirrorBlockJob {
BlockJob common;
@ -36,9 +36,26 @@ typedef struct MirrorBlockJob {
bool synced;
bool should_complete;
int64_t sector_num;
int64_t granularity;
size_t buf_size;
unsigned long *cow_bitmap;
HBitmapIter hbi;
uint8_t *buf;
QSIMPLEQ_HEAD(, MirrorBuffer) buf_free;
int buf_free_count;
unsigned long *in_flight_bitmap;
int in_flight;
int ret;
} MirrorBlockJob;
typedef struct MirrorOp {
MirrorBlockJob *s;
QEMUIOVector qiov;
int64_t sector_num;
int nb_sectors;
} MirrorOp;
static BlockErrorAction mirror_error_action(MirrorBlockJob *s, bool read,
int error)
{
@ -52,51 +69,234 @@ static BlockErrorAction mirror_error_action(MirrorBlockJob *s, bool read,
}
}
static int coroutine_fn mirror_iteration(MirrorBlockJob *s,
BlockErrorAction *p_action)
static void mirror_iteration_done(MirrorOp *op, int ret)
{
MirrorBlockJob *s = op->s;
struct iovec *iov;
int64_t chunk_num;
int i, nb_chunks, sectors_per_chunk;
trace_mirror_iteration_done(s, op->sector_num, op->nb_sectors, ret);
s->in_flight--;
iov = op->qiov.iov;
for (i = 0; i < op->qiov.niov; i++) {
MirrorBuffer *buf = (MirrorBuffer *) iov[i].iov_base;
QSIMPLEQ_INSERT_TAIL(&s->buf_free, buf, next);
s->buf_free_count++;
}
sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS;
chunk_num = op->sector_num / sectors_per_chunk;
nb_chunks = op->nb_sectors / sectors_per_chunk;
bitmap_clear(s->in_flight_bitmap, chunk_num, nb_chunks);
if (s->cow_bitmap && ret >= 0) {
bitmap_set(s->cow_bitmap, chunk_num, nb_chunks);
}
g_slice_free(MirrorOp, op);
qemu_coroutine_enter(s->common.co, NULL);
}
static void mirror_write_complete(void *opaque, int ret)
{
MirrorOp *op = opaque;
MirrorBlockJob *s = op->s;
if (ret < 0) {
BlockDriverState *source = s->common.bs;
BlockErrorAction action;
bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
action = mirror_error_action(s, false, -ret);
if (action == BDRV_ACTION_REPORT && s->ret >= 0) {
s->ret = ret;
}
}
mirror_iteration_done(op, ret);
}
static void mirror_read_complete(void *opaque, int ret)
{
MirrorOp *op = opaque;
MirrorBlockJob *s = op->s;
if (ret < 0) {
BlockDriverState *source = s->common.bs;
BlockErrorAction action;
bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
action = mirror_error_action(s, true, -ret);
if (action == BDRV_ACTION_REPORT && s->ret >= 0) {
s->ret = ret;
}
mirror_iteration_done(op, ret);
return;
}
bdrv_aio_writev(s->target, op->sector_num, &op->qiov, op->nb_sectors,
mirror_write_complete, op);
}
static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
{
BlockDriverState *source = s->common.bs;
BlockDriverState *target = s->target;
QEMUIOVector qiov;
int ret, nb_sectors;
int64_t end;
struct iovec iov;
int nb_sectors, sectors_per_chunk, nb_chunks;
int64_t end, sector_num, next_chunk, next_sector, hbitmap_next_sector;
MirrorOp *op;
s->sector_num = hbitmap_iter_next(&s->hbi);
if (s->sector_num < 0) {
bdrv_dirty_iter_init(source, &s->hbi);
s->sector_num = hbitmap_iter_next(&s->hbi);
trace_mirror_restart_iter(s, bdrv_get_dirty_count(source));
assert(s->sector_num >= 0);
}
hbitmap_next_sector = s->sector_num;
sector_num = s->sector_num;
sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS;
end = s->common.len >> BDRV_SECTOR_BITS;
s->sector_num = bdrv_get_next_dirty(source, s->sector_num);
nb_sectors = MIN(BDRV_SECTORS_PER_DIRTY_CHUNK, end - s->sector_num);
bdrv_reset_dirty(source, s->sector_num, nb_sectors);
/* Extend the QEMUIOVector to include all adjacent blocks that will
* be copied in this operation.
*
* We have to do this if we have no backing file yet in the destination,
* and the cluster size is very large. Then we need to do COW ourselves.
* The first time a cluster is copied, copy it entirely. Note that,
* because both the granularity and the cluster size are powers of two,
* the number of sectors to copy cannot exceed one cluster.
*
* We also want to extend the QEMUIOVector to include more adjacent
* dirty blocks if possible, to limit the number of I/O operations and
* run efficiently even with a small granularity.
*/
nb_chunks = 0;
nb_sectors = 0;
next_sector = sector_num;
next_chunk = sector_num / sectors_per_chunk;
/* Wait for I/O to this cluster (from a previous iteration) to be done. */
while (test_bit(next_chunk, s->in_flight_bitmap)) {
trace_mirror_yield_in_flight(s, sector_num, s->in_flight);
qemu_coroutine_yield();
}
do {
int added_sectors, added_chunks;
if (!bdrv_get_dirty(source, next_sector) ||
test_bit(next_chunk, s->in_flight_bitmap)) {
assert(nb_sectors > 0);
break;
}
added_sectors = sectors_per_chunk;
if (s->cow_bitmap && !test_bit(next_chunk, s->cow_bitmap)) {
bdrv_round_to_clusters(s->target,
next_sector, added_sectors,
&next_sector, &added_sectors);
/* On the first iteration, the rounding may make us copy
* sectors before the first dirty one.
*/
if (next_sector < sector_num) {
assert(nb_sectors == 0);
sector_num = next_sector;
next_chunk = next_sector / sectors_per_chunk;
}
}
added_sectors = MIN(added_sectors, end - (sector_num + nb_sectors));
added_chunks = (added_sectors + sectors_per_chunk - 1) / sectors_per_chunk;
/* When doing COW, it may happen that there is not enough space for
* a full cluster. Wait if that is the case.
*/
while (nb_chunks == 0 && s->buf_free_count < added_chunks) {
trace_mirror_yield_buf_busy(s, nb_chunks, s->in_flight);
qemu_coroutine_yield();
}
if (s->buf_free_count < nb_chunks + added_chunks) {
trace_mirror_break_buf_busy(s, nb_chunks, s->in_flight);
break;
}
/* We have enough free space to copy these sectors. */
bitmap_set(s->in_flight_bitmap, next_chunk, added_chunks);
nb_sectors += added_sectors;
nb_chunks += added_chunks;
next_sector += added_sectors;
next_chunk += added_chunks;
} while (next_sector < end);
/* Allocate a MirrorOp that is used as an AIO callback. */
op = g_slice_new(MirrorOp);
op->s = s;
op->sector_num = sector_num;
op->nb_sectors = nb_sectors;
/* Now make a QEMUIOVector taking enough granularity-sized chunks
* from s->buf_free.
*/
qemu_iovec_init(&op->qiov, nb_chunks);
next_sector = sector_num;
while (nb_chunks-- > 0) {
MirrorBuffer *buf = QSIMPLEQ_FIRST(&s->buf_free);
QSIMPLEQ_REMOVE_HEAD(&s->buf_free, next);
s->buf_free_count--;
qemu_iovec_add(&op->qiov, buf, s->granularity);
/* Advance the HBitmapIter in parallel, so that we do not examine
* the same sector twice.
*/
if (next_sector > hbitmap_next_sector && bdrv_get_dirty(source, next_sector)) {
hbitmap_next_sector = hbitmap_iter_next(&s->hbi);
}
next_sector += sectors_per_chunk;
}
bdrv_reset_dirty(source, sector_num, nb_sectors);
/* Copy the dirty cluster. */
iov.iov_base = s->buf;
iov.iov_len = nb_sectors * 512;
qemu_iovec_init_external(&qiov, &iov, 1);
s->in_flight++;
trace_mirror_one_iteration(s, sector_num, nb_sectors);
bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors,
mirror_read_complete, op);
}
trace_mirror_one_iteration(s, s->sector_num, nb_sectors);
ret = bdrv_co_readv(source, s->sector_num, nb_sectors, &qiov);
if (ret < 0) {
*p_action = mirror_error_action(s, true, -ret);
goto fail;
}
ret = bdrv_co_writev(target, s->sector_num, nb_sectors, &qiov);
if (ret < 0) {
*p_action = mirror_error_action(s, false, -ret);
s->synced = false;
goto fail;
}
return 0;
static void mirror_free_init(MirrorBlockJob *s)
{
int granularity = s->granularity;
size_t buf_size = s->buf_size;
uint8_t *buf = s->buf;
fail:
/* Try again later. */
bdrv_set_dirty(source, s->sector_num, nb_sectors);
return ret;
assert(s->buf_free_count == 0);
QSIMPLEQ_INIT(&s->buf_free);
while (buf_size != 0) {
MirrorBuffer *cur = (MirrorBuffer *)buf;
QSIMPLEQ_INSERT_TAIL(&s->buf_free, cur, next);
s->buf_free_count++;
buf_size -= granularity;
buf += granularity;
}
}
static void mirror_drain(MirrorBlockJob *s)
{
while (s->in_flight > 0) {
qemu_coroutine_yield();
}
}
static void coroutine_fn mirror_run(void *opaque)
{
MirrorBlockJob *s = opaque;
BlockDriverState *bs = s->common.bs;
int64_t sector_num, end;
int64_t sector_num, end, sectors_per_chunk, length;
uint64_t last_pause_ns;
BlockDriverInfo bdi;
char backing_filename[1024];
int ret = 0;
int n;
@ -105,20 +305,39 @@ static void coroutine_fn mirror_run(void *opaque)
}
s->common.len = bdrv_getlength(bs);
if (s->common.len < 0) {
if (s->common.len <= 0) {
block_job_completed(&s->common, s->common.len);
return;
}
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
* the destination do COW. Instead, we copy sectors around the
* dirty data if needed. We need a bitmap to do that.
*/
bdrv_get_backing_filename(s->target, backing_filename,
sizeof(backing_filename));
if (backing_filename[0] && !s->target->backing_hd) {
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);
}
}
end = s->common.len >> BDRV_SECTOR_BITS;
s->buf = qemu_blockalign(bs, BLOCK_SIZE);
s->buf = qemu_blockalign(bs, s->buf_size);
sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS;
mirror_free_init(s);
if (s->mode != MIRROR_SYNC_MODE_NONE) {
/* First part, loop on the sectors and initialize the dirty bitmap. */
BlockDriverState *base;
base = s->mode == MIRROR_SYNC_MODE_FULL ? NULL : bs->backing_hd;
for (sector_num = 0; sector_num < end; ) {
int64_t next = (sector_num | (BDRV_SECTORS_PER_DIRTY_CHUNK - 1)) + 1;
int64_t next = (sector_num | (sectors_per_chunk - 1)) + 1;
ret = bdrv_co_is_allocated_above(bs, base,
sector_num, next - sector_num, &n);
@ -136,24 +355,40 @@ static void coroutine_fn mirror_run(void *opaque)
}
}
s->sector_num = -1;
bdrv_dirty_iter_init(bs, &s->hbi);
last_pause_ns = qemu_get_clock_ns(rt_clock);
for (;;) {
uint64_t delay_ns;
int64_t cnt;
bool should_complete;
if (s->ret < 0) {
ret = s->ret;
goto immediate_exit;
}
cnt = bdrv_get_dirty_count(bs);
if (cnt != 0) {
BlockErrorAction action = BDRV_ACTION_REPORT;
ret = mirror_iteration(s, &action);
if (ret < 0 && action == BDRV_ACTION_REPORT) {
goto immediate_exit;
/* Note that even when no rate limit is applied we need to yield
* periodically with no pending I/O so that qemu_aio_flush() returns.
* We do so every SLICE_TIME nanoseconds, or when there is an error,
* or when the source is clean, whichever comes first.
*/
if (qemu_get_clock_ns(rt_clock) - last_pause_ns < SLICE_TIME &&
s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
if (s->in_flight == MAX_IN_FLIGHT || s->buf_free_count == 0 ||
(cnt == 0 && s->in_flight > 0)) {
trace_mirror_yield(s, s->in_flight, s->buf_free_count, cnt);
qemu_coroutine_yield();
continue;
} else if (cnt != 0) {
mirror_iteration(s);
continue;
}
cnt = bdrv_get_dirty_count(bs);
}
should_complete = false;
if (cnt == 0) {
if (s->in_flight == 0 && cnt == 0) {
trace_mirror_before_flush(s);
ret = bdrv_flush(s->target);
if (ret < 0) {
@ -196,23 +431,20 @@ static void coroutine_fn mirror_run(void *opaque)
trace_mirror_before_sleep(s, cnt, s->synced);
if (!s->synced) {
/* Publish progress */
s->common.offset = end * BDRV_SECTOR_SIZE - cnt * BLOCK_SIZE;
s->common.offset = (end - cnt) * BDRV_SECTOR_SIZE;
if (s->common.speed) {
delay_ns = ratelimit_calculate_delay(&s->limit, BDRV_SECTORS_PER_DIRTY_CHUNK);
delay_ns = ratelimit_calculate_delay(&s->limit, sectors_per_chunk);
} else {
delay_ns = 0;
}
/* Note that even when no rate limit is applied we need to yield
* with no pending I/O here so that bdrv_drain_all() returns.
*/
block_job_sleep_ns(&s->common, rt_clock, delay_ns);
if (block_job_is_cancelled(&s->common)) {
break;
}
} else if (!should_complete) {
delay_ns = (cnt == 0 ? SLICE_TIME : 0);
delay_ns = (s->in_flight == 0 && cnt == 0 ? SLICE_TIME : 0);
block_job_sleep_ns(&s->common, rt_clock, delay_ns);
} else if (cnt == 0) {
/* The two disks are in sync. Exit and report successful
@ -222,11 +454,24 @@ static void coroutine_fn mirror_run(void *opaque)
s->common.cancelled = false;
break;
}
last_pause_ns = qemu_get_clock_ns(rt_clock);
}
immediate_exit:
g_free(s->buf);
bdrv_set_dirty_tracking(bs, false);
if (s->in_flight > 0) {
/* We get here only if something went wrong. Either the job failed,
* or it was cancelled prematurely so that we do not guarantee that
* the target is a copy of the source.
*/
assert(ret < 0 || (!s->synced && block_job_is_cancelled(&s->common)));
mirror_drain(s);
}
assert(s->in_flight == 0);
qemu_vfree(s->buf);
g_free(s->cow_bitmap);
g_free(s->in_flight_bitmap);
bdrv_set_dirty_tracking(bs, 0);
bdrv_iostatus_disable(s->target);
if (s->should_complete && ret == 0) {
if (bdrv_get_flags(s->target) != bdrv_get_flags(s->common.bs)) {
@ -288,14 +533,28 @@ static BlockJobType mirror_job_type = {
};
void mirror_start(BlockDriverState *bs, BlockDriverState *target,
int64_t speed, MirrorSyncMode mode,
BlockdevOnError on_source_error,
int64_t speed, int64_t granularity, int64_t buf_size,
MirrorSyncMode mode, BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
BlockDriverCompletionFunc *cb,
void *opaque, Error **errp)
{
MirrorBlockJob *s;
if (granularity == 0) {
/* Choose the default granularity based on the target file's cluster
* size, clamped between 4k and 64k. */
BlockDriverInfo bdi;
if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) {
granularity = MAX(4096, bdi.cluster_size);
granularity = MIN(65536, granularity);
} else {
granularity = 65536;
}
}
assert ((granularity & (granularity - 1)) == 0);
if ((on_source_error == BLOCKDEV_ON_ERROR_STOP ||
on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
!bdrv_iostatus_is_enabled(bs)) {
@ -312,7 +571,10 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
s->on_target_error = on_target_error;
s->target = target;
s->mode = mode;
bdrv_set_dirty_tracking(bs, true);
s->granularity = granularity;
s->buf_size = MAX(buf_size, granularity);
bdrv_set_dirty_tracking(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);

View File

@ -68,19 +68,23 @@ static int parallels_probe(const uint8_t *buf, int buf_size, const char *filenam
return 0;
}
static int parallels_open(BlockDriverState *bs, int flags)
static int parallels_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVParallelsState *s = bs->opaque;
int i;
struct parallels_header ph;
int ret;
bs->read_only = 1; // no write support yet
if (bdrv_pread(bs->file, 0, &ph, sizeof(ph)) != sizeof(ph))
ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
if (ret < 0) {
goto fail;
}
if (memcmp(ph.magic, HEADER_MAGIC, 16) ||
(le32_to_cpu(ph.version) != HEADER_VERSION)) {
(le32_to_cpu(ph.version) != HEADER_VERSION)) {
ret = -EMEDIUMTYPE;
goto fail;
}
@ -90,18 +94,21 @@ static int parallels_open(BlockDriverState *bs, int flags)
s->catalog_size = le32_to_cpu(ph.catalog_entries);
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
if (bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4) !=
s->catalog_size * 4)
goto fail;
ret = bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4);
if (ret < 0) {
goto fail;
}
for (i = 0; i < s->catalog_size; i++)
le32_to_cpus(&s->catalog_bitmap[i]);
qemu_co_mutex_init(&s->lock);
return 0;
fail:
if (s->catalog_bitmap)
g_free(s->catalog_bitmap);
return -1;
g_free(s->catalog_bitmap);
return ret;
}
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)

View File

@ -92,7 +92,7 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int qcow_open(BlockDriverState *bs, int flags)
static int qcow_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVQcowState *s = bs->opaque;
int len, i, shift, ret;
@ -112,7 +112,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
be64_to_cpus(&header.l1_table_offset);
if (header.magic != QCOW_MAGIC) {
ret = -EINVAL;
ret = -EMEDIUMTYPE;
goto fail;
}
if (header.version != QCOW_VERSION) {

View File

@ -454,6 +454,9 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
*cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
break;
case QCOW2_CLUSTER_ZERO:
if (s->qcow_version < 3) {
return -EIO;
}
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0,
QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
@ -668,7 +671,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
}
/* Update L2 table. */
if (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS) {
if (s->use_lazy_refcounts) {
qcow2_mark_dirty(bs);
}
if (qcow2_need_accurate_refcounts(s)) {

View File

@ -201,7 +201,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
*refcount_block = NULL;
/* We write to the refcount table, so we might depend on L2 tables */
qcow2_cache_flush(bs, s->l2_table_cache);
ret = qcow2_cache_flush(bs, s->l2_table_cache);
if (ret < 0) {
return ret;
}
/* Allocate the refcount block itself and mark it as used */
int64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
@ -237,7 +240,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
goto fail_block;
}
bdrv_flush(bs->file);
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
goto fail_block;
}
/* Initialize the new refcount block only after updating its refcount,
* update_refcount uses the refcount cache itself */
@ -526,8 +532,6 @@ static int update_cluster_refcount(BlockDriverState *bs,
return ret;
}
bdrv_flush(bs->file);
return get_refcount(bs, cluster_index);
}
@ -663,7 +667,11 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
}
}
bdrv_flush(bs->file);
/* The cluster refcount was incremented, either by qcow2_alloc_clusters()
* or explicitly by update_cluster_refcount(). Refcount blocks must be
* flushed before the caller's L2 table updates.
*/
qcow2_cache_set_dependency(bs, s->l2_table_cache, s->refcount_block_cache);
return offset;
}
@ -737,11 +745,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
* l1_table_offset when it is the current s->l1_table_offset! Be careful
* when changing this! */
if (l1_table_offset != s->l1_table_offset) {
if (l1_size2 != 0) {
l1_table = g_malloc0(align_offset(l1_size2, 512));
} else {
l1_table = NULL;
}
l1_table = g_malloc0(align_offset(l1_size2, 512));
l1_allocated = 1;
if (bdrv_pread(bs->file, l1_table_offset,
l1_table, l1_size2) != l1_size2)
@ -786,10 +790,6 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
if (ret < 0) {
goto fail;
}
/* TODO Flushing once for the whole function should
* be enough */
bdrv_flush(bs->file);
}
/* compressed clusters are never modified */
refcount = 2;
@ -845,7 +845,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
}
}
ret = 0;
ret = bdrv_flush(bs);
fail:
if (l2_table) {
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
@ -918,6 +918,12 @@ static void inc_refcounts(BlockDriverState *bs,
}
}
/* Flags for check_refcounts_l1() and check_refcounts_l2() */
enum {
CHECK_OFLAG_COPIED = 0x1, /* check QCOW_OFLAG_COPIED matches refcount */
CHECK_FRAG_INFO = 0x2, /* update BlockFragInfo counters */
};
/*
* Increases the refcount in the given refcount table for the all clusters
* referenced in the L2 table. While doing so, performs some checks on L2
@ -928,10 +934,11 @@ static void inc_refcounts(BlockDriverState *bs,
*/
static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
uint16_t *refcount_table, int refcount_table_size, int64_t l2_offset,
int check_copied)
int flags)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l2_table, l2_entry;
uint64_t next_contiguous_offset = 0;
int i, l2_size, nb_csectors, refcount;
/* Read L2 table from disk */
@ -962,6 +969,18 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
l2_entry &= s->cluster_offset_mask;
inc_refcounts(bs, res, refcount_table, refcount_table_size,
l2_entry & ~511, nb_csectors * 512);
if (flags & CHECK_FRAG_INFO) {
res->bfi.allocated_clusters++;
res->bfi.compressed_clusters++;
/* Compressed clusters are fragmented by nature. Since they
* take up sub-sector space but we only have sector granularity
* I/O we need to re-read the same sectors even for adjacent
* compressed clusters.
*/
res->bfi.fragmented_clusters++;
}
break;
case QCOW2_CLUSTER_ZERO:
@ -975,7 +994,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
uint64_t offset = l2_entry & L2E_OFFSET_MASK;
if (check_copied) {
if (flags & CHECK_OFLAG_COPIED) {
refcount = get_refcount(bs, offset >> s->cluster_bits);
if (refcount < 0) {
fprintf(stderr, "Can't get refcount for offset %"
@ -989,6 +1008,15 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
}
}
if (flags & CHECK_FRAG_INFO) {
res->bfi.allocated_clusters++;
if (next_contiguous_offset &&
offset != next_contiguous_offset) {
res->bfi.fragmented_clusters++;
}
next_contiguous_offset = offset + s->cluster_size;
}
/* Mark cluster as used */
inc_refcounts(bs, res, refcount_table,refcount_table_size,
offset, s->cluster_size);
@ -1032,7 +1060,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
uint16_t *refcount_table,
int refcount_table_size,
int64_t l1_table_offset, int l1_size,
int check_copied)
int flags)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l1_table, l2_offset, l1_size2;
@ -1061,7 +1089,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
l2_offset = l1_table[i];
if (l2_offset) {
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
if (check_copied) {
if (flags & CHECK_OFLAG_COPIED) {
refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED)
>> s->cluster_bits);
if (refcount < 0) {
@ -1090,7 +1118,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
/* Process and check L2 entries */
ret = check_refcounts_l2(bs, res, refcount_table,
refcount_table_size, l2_offset, check_copied);
refcount_table_size, l2_offset, flags);
if (ret < 0) {
goto fail;
}
@ -1116,7 +1144,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
BdrvCheckMode fix)
{
BDRVQcowState *s = bs->opaque;
int64_t size, i;
int64_t size, i, highest_cluster;
int nb_clusters, refcount1, refcount2;
QCowSnapshot *sn;
uint16_t *refcount_table;
@ -1124,6 +1152,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
size = bdrv_getlength(bs->file);
nb_clusters = size_to_clusters(s, size);
res->bfi.total_clusters = nb_clusters;
refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t));
/* header */
@ -1132,7 +1161,8 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
/* current L1 table */
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
s->l1_table_offset, s->l1_size, 1);
s->l1_table_offset, s->l1_size,
CHECK_OFLAG_COPIED | CHECK_FRAG_INFO);
if (ret < 0) {
goto fail;
}
@ -1187,7 +1217,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
}
/* compare ref counts */
for(i = 0; i < nb_clusters; i++) {
for (i = 0, highest_cluster = 0; i < nb_clusters; i++) {
refcount1 = get_refcount(bs, i);
if (refcount1 < 0) {
fprintf(stderr, "Can't get refcount for cluster %" PRId64 ": %s\n",
@ -1197,6 +1227,11 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
}
refcount2 = refcount_table[i];
if (refcount1 > 0 || refcount2 > 0) {
highest_cluster = i;
}
if (refcount1 != refcount2) {
/* Check if we're allowed to fix the mismatch */
@ -1231,6 +1266,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
}
}
res->image_end_offset = (highest_cluster + 1) * s->cluster_size;
ret = 0;
fail:

View File

@ -180,11 +180,14 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
/* Allocate space for the new snapshot list */
snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
bdrv_flush(bs->file);
offset = snapshots_offset;
if (offset < 0) {
return offset;
}
ret = bdrv_flush(bs);
if (ret < 0) {
return ret;
}
/* Write all snapshots to the new list */
for(i = 0; i < s->nb_snapshots; i++) {
@ -378,11 +381,6 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
goto fail;
}
ret = bdrv_flush(bs);
if (ret < 0) {
goto fail;
}
/* Append the new snapshot to the snapshot list */
new_snapshot_list = g_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
if (s->snapshots) {

View File

@ -285,11 +285,26 @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
return ret;
}
static int qcow2_open(BlockDriverState *bs, int flags)
static QemuOptsList qcow2_runtime_opts = {
.name = "qcow2",
.head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head),
.desc = {
{
.name = "lazy_refcounts",
.type = QEMU_OPT_BOOL,
.help = "Postpone refcount updates",
},
{ /* end of list */ }
},
};
static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVQcowState *s = bs->opaque;
int len, i, ret = 0;
QCowHeader header;
QemuOpts *opts;
Error *local_err = NULL;
uint64_t ext_end;
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
@ -311,7 +326,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
be32_to_cpus(&header.nb_snapshots);
if (header.magic != QCOW_MAGIC) {
ret = -EINVAL;
ret = -EMEDIUMTYPE;
goto fail;
}
if (header.version < 2 || header.version > 3) {
@ -495,6 +510,28 @@ static int qcow2_open(BlockDriverState *bs, int flags)
}
}
/* Enable lazy_refcounts according to image and command line options */
opts = qemu_opts_create_nofail(&qcow2_runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
ret = -EINVAL;
goto fail;
}
s->use_lazy_refcounts = qemu_opt_get_bool(opts, "lazy_refcounts",
(s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS));
qemu_opts_del(opts);
if (s->use_lazy_refcounts && s->qcow_version < 3) {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Lazy refcounts require "
"a qcow2 image with at least qemu 1.1 compatibility level");
ret = -EINVAL;
goto fail;
}
#ifdef DEBUG_ALLOC
{
BdrvCheckResult result = {0};
@ -584,7 +621,7 @@ static int coroutine_fn qcow2_co_is_allocated(BlockDriverState *bs,
*pnum = 0;
}
return (cluster_offset != 0);
return (cluster_offset != 0) || (ret == QCOW2_CLUSTER_ZERO);
}
/* handle reading after the end of the backing file */
@ -665,10 +702,6 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
break;
case QCOW2_CLUSTER_ZERO:
if (s->qcow_version < 3) {
ret = -EIO;
goto fail;
}
qemu_iovec_memset(&hd_qiov, 0, 0, 512 * cur_nr_sectors);
break;
@ -759,7 +792,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
QEMUIOVector hd_qiov;
uint64_t bytes_done = 0;
uint8_t *cluster_data = NULL;
QCowL2Meta *l2meta;
QCowL2Meta *l2meta = NULL;
trace_qcow2_writev_start_req(qemu_coroutine_self(), sector_num,
remaining_sectors);
@ -912,7 +945,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs)
qcow2_close(bs);
memset(s, 0, sizeof(BDRVQcowState));
qcow2_open(bs, flags);
qcow2_open(bs, NULL, flags);
if (crypt_method) {
s->crypt_method = crypt_method;
@ -1265,7 +1298,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
*/
BlockDriver* drv = bdrv_find_format("qcow2");
assert(drv != NULL);
ret = bdrv_open(bs, filename,
ret = bdrv_open(bs, filename, NULL,
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv);
if (ret < 0) {
goto out;

View File

@ -173,6 +173,7 @@ typedef struct BDRVQcowState {
int flags;
int qcow_version;
bool use_lazy_refcounts;
uint64_t incompatible_features;
uint64_t compatible_features;

View File

@ -373,7 +373,7 @@ static void bdrv_qed_rebind(BlockDriverState *bs)
s->bs = bs;
}
static int bdrv_qed_open(BlockDriverState *bs, int flags)
static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVQEDState *s = bs->opaque;
QEDHeader le_header;
@ -390,7 +390,7 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
qed_header_le_to_cpu(&le_header, &s->header);
if (s->header.magic != QED_MAGIC) {
return -EINVAL;
return -EMEDIUMTYPE;
}
if (s->header.features & ~QED_FEATURE_MASK) {
/* image uses unsupported feature bits */
@ -1526,7 +1526,7 @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs)
bdrv_qed_close(bs);
memset(s, 0, sizeof(BDRVQEDState));
bdrv_qed_open(bs, bs->open_flags);
bdrv_qed_open(bs, NULL, bs->open_flags);
}
static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result,

View File

@ -20,11 +20,14 @@
#define QEMU_AIO_WRITE 0x0002
#define QEMU_AIO_IOCTL 0x0004
#define QEMU_AIO_FLUSH 0x0008
#define QEMU_AIO_DISCARD 0x0010
#define QEMU_AIO_TYPE_MASK \
(QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH)
(QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH| \
QEMU_AIO_DISCARD)
/* AIO flags */
#define QEMU_AIO_MISALIGNED 0x1000
#define QEMU_AIO_BLKDEV 0x2000
/* linux-aio.c - Linux native implementation */

View File

@ -59,6 +59,9 @@
#ifdef CONFIG_FIEMAP
#include <linux/fiemap.h>
#endif
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
#include <linux/falloc.h>
#endif
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <sys/disk.h>
#include <sys/cdio.h>
@ -138,6 +141,7 @@ typedef struct BDRVRawState {
#ifdef CONFIG_XFS
bool is_xfs : 1;
#endif
bool has_discard : 1;
} BDRVRawState;
typedef struct BDRVRawReopenState {
@ -159,7 +163,7 @@ typedef struct RawPosixAIOData {
void *aio_ioctl_buf;
};
int aio_niov;
size_t aio_nbytes;
uint64_t aio_nbytes;
#define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */
off_t aio_offset;
int aio_type;
@ -289,6 +293,7 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
}
#endif
s->has_discard = 1;
#ifdef CONFIG_XFS
if (platform_test_xfs_fd(s->fd)) {
s->is_xfs = 1;
@ -340,11 +345,20 @@ static int raw_reopen_prepare(BDRVReopenState *state,
raw_s->fd = -1;
int fcntl_flags = O_APPEND | O_ASYNC | O_NONBLOCK;
int fcntl_flags = O_APPEND | O_NONBLOCK;
#ifdef O_NOATIME
fcntl_flags |= O_NOATIME;
#endif
#ifdef O_ASYNC
/* Not all operating systems have O_ASYNC, and those that don't
* will not let us track the state into raw_s->open_flags (typically
* you achieve the same effect with an ioctl, for example I_SETSIG
* on Solaris). But we do not use O_ASYNC, so that's fine.
*/
assert((s->open_flags & O_ASYNC) == 0);
#endif
if ((raw_s->open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) {
/* dup the original fd */
/* TODO: use qemu fcntl wrapper */
@ -430,22 +444,6 @@ static void raw_reopen_abort(BDRVReopenState *state)
#endif
*/
/*
* Check if all memory in this vector is sector aligned.
*/
static int qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
{
int i;
for (i = 0; i < qiov->niov; i++) {
if ((uintptr_t) qiov->iov[i].iov_base % bs->buffer_alignment) {
return 0;
}
}
return 1;
}
static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb)
{
int ret;
@ -455,15 +453,7 @@ static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb)
return -errno;
}
/*
* This looks weird, but the aio code only considers a request
* successful if it has written the full number of bytes.
*
* Now we overload aio_nbytes as aio_ioctl_cmd for the ioctl command,
* so in fact we return the ioctl command here to make posix_aio_read()
* happy..
*/
return aiocb->aio_nbytes;
return 0;
}
static ssize_t handle_aiocb_flush(RawPosixAIOData *aiocb)
@ -642,6 +632,72 @@ static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
return nbytes;
}
#ifdef CONFIG_XFS
static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
{
struct xfs_flock64 fl;
memset(&fl, 0, sizeof(fl));
fl.l_whence = SEEK_SET;
fl.l_start = offset;
fl.l_len = bytes;
if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) {
DEBUG_BLOCK_PRINT("cannot punch hole (%s)\n", strerror(errno));
return -errno;
}
return 0;
}
#endif
static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb)
{
int ret = -EOPNOTSUPP;
BDRVRawState *s = aiocb->bs->opaque;
if (s->has_discard == 0) {
return 0;
}
if (aiocb->aio_type & QEMU_AIO_BLKDEV) {
#ifdef BLKDISCARD
do {
uint64_t range[2] = { aiocb->aio_offset, aiocb->aio_nbytes };
if (ioctl(aiocb->aio_fildes, BLKDISCARD, range) == 0) {
return 0;
}
} while (errno == EINTR);
ret = -errno;
#endif
} else {
#ifdef CONFIG_XFS
if (s->is_xfs) {
return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes);
}
#endif
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
do {
if (fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
aiocb->aio_offset, aiocb->aio_nbytes) == 0) {
return 0;
}
} while (errno == EINTR);
ret = -errno;
#endif
}
if (ret == -ENODEV || ret == -ENOSYS || ret == -EOPNOTSUPP ||
ret == -ENOTTY) {
s->has_discard = 0;
ret = 0;
}
return ret;
}
static int aio_worker(void *arg)
{
RawPosixAIOData *aiocb = arg;
@ -676,6 +732,9 @@ static int aio_worker(void *arg)
case QEMU_AIO_IOCTL:
ret = handle_aiocb_ioctl(aiocb);
break;
case QEMU_AIO_DISCARD:
ret = handle_aiocb_discard(aiocb);
break;
default:
fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
ret = -EINVAL;
@ -691,6 +750,7 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
BlockDriverCompletionFunc *cb, void *opaque, int type)
{
RawPosixAIOData *acb = g_slice_new(RawPosixAIOData);
ThreadPool *pool;
acb->bs = bs;
acb->aio_type = type;
@ -704,7 +764,8 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
acb->aio_offset = sector_num * 512;
trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
}
static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
@ -722,7 +783,7 @@ static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
* driver that it needs to copy the buffer.
*/
if ((bs->open_flags & BDRV_O_NOCACHE)) {
if (!qiov_is_aligned(bs, qiov)) {
if (!bdrv_qiov_is_aligned(bs, qiov)) {
type |= QEMU_AIO_MISALIGNED;
#ifdef CONFIG_LINUX_AIO
} else if (s->use_aio) {
@ -1076,37 +1137,14 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs,
}
}
#ifdef CONFIG_XFS
static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors)
static coroutine_fn BlockDriverAIOCB *raw_aio_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
struct xfs_flock64 fl;
memset(&fl, 0, sizeof(fl));
fl.l_whence = SEEK_SET;
fl.l_start = sector_num << 9;
fl.l_len = (int64_t)nb_sectors << 9;
if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) {
DEBUG_BLOCK_PRINT("cannot punch hole (%s)\n", strerror(errno));
return -errno;
}
return 0;
}
#endif
static coroutine_fn int raw_co_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors)
{
#ifdef CONFIG_XFS
BDRVRawState *s = bs->opaque;
if (s->is_xfs) {
return xfs_discard(s, sector_num, nb_sectors);
}
#endif
return 0;
return paio_submit(bs, s->fd, sector_num, NULL, nb_sectors,
cb, opaque, QEMU_AIO_DISCARD);
}
static QEMUOptionParameter raw_create_options[] = {
@ -1129,12 +1167,12 @@ static BlockDriver bdrv_file = {
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_close = raw_close,
.bdrv_create = raw_create,
.bdrv_co_discard = raw_co_discard,
.bdrv_co_is_allocated = raw_co_is_allocated,
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
.bdrv_aio_discard = raw_aio_discard,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
@ -1221,9 +1259,43 @@ static int hdev_probe_device(const char *filename)
return 0;
}
static int check_hdev_writable(BDRVRawState *s)
{
#if defined(BLKROGET)
/* Linux block devices can be configured "read-only" using blockdev(8).
* This is independent of device node permissions and therefore open(2)
* with O_RDWR succeeds. Actual writes fail with EPERM.
*
* bdrv_open() is supposed to fail if the disk is read-only. Explicitly
* check for read-only block devices so that Linux block devices behave
* properly.
*/
struct stat st;
int readonly = 0;
if (fstat(s->fd, &st)) {
return -errno;
}
if (!S_ISBLK(st.st_mode)) {
return 0;
}
if (ioctl(s->fd, BLKROGET, &readonly) < 0) {
return -errno;
}
if (readonly) {
return -EACCES;
}
#endif /* defined(BLKROGET) */
return 0;
}
static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
int ret;
#if defined(__APPLE__) && defined(__MACH__)
if (strstart(filename, "/dev/cdrom", NULL)) {
@ -1264,7 +1336,20 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
}
#endif
return raw_open_common(bs, filename, flags, 0);
ret = raw_open_common(bs, filename, flags, 0);
if (ret < 0) {
return ret;
}
if (flags & BDRV_O_RDWR) {
ret = check_hdev_writable(s);
if (ret < 0) {
raw_close(bs);
return ret;
}
}
return ret;
}
#if defined(__linux__)
@ -1330,6 +1415,7 @@ static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
{
BDRVRawState *s = bs->opaque;
RawPosixAIOData *acb;
ThreadPool *pool;
if (fd_open(bs) < 0)
return NULL;
@ -1341,7 +1427,8 @@ static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
acb->aio_offset = 0;
acb->aio_ioctl_buf = buf;
acb->aio_ioctl_cmd = req;
return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
}
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@ -1363,6 +1450,19 @@ static int fd_open(BlockDriverState *bs)
#endif /* !linux && !FreeBSD */
static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
if (fd_open(bs) < 0) {
return NULL;
}
return paio_submit(bs, s->fd, sector_num, NULL, nb_sectors,
cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV);
}
static int hdev_create(const char *filename, QEMUOptionParameter *options)
{
int fd;
@ -1415,6 +1515,7 @@ static BlockDriver bdrv_host_device = {
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
.bdrv_aio_discard = hdev_aio_discard,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
@ -1776,6 +1877,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)
{
/*

View File

@ -144,6 +144,7 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
BlockDriverCompletionFunc *cb, void *opaque, int type)
{
RawWin32AIOData *acb = g_slice_new(RawWin32AIOData);
ThreadPool *pool;
acb->bs = bs;
acb->hfile = hfile;
@ -157,7 +158,8 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
acb->aio_offset = sector_num * 512;
trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
}
int qemu_ftruncate64(int fd, int64_t length)
@ -314,11 +316,11 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset)
*/
dwPtrLow = SetFilePointer(s->hfile, low, &high, FILE_BEGIN);
if (dwPtrLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
fprintf(stderr, "SetFilePointer error: %d\n", GetLastError());
fprintf(stderr, "SetFilePointer error: %lu\n", GetLastError());
return -EIO;
}
if (SetEndOfFile(s->hfile) == 0) {
fprintf(stderr, "SetEndOfFile error: %d\n", GetLastError());
fprintf(stderr, "SetEndOfFile error: %lu\n", GetLastError());
return -EIO;
}
return 0;

View File

@ -3,7 +3,7 @@
#include "block/block_int.h"
#include "qemu/module.h"
static int raw_open(BlockDriverState *bs, int flags)
static int raw_open(BlockDriverState *bs, QDict *options, int flags)
{
bs->sg = bs->file->sg;
return 0;

View File

@ -13,6 +13,7 @@
*/
#include "qemu-common.h"
#include "qemu/uri.h"
#include "qemu/error-report.h"
#include "qemu/sockets.h"
#include "block/block_int.h"
@ -21,7 +22,7 @@
#define SD_PROTO_VER 0x01
#define SD_DEFAULT_ADDR "localhost"
#define SD_DEFAULT_PORT "7000"
#define SD_DEFAULT_PORT 7000
#define SD_OP_CREATE_AND_WRITE_OBJ 0x01
#define SD_OP_READ_OBJ 0x02
@ -36,7 +37,8 @@
#define SD_FLAG_CMD_WRITE 0x01
#define SD_FLAG_CMD_COW 0x02
#define SD_FLAG_CMD_CACHE 0x04
#define SD_FLAG_CMD_CACHE 0x04 /* Writeback mode for cache */
#define SD_FLAG_CMD_DIRECT 0x08 /* Don't use cache */
#define SD_RES_SUCCESS 0x00 /* Success */
#define SD_RES_UNKNOWN 0x01 /* Unknown error */
@ -144,7 +146,7 @@ typedef struct SheepdogVdiReq {
uint32_t id;
uint32_t data_length;
uint64_t vdi_size;
uint32_t base_vdi_id;
uint32_t vdi_id;
uint32_t copies;
uint32_t snapid;
uint32_t pad[3];
@ -265,6 +267,7 @@ typedef struct AIOReq {
enum AIOCBState {
AIOCB_WRITE_UDATA,
AIOCB_READ_UDATA,
AIOCB_FLUSH_CACHE,
};
struct SheepdogAIOCB {
@ -293,12 +296,11 @@ typedef struct BDRVSheepdogState {
char name[SD_MAX_VDI_LEN];
bool is_snapshot;
bool cache_enabled;
uint32_t cache_flags;
char *addr;
char *port;
char *host_spec;
bool is_unix;
int fd;
int flush_fd;
CoMutex lock;
Coroutine *co_send;
@ -426,12 +428,11 @@ static const AIOCBInfo sd_aiocb_info = {
};
static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
int64_t sector_num, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
int64_t sector_num, int nb_sectors)
{
SheepdogAIOCB *acb;
acb = qemu_aio_get(&sd_aiocb_info, bs, cb, opaque);
acb = qemu_aio_get(&sd_aiocb_info, bs, NULL, NULL);
acb->qiov = qiov;
@ -446,56 +447,31 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
return acb;
}
static int connect_to_sdog(const char *addr, const char *port)
static int connect_to_sdog(BDRVSheepdogState *s)
{
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
int fd, ret;
struct addrinfo hints, *res, *res0;
int fd;
Error *err = NULL;
if (!addr) {
addr = SD_DEFAULT_ADDR;
port = SD_DEFAULT_PORT;
}
if (s->is_unix) {
fd = unix_connect(s->host_spec, &err);
} else {
fd = inet_connect(s->host_spec, &err);
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
ret = getaddrinfo(addr, port, &hints, &res0);
if (ret) {
error_report("unable to get address info %s, %s",
addr, strerror(errno));
return -errno;
}
for (res = res0; res; res = res->ai_next) {
ret = getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
if (ret) {
continue;
}
fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (fd < 0) {
continue;
}
reconnect:
ret = connect(fd, res->ai_addr, res->ai_addrlen);
if (ret < 0) {
if (errno == EINTR) {
goto reconnect;
if (err == NULL) {
int ret = socket_set_nodelay(fd);
if (ret < 0) {
error_report("%s", strerror(errno));
}
close(fd);
break;
}
dprintf("connected to %s:%s\n", addr, port);
goto success;
}
fd = -errno;
error_report("failed connect to %s:%s", addr, port);
success:
freeaddrinfo(res0);
if (err != NULL) {
qerror_report_err(err);
error_free(err);
} else {
socket_set_nonblock(fd);
}
return fd;
}
@ -525,6 +501,13 @@ static void restart_co_req(void *opaque)
qemu_coroutine_enter(co, NULL);
}
static int have_co_req(void *opaque)
{
/* this handler is set only when there is a pending request, so
* always returns 1. */
return 1;
}
typedef struct SheepdogReqCo {
int sockfd;
SheepdogReq *hdr;
@ -547,15 +530,14 @@ static coroutine_fn void do_co_req(void *opaque)
unsigned int *rlen = srco->rlen;
co = qemu_coroutine_self();
qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, NULL, co);
qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, have_co_req, co);
socket_set_block(sockfd);
ret = send_co_req(sockfd, hdr, data, wlen);
if (ret < 0) {
goto out;
}
qemu_aio_set_fd_handler(sockfd, restart_co_req, NULL, NULL, co);
qemu_aio_set_fd_handler(sockfd, restart_co_req, NULL, have_co_req, co);
ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr));
if (ret < sizeof(*hdr)) {
@ -578,8 +560,9 @@ static coroutine_fn void do_co_req(void *opaque)
}
ret = 0;
out:
/* there is at most one request for this sockfd, so it is safe to
* set each handler to NULL. */
qemu_aio_set_fd_handler(sockfd, NULL, NULL, NULL, NULL);
socket_set_nonblock(sockfd);
srco->ret = ret;
srco->finished = true;
@ -714,16 +697,17 @@ static void coroutine_fn aio_read_response(void *opaque)
* and max_dirty_data_idx are changed to include updated
* index between them.
*/
s->inode.data_vdi_id[idx] = s->inode.vdi_id;
s->max_dirty_data_idx = MAX(idx, s->max_dirty_data_idx);
s->min_dirty_data_idx = MIN(idx, s->min_dirty_data_idx);
if (rsp.result == SD_RES_SUCCESS) {
s->inode.data_vdi_id[idx] = s->inode.vdi_id;
s->max_dirty_data_idx = MAX(idx, s->max_dirty_data_idx);
s->min_dirty_data_idx = MIN(idx, s->min_dirty_data_idx);
}
/*
* Some requests may be blocked because simultaneous
* create requests are not allowed, so we search the
* pending requests here.
*/
send_pending_req(s, vid_to_data_oid(s->inode.vdi_id, idx));
send_pending_req(s, aio_req->oid);
}
break;
case AIOCB_READ_UDATA:
@ -734,6 +718,13 @@ static void coroutine_fn aio_read_response(void *opaque)
goto out;
}
break;
case AIOCB_FLUSH_CACHE:
if (rsp.result == SD_RES_INVALID_PARMS) {
dprintf("disable cache since the server doesn't support it\n");
s->cache_flags = SD_FLAG_CMD_DIRECT;
rsp.result = SD_RES_SUCCESS;
}
break;
}
if (rsp.result != SD_RES_SUCCESS) {
@ -779,15 +770,6 @@ static int aio_flush_request(void *opaque)
!QLIST_EMPTY(&s->pending_aio_head);
}
static int set_nodelay(int fd)
{
int ret, opt;
opt = 1;
ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt));
return ret;
}
/*
* Return a socket discriptor to read/write objects.
*
@ -796,29 +778,86 @@ static int set_nodelay(int fd)
*/
static int get_sheep_fd(BDRVSheepdogState *s)
{
int ret, fd;
int fd;
fd = connect_to_sdog(s->addr, s->port);
fd = connect_to_sdog(s);
if (fd < 0) {
error_report("%s", strerror(errno));
return fd;
}
socket_set_nonblock(fd);
ret = set_nodelay(fd);
if (ret) {
error_report("%s", strerror(errno));
closesocket(fd);
return -errno;
}
qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request, s);
return fd;
}
static int sd_parse_uri(BDRVSheepdogState *s, const char *filename,
char *vdi, uint32_t *snapid, char *tag)
{
URI *uri;
QueryParams *qp = NULL;
int ret = 0;
uri = uri_parse(filename);
if (!uri) {
return -EINVAL;
}
/* transport */
if (!strcmp(uri->scheme, "sheepdog")) {
s->is_unix = false;
} else if (!strcmp(uri->scheme, "sheepdog+tcp")) {
s->is_unix = false;
} else if (!strcmp(uri->scheme, "sheepdog+unix")) {
s->is_unix = true;
} else {
ret = -EINVAL;
goto out;
}
if (uri->path == NULL || !strcmp(uri->path, "/")) {
ret = -EINVAL;
goto out;
}
pstrcpy(vdi, SD_MAX_VDI_LEN, uri->path + 1);
qp = query_params_parse(uri->query);
if (qp->n > 1 || (s->is_unix && !qp->n) || (!s->is_unix && qp->n)) {
ret = -EINVAL;
goto out;
}
if (s->is_unix) {
/* sheepdog+unix:///vdiname?socket=path */
if (uri->server || uri->port || strcmp(qp->p[0].name, "socket")) {
ret = -EINVAL;
goto out;
}
s->host_spec = g_strdup(qp->p[0].value);
} else {
/* sheepdog[+tcp]://[host:port]/vdiname */
s->host_spec = g_strdup_printf("%s:%d", uri->server ?: SD_DEFAULT_ADDR,
uri->port ?: SD_DEFAULT_PORT);
}
/* snapshot tag */
if (uri->fragment) {
*snapid = strtoul(uri->fragment, NULL, 10);
if (*snapid == 0) {
pstrcpy(tag, SD_MAX_VDI_TAG_LEN, uri->fragment);
}
} else {
*snapid = CURRENT_VDI_ID; /* search current vdi */
}
out:
if (qp) {
query_params_free(qp);
}
uri_free(uri);
return ret;
}
/*
* Parse a filename
* Parse a filename (old syntax)
*
* filename must be one of the following formats:
* 1. [vdiname]
@ -837,9 +876,11 @@ static int get_sheep_fd(BDRVSheepdogState *s)
static int parse_vdiname(BDRVSheepdogState *s, const char *filename,
char *vdi, uint32_t *snapid, char *tag)
{
char *p, *q;
int nr_sep;
char *p, *q, *uri;
const char *host_spec, *vdi_spec;
int nr_sep, ret;
strstart(filename, "sheepdog:", (const char **)&filename);
p = q = g_strdup(filename);
/* count the number of separators */
@ -852,38 +893,32 @@ static int parse_vdiname(BDRVSheepdogState *s, const char *filename,
}
p = q;
/* use the first two tokens as hostname and port number. */
/* use the first two tokens as host_spec. */
if (nr_sep >= 2) {
s->addr = p;
host_spec = p;
p = strchr(p, ':');
*p++ = '\0';
s->port = p;
p++;
p = strchr(p, ':');
*p++ = '\0';
} else {
s->addr = NULL;
s->port = 0;
host_spec = "";
}
pstrcpy(vdi, SD_MAX_VDI_LEN, p);
vdi_spec = p;
p = strchr(vdi, ':');
p = strchr(vdi_spec, ':');
if (p) {
*p++ = '\0';
*snapid = strtoul(p, NULL, 10);
if (*snapid == 0) {
pstrcpy(tag, SD_MAX_VDI_TAG_LEN, p);
}
} else {
*snapid = CURRENT_VDI_ID; /* search current vdi */
*p++ = '#';
}
if (s->addr == NULL) {
g_free(q);
}
uri = g_strdup_printf("sheepdog://%s/%s", host_spec, vdi_spec);
return 0;
ret = sd_parse_uri(s, uri, vdi, snapid, tag);
g_free(q);
g_free(uri);
return ret;
}
static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid,
@ -895,7 +930,7 @@ static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid,
unsigned int wlen, rlen = 0;
char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
fd = connect_to_sdog(s->addr, s->port);
fd = connect_to_sdog(s);
if (fd < 0) {
return fd;
}
@ -948,7 +983,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
{
int nr_copies = s->inode.nr_copies;
SheepdogObjReq hdr;
unsigned int wlen;
unsigned int wlen = 0;
int ret;
uint64_t oid = aio_req->oid;
unsigned int datalen = aio_req->data_len;
@ -962,22 +997,27 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
memset(&hdr, 0, sizeof(hdr));
if (aiocb_type == AIOCB_READ_UDATA) {
wlen = 0;
switch (aiocb_type) {
case AIOCB_FLUSH_CACHE:
hdr.opcode = SD_OP_FLUSH_VDI;
break;
case AIOCB_READ_UDATA:
hdr.opcode = SD_OP_READ_OBJ;
hdr.flags = flags;
} else if (create) {
break;
case AIOCB_WRITE_UDATA:
if (create) {
hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ;
} else {
hdr.opcode = SD_OP_WRITE_OBJ;
}
wlen = datalen;
hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ;
hdr.flags = SD_FLAG_CMD_WRITE | flags;
} else {
wlen = datalen;
hdr.opcode = SD_OP_WRITE_OBJ;
hdr.flags = SD_FLAG_CMD_WRITE | flags;
break;
}
if (s->cache_enabled) {
hdr.flags |= SD_FLAG_CMD_CACHE;
if (s->cache_flags) {
hdr.flags |= s->cache_flags;
}
hdr.oid = oid;
@ -1022,7 +1062,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
unsigned int datalen, uint64_t offset,
bool write, bool create, bool cache)
bool write, bool create, uint32_t cache_flags)
{
SheepdogObjReq hdr;
SheepdogObjRsp *rsp = (SheepdogObjRsp *)&hdr;
@ -1046,9 +1086,7 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
hdr.opcode = SD_OP_READ_OBJ;
}
if (cache) {
hdr.flags |= SD_FLAG_CMD_CACHE;
}
hdr.flags |= cache_flags;
hdr.oid = oid;
hdr.data_length = datalen;
@ -1071,18 +1109,19 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
}
static int read_object(int fd, char *buf, uint64_t oid, int copies,
unsigned int datalen, uint64_t offset, bool cache)
unsigned int datalen, uint64_t offset,
uint32_t cache_flags)
{
return read_write_object(fd, buf, oid, copies, datalen, offset, false,
false, cache);
false, cache_flags);
}
static int write_object(int fd, char *buf, uint64_t oid, int copies,
unsigned int datalen, uint64_t offset, bool create,
bool cache)
uint32_t cache_flags)
{
return read_write_object(fd, buf, oid, copies, datalen, offset, true,
create, cache);
create, cache_flags);
}
static int sd_open(BlockDriverState *bs, const char *filename, int flags)
@ -1094,16 +1133,19 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
uint32_t snapid;
char *buf = NULL;
strstart(filename, "sheepdog:", (const char **)&filename);
QLIST_INIT(&s->inflight_aio_head);
QLIST_INIT(&s->pending_aio_head);
s->fd = -1;
memset(vdi, 0, sizeof(vdi));
memset(tag, 0, sizeof(tag));
if (parse_vdiname(s, filename, vdi, &snapid, tag) < 0) {
ret = -EINVAL;
if (strstr(filename, "://")) {
ret = sd_parse_uri(s, filename, vdi, &snapid, tag);
} else {
ret = parse_vdiname(s, filename, vdi, &snapid, tag);
}
if (ret < 0) {
goto out;
}
s->fd = get_sheep_fd(s);
@ -1117,12 +1159,13 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
goto out;
}
s->cache_enabled = true;
s->flush_fd = connect_to_sdog(s->addr, s->port);
if (s->flush_fd < 0) {
error_report("failed to connect");
ret = s->flush_fd;
goto out;
/*
* QEMU block layer emulates writethrough cache as 'writeback + flush', so
* we always set SD_FLAG_CMD_CACHE (writeback cache) as default.
*/
s->cache_flags = SD_FLAG_CMD_CACHE;
if (flags & BDRV_O_NOCACHE) {
s->cache_flags = SD_FLAG_CMD_DIRECT;
}
if (snapid || tag[0] != '\0') {
@ -1130,16 +1173,15 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
s->is_snapshot = true;
}
fd = connect_to_sdog(s->addr, s->port);
fd = connect_to_sdog(s);
if (fd < 0) {
error_report("failed to connect");
ret = fd;
goto out;
}
buf = g_malloc(SD_INODE_SIZE);
ret = read_object(fd, buf, vid_to_vdi_oid(vid), 0, SD_INODE_SIZE, 0,
s->cache_enabled);
s->cache_flags);
closesocket(fd);
@ -1165,9 +1207,8 @@ out:
return ret;
}
static int do_sd_create(char *filename, int64_t vdi_size,
uint32_t base_vid, uint32_t *vdi_id, int snapshot,
const char *addr, const char *port)
static int do_sd_create(BDRVSheepdogState *s, char *filename, int64_t vdi_size,
uint32_t base_vid, uint32_t *vdi_id, int snapshot)
{
SheepdogVdiReq hdr;
SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
@ -1175,7 +1216,7 @@ static int do_sd_create(char *filename, int64_t vdi_size,
unsigned int wlen, rlen = 0;
char buf[SD_MAX_VDI_LEN];
fd = connect_to_sdog(addr, port);
fd = connect_to_sdog(s);
if (fd < 0) {
return fd;
}
@ -1188,7 +1229,7 @@ static int do_sd_create(char *filename, int64_t vdi_size,
memset(&hdr, 0, sizeof(hdr));
hdr.opcode = SD_OP_NEW_VDI;
hdr.base_vdi_id = base_vid;
hdr.vdi_id = base_vid;
wlen = SD_MAX_VDI_LEN;
@ -1271,17 +1312,17 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
uint32_t snapid;
bool prealloc = false;
const char *vdiname;
s = g_malloc0(sizeof(BDRVSheepdogState));
strstart(filename, "sheepdog:", &vdiname);
memset(vdi, 0, sizeof(vdi));
memset(tag, 0, sizeof(tag));
if (parse_vdiname(s, vdiname, vdi, &snapid, tag) < 0) {
error_report("invalid filename");
ret = -EINVAL;
if (strstr(filename, "://")) {
ret = sd_parse_uri(s, filename, vdi, &snapid, tag);
} else {
ret = parse_vdiname(s, filename, vdi, &snapid, tag);
}
if (ret < 0) {
goto out;
}
@ -1342,7 +1383,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
bdrv_delete(bs);
}
ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s->addr, s->port);
ret = do_sd_create(s, vdi, vdi_size, base_vid, &vid, 0);
if (!prealloc || ret) {
goto out;
}
@ -1363,7 +1404,7 @@ static void sd_close(BlockDriverState *bs)
dprintf("%s\n", s->name);
fd = connect_to_sdog(s->addr, s->port);
fd = connect_to_sdog(s);
if (fd < 0) {
return;
}
@ -1371,6 +1412,7 @@ static void sd_close(BlockDriverState *bs)
memset(&hdr, 0, sizeof(hdr));
hdr.opcode = SD_OP_RELEASE_VDI;
hdr.vdi_id = s->inode.vdi_id;
wlen = strlen(s->name) + 1;
hdr.data_length = wlen;
hdr.flags = SD_FLAG_CMD_WRITE;
@ -1386,10 +1428,7 @@ static void sd_close(BlockDriverState *bs)
qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL);
closesocket(s->fd);
if (s->cache_enabled) {
closesocket(s->flush_fd);
}
g_free(s->addr);
g_free(s->host_spec);
}
static int64_t sd_getlength(BlockDriverState *bs)
@ -1413,7 +1452,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
return -EINVAL;
}
fd = connect_to_sdog(s->addr, s->port);
fd = connect_to_sdog(s);
if (fd < 0) {
return fd;
}
@ -1422,7 +1461,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
s->inode.vdi_size = offset;
ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
s->inode.nr_copies, datalen, 0, false, s->cache_enabled);
s->inode.nr_copies, datalen, 0, false, s->cache_flags);
close(fd);
if (ret < 0) {
@ -1489,23 +1528,21 @@ static int sd_create_branch(BDRVSheepdogState *s)
buf = g_malloc(SD_INODE_SIZE);
ret = do_sd_create(s->name, s->inode.vdi_size, s->inode.vdi_id, &vid, 1,
s->addr, s->port);
ret = do_sd_create(s, s->name, s->inode.vdi_size, s->inode.vdi_id, &vid, 1);
if (ret) {
goto out;
}
dprintf("%" PRIx32 " is created.\n", vid);
fd = connect_to_sdog(s->addr, s->port);
fd = connect_to_sdog(s);
if (fd < 0) {
error_report("failed to connect");
ret = fd;
goto out;
}
ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies,
SD_INODE_SIZE, 0, s->cache_enabled);
SD_INODE_SIZE, 0, s->cache_flags);
closesocket(fd);
@ -1661,7 +1698,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
bs->total_sectors = sector_num + nb_sectors;
}
acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, NULL, NULL);
acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors);
acb->aio_done_func = sd_write_done;
acb->aiocb_type = AIOCB_WRITE_UDATA;
@ -1682,7 +1719,7 @@ static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num,
SheepdogAIOCB *acb;
int ret;
acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, NULL, NULL);
acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors);
acb->aiocb_type = AIOCB_READ_UDATA;
acb->aio_done_func = sd_finish_aiocb;
@ -1700,39 +1737,31 @@ static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num,
static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs)
{
BDRVSheepdogState *s = bs->opaque;
SheepdogObjReq hdr = { 0 };
SheepdogObjRsp *rsp = (SheepdogObjRsp *)&hdr;
SheepdogInode *inode = &s->inode;
SheepdogAIOCB *acb;
AIOReq *aio_req;
int ret;
unsigned int wlen = 0, rlen = 0;
if (!s->cache_enabled) {
if (s->cache_flags != SD_FLAG_CMD_CACHE) {
return 0;
}
hdr.opcode = SD_OP_FLUSH_VDI;
hdr.oid = vid_to_vdi_oid(inode->vdi_id);
acb = sd_aio_setup(bs, NULL, 0, 0);
acb->aiocb_type = AIOCB_FLUSH_CACHE;
acb->aio_done_func = sd_finish_aiocb;
ret = do_req(s->flush_fd, (SheepdogReq *)&hdr, NULL, &wlen, &rlen);
if (ret) {
error_report("failed to send a request to the sheep");
aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id),
0, 0, 0, 0, 0);
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
ret = add_aio_request(s, aio_req, NULL, 0, false, acb->aiocb_type);
if (ret < 0) {
error_report("add_aio_request is failed");
free_aio_req(s, aio_req);
qemu_aio_release(acb);
return ret;
}
if (rsp->result == SD_RES_INVALID_PARMS) {
dprintf("disable write cache since the server doesn't support it\n");
s->cache_enabled = false;
closesocket(s->flush_fd);
return 0;
}
if (rsp->result != SD_RES_SUCCESS) {
error_report("%s", sd_strerror(rsp->result));
return -EIO;
}
return 0;
qemu_coroutine_yield();
return acb->ret;
}
static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
@ -1766,21 +1795,21 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
/* refresh inode. */
fd = connect_to_sdog(s->addr, s->port);
fd = connect_to_sdog(s);
if (fd < 0) {
ret = fd;
goto cleanup;
}
ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
s->inode.nr_copies, datalen, 0, false, s->cache_enabled);
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->name, s->inode.vdi_size, s->inode.vdi_id, &new_vid, 1,
s->addr, s->port);
ret = do_sd_create(s, s->name, s->inode.vdi_size, s->inode.vdi_id, &new_vid,
1);
if (ret < 0) {
error_report("failed to create inode for snapshot. %s",
strerror(errno));
@ -1790,7 +1819,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
inode = (SheepdogInode *)g_malloc(datalen);
ret = read_object(fd, (char *)inode, vid_to_vdi_oid(new_vid),
s->inode.nr_copies, datalen, 0, s->cache_enabled);
s->inode.nr_copies, datalen, 0, s->cache_flags);
if (ret < 0) {
error_report("failed to read new inode info. %s", strerror(errno));
@ -1835,16 +1864,15 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
goto out;
}
fd = connect_to_sdog(s->addr, s->port);
fd = connect_to_sdog(s);
if (fd < 0) {
error_report("failed to connect");
ret = fd;
goto out;
}
buf = g_malloc(SD_INODE_SIZE);
ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies,
SD_INODE_SIZE, 0, s->cache_enabled);
SD_INODE_SIZE, 0, s->cache_flags);
closesocket(fd);
@ -1899,7 +1927,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
vdi_inuse = g_malloc(max);
fd = connect_to_sdog(s->addr, s->port);
fd = connect_to_sdog(s);
if (fd < 0) {
ret = fd;
goto out;
@ -1926,9 +1954,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->addr, s->port);
fd = connect_to_sdog(s);
if (fd < 0) {
error_report("failed to connect");
ret = fd;
goto out;
}
@ -1941,7 +1968,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
/* we don't need to read entire object */
ret = read_object(fd, (char *)&inode, vid_to_vdi_oid(vid),
0, SD_INODE_SIZE - sizeof(inode.data_vdi_id), 0,
s->cache_enabled);
s->cache_flags);
if (ret) {
continue;
@ -1985,7 +2012,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
uint32_t vdi_index;
uint64_t offset;
fd = connect_to_sdog(s->addr, s->port);
fd = connect_to_sdog(s);
if (fd < 0) {
return fd;
}
@ -2002,11 +2029,11 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
if (load) {
ret = read_object(fd, (char *)data, vmstate_oid,
s->inode.nr_copies, data_len, offset,
s->cache_enabled);
s->cache_flags);
} else {
ret = write_object(fd, (char *)data, vmstate_oid,
s->inode.nr_copies, data_len, offset, create,
s->cache_enabled);
s->cache_flags);
}
if (ret < 0) {
@ -2060,7 +2087,7 @@ static QEMUOptionParameter sd_create_options[] = {
{ NULL }
};
BlockDriver bdrv_sheepdog = {
static BlockDriver bdrv_sheepdog = {
.format_name = "sheepdog",
.protocol_name = "sheepdog",
.instance_size = sizeof(BDRVSheepdogState),
@ -2085,8 +2112,60 @@ BlockDriver bdrv_sheepdog = {
.create_options = sd_create_options,
};
static BlockDriver bdrv_sheepdog_tcp = {
.format_name = "sheepdog",
.protocol_name = "sheepdog+tcp",
.instance_size = sizeof(BDRVSheepdogState),
.bdrv_file_open = sd_open,
.bdrv_close = sd_close,
.bdrv_create = sd_create,
.bdrv_getlength = sd_getlength,
.bdrv_truncate = sd_truncate,
.bdrv_co_readv = sd_co_readv,
.bdrv_co_writev = sd_co_writev,
.bdrv_co_flush_to_disk = sd_co_flush_to_disk,
.bdrv_snapshot_create = sd_snapshot_create,
.bdrv_snapshot_goto = sd_snapshot_goto,
.bdrv_snapshot_delete = sd_snapshot_delete,
.bdrv_snapshot_list = sd_snapshot_list,
.bdrv_save_vmstate = sd_save_vmstate,
.bdrv_load_vmstate = sd_load_vmstate,
.create_options = sd_create_options,
};
static BlockDriver bdrv_sheepdog_unix = {
.format_name = "sheepdog",
.protocol_name = "sheepdog+unix",
.instance_size = sizeof(BDRVSheepdogState),
.bdrv_file_open = sd_open,
.bdrv_close = sd_close,
.bdrv_create = sd_create,
.bdrv_getlength = sd_getlength,
.bdrv_truncate = sd_truncate,
.bdrv_co_readv = sd_co_readv,
.bdrv_co_writev = sd_co_writev,
.bdrv_co_flush_to_disk = sd_co_flush_to_disk,
.bdrv_snapshot_create = sd_snapshot_create,
.bdrv_snapshot_goto = sd_snapshot_goto,
.bdrv_snapshot_delete = sd_snapshot_delete,
.bdrv_snapshot_list = sd_snapshot_list,
.bdrv_save_vmstate = sd_save_vmstate,
.bdrv_load_vmstate = sd_load_vmstate,
.create_options = sd_create_options,
};
static void bdrv_sheepdog_init(void)
{
bdrv_register(&bdrv_sheepdog);
bdrv_register(&bdrv_sheepdog_tcp);
bdrv_register(&bdrv_sheepdog_unix);
}
block_init(bdrv_sheepdog_init);

View File

@ -246,7 +246,7 @@ static void vdi_header_print(VdiHeader *header)
{
char uuid[37];
logout("text %s", header->text);
logout("signature 0x%04x\n", header->signature);
logout("signature 0x%08x\n", header->signature);
logout("header size 0x%04x\n", header->header_size);
logout("image type 0x%04x\n", header->image_type);
logout("image flags 0x%04x\n", header->image_flags);
@ -364,15 +364,17 @@ static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename)
return result;
}
static int vdi_open(BlockDriverState *bs, int flags)
static int vdi_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVVdiState *s = bs->opaque;
VdiHeader header;
size_t bmap_size;
int ret;
logout("\n");
if (bdrv_read(bs->file, 0, (uint8_t *)&header, 1) < 0) {
ret = bdrv_read(bs->file, 0, (uint8_t *)&header, 1);
if (ret < 0) {
goto fail;
}
@ -390,33 +392,45 @@ static int vdi_open(BlockDriverState *bs, int flags)
header.disk_size &= ~(SECTOR_SIZE - 1);
}
if (header.version != VDI_VERSION_1_1) {
if (header.signature != VDI_SIGNATURE) {
logout("bad vdi signature %08x\n", header.signature);
ret = -EMEDIUMTYPE;
goto fail;
} else if (header.version != VDI_VERSION_1_1) {
logout("unsupported version %u.%u\n",
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. */
logout("unsupported block map offset 0x%x B\n", 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. */
logout("unsupported data offset 0x%x B\n", header.offset_data);
ret = -ENOTSUP;
goto fail;
} else if (header.sector_size != SECTOR_SIZE) {
logout("unsupported sector size %u B\n", header.sector_size);
ret = -ENOTSUP;
goto fail;
} else if (header.block_size != 1 * MiB) {
logout("unsupported block size %u B\n", header.block_size);
ret = -ENOTSUP;
goto fail;
} else if (header.disk_size >
(uint64_t)header.blocks_in_image * header.block_size) {
logout("unsupported disk size %" PRIu64 " B\n", header.disk_size);
ret = -ENOTSUP;
goto fail;
} else if (!uuid_is_null(header.uuid_link)) {
logout("link uuid != 0, unsupported\n");
ret = -ENOTSUP;
goto fail;
} else if (!uuid_is_null(header.uuid_parent)) {
logout("parent uuid != 0, unsupported\n");
ret = -ENOTSUP;
goto fail;
}
@ -429,10 +443,9 @@ static int vdi_open(BlockDriverState *bs, int flags)
bmap_size = header.blocks_in_image * sizeof(uint32_t);
bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
if (bmap_size > 0) {
s->bmap = g_malloc(bmap_size * SECTOR_SIZE);
}
if (bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
s->bmap = g_malloc(bmap_size * SECTOR_SIZE);
ret = bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size);
if (ret < 0) {
goto fail_free_bmap;
}
@ -448,7 +461,7 @@ static int vdi_open(BlockDriverState *bs, int flags)
g_free(s->bmap);
fail:
return -1;
return ret;
}
static int vdi_reopen_prepare(BDRVReopenState *state,

View File

@ -616,7 +616,7 @@ static int vmdk_open_sparse(BlockDriverState *bs,
return vmdk_open_vmdk4(bs, file, flags);
break;
default:
return -EINVAL;
return -EMEDIUMTYPE;
break;
}
}
@ -641,7 +641,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
* RW [size in sectors] SPARSE "file-name.vmdk"
*/
flat_offset = -1;
ret = sscanf(p, "%10s %" SCNd64 " %10s %511s %" SCNd64,
ret = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64,
access, &sectors, type, fname, &flat_offset);
if (ret < 4 || strcmp(access, "RW")) {
goto next_line;
@ -653,14 +653,6 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
return -EINVAL;
}
/* trim the quotation marks around */
if (fname[0] == '"') {
memmove(fname, fname + 1, strlen(fname));
if (strlen(fname) <= 1 || fname[strlen(fname) - 1] != '"') {
return -EINVAL;
}
fname[strlen(fname) - 1] = '\0';
}
if (sectors <= 0 ||
(strcmp(type, "FLAT") && strcmp(type, "SPARSE")) ||
(strcmp(access, "RW"))) {
@ -718,7 +710,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
}
buf[2047] = '\0';
if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) {
return -EINVAL;
return -EMEDIUMTYPE;
}
if (strcmp(ct, "monolithicFlat") &&
strcmp(ct, "twoGbMaxExtentSparse") &&
@ -731,7 +723,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
return vmdk_parse_extents(buf, bs, bs->file->filename);
}
static int vmdk_open(BlockDriverState *bs, int flags)
static int vmdk_open(BlockDriverState *bs, QDict *options, int flags)
{
int ret;
BDRVVmdkState *s = bs->opaque;
@ -1442,6 +1434,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
int fd, idx = 0;
char desc[BUF_SIZE];
int64_t total_size = 0, filesize;
const char *adapter_type = NULL;
const char *backing_file = NULL;
const char *fmt = NULL;
int flags = 0;
@ -1453,6 +1446,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
const char *desc_extent_line;
char parent_desc_line[BUF_SIZE] = "";
uint32_t parent_cid = 0xffffffff;
uint32_t number_heads = 16;
const char desc_template[] =
"# Disk DescriptorFile\n"
"version=1\n"
@ -1469,9 +1463,9 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
"\n"
"ddb.virtualHWVersion = \"%d\"\n"
"ddb.geometry.cylinders = \"%" PRId64 "\"\n"
"ddb.geometry.heads = \"16\"\n"
"ddb.geometry.heads = \"%d\"\n"
"ddb.geometry.sectors = \"63\"\n"
"ddb.adapterType = \"ide\"\n";
"ddb.adapterType = \"%s\"\n";
if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) {
return -EINVAL;
@ -1480,6 +1474,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
total_size = options->value.n;
} else if (!strcmp(options->name, BLOCK_OPT_ADAPTER_TYPE)) {
adapter_type = options->value.s;
} else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
backing_file = options->value.s;
} else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
@ -1489,6 +1485,20 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
}
options++;
}
if (!adapter_type) {
adapter_type = "ide";
} else if (strcmp(adapter_type, "ide") &&
strcmp(adapter_type, "buslogic") &&
strcmp(adapter_type, "lsilogic") &&
strcmp(adapter_type, "legacyESX")) {
fprintf(stderr, "VMDK: Unknown adapter type: '%s'.\n", adapter_type);
return -EINVAL;
}
if (strcmp(adapter_type, "ide") != 0) {
/* that's the number of heads with which vmware operates when
creating, exporting, etc. vmdk files with a non-ide adapter type */
number_heads = 255;
}
if (!fmt) {
/* Default format to monolithicSparse */
fmt = "monolithicSparse";
@ -1517,7 +1527,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
if (backing_file) {
char parent_filename[PATH_MAX];
BlockDriverState *bs = bdrv_new("");
ret = bdrv_open(bs, backing_file, 0, NULL);
ret = bdrv_open(bs, backing_file, NULL, 0, NULL);
if (ret != 0) {
bdrv_delete(bs);
return ret;
@ -1576,7 +1586,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
parent_desc_line,
ext_desc_lines,
(flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
total_size / (int64_t)(63 * 16 * 512));
total_size / (int64_t)(63 * number_heads * 512), number_heads,
adapter_type);
if (split || flat) {
fd = qemu_open(filename,
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
@ -1660,6 +1671,12 @@ static QEMUOptionParameter vmdk_create_options[] = {
.type = OPT_SIZE,
.help = "Virtual disk size"
},
{
.name = BLOCK_OPT_ADAPTER_TYPE,
.type = OPT_STRING,
.help = "Virtual adapter type, can be one of "
"ide (default), lsilogic, buslogic or legacyESX"
},
{
.name = BLOCK_OPT_BACKING_FILE,
.type = OPT_STRING,

View File

@ -155,7 +155,7 @@ static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int vpc_open(BlockDriverState *bs, int flags)
static int vpc_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVVPCState *s = bs->opaque;
int i;
@ -163,24 +163,33 @@ static int vpc_open(BlockDriverState *bs, int flags)
struct vhd_dyndisk_header* dyndisk_header;
uint8_t buf[HEADER_SIZE];
uint32_t checksum;
int err = -1;
int disk_type = VHD_DYNAMIC;
int ret;
if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
ret = bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE);
if (ret < 0) {
goto fail;
}
footer = (struct vhd_footer*) s->footer_buf;
if (strncmp(footer->creator, "conectix", 8)) {
int64_t offset = bdrv_getlength(bs->file);
if (offset < HEADER_SIZE) {
if (offset < 0) {
ret = offset;
goto fail;
} else if (offset < HEADER_SIZE) {
ret = -EINVAL;
goto fail;
}
/* If a fixed disk, the footer is found only at the end of the file */
if (bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf, HEADER_SIZE)
!= HEADER_SIZE) {
ret = bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf,
HEADER_SIZE);
if (ret < 0) {
goto fail;
}
if (strncmp(footer->creator, "conectix", 8)) {
ret = -EMEDIUMTYPE;
goto fail;
}
disk_type = VHD_FIXED;
@ -203,19 +212,21 @@ static int vpc_open(BlockDriverState *bs, int flags)
/* Allow a maximum disk size of approximately 2 TB */
if (bs->total_sectors >= 65535LL * 255 * 255) {
err = -EFBIG;
ret = -EFBIG;
goto fail;
}
if (disk_type == VHD_DYNAMIC) {
if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
HEADER_SIZE) != HEADER_SIZE) {
ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
HEADER_SIZE);
if (ret < 0) {
goto fail;
}
dyndisk_header = (struct vhd_dyndisk_header *) buf;
if (strncmp(dyndisk_header->magic, "cxsparse", 8)) {
ret = -EINVAL;
goto fail;
}
@ -226,8 +237,10 @@ static int vpc_open(BlockDriverState *bs, int flags)
s->pagetable = g_malloc(s->max_table_entries * 4);
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
if (bdrv_pread(bs->file, s->bat_offset, s->pagetable,
s->max_table_entries * 4) != s->max_table_entries * 4) {
ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable,
s->max_table_entries * 4);
if (ret < 0) {
goto fail;
}
@ -265,8 +278,13 @@ static int vpc_open(BlockDriverState *bs, int flags)
migrate_add_blocker(s->migration_blocker);
return 0;
fail:
return err;
fail:
g_free(s->pagetable);
#ifdef CACHE
g_free(s->pageentry_u8);
#endif
return ret;
}
static int vpc_reopen_prepare(BDRVReopenState *state,

View File

@ -529,13 +529,9 @@ static inline uint8_t fat_chksum(const direntry_t* entry)
/* if return_time==0, this returns the fat_date, else the fat_time */
static uint16_t fat_datetime(time_t time,int return_time) {
struct tm* t;
#ifdef _WIN32
t=localtime(&time); /* this is not thread safe */
#else
struct tm t1;
t = &t1;
localtime_r(&time,t);
#endif
if(return_time)
return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
@ -2834,7 +2830,7 @@ static int enable_write_target(BDRVVVFATState *s)
return -1;
}
ret = bdrv_open(s->qcow, s->qcow_filename,
ret = bdrv_open(s->qcow, s->qcow_filename, NULL,
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow);
if (ret < 0) {
return ret;

View File

@ -29,6 +29,7 @@
#include "block/aio.h"
#include "raw-aio.h"
#include "qemu/event_notifier.h"
#include "qemu/iov.h"
#include <windows.h>
#include <winioctl.h>
@ -80,15 +81,9 @@ static void win32_aio_process_completion(QEMUWin32AIOState *s,
if (!waiocb->is_linear) {
if (ret == 0 && waiocb->is_read) {
QEMUIOVector *qiov = waiocb->qiov;
char *p = waiocb->buf;
int i;
for (i = 0; i < qiov->niov; ++i) {
memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len);
p += qiov->iov[i].iov_len;
}
g_free(waiocb->buf);
iov_from_buf(qiov->iov, qiov->niov, 0, waiocb->buf, qiov->size);
}
qemu_vfree(waiocb->buf);
}
@ -153,13 +148,7 @@ BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
if (qiov->niov > 1) {
waiocb->buf = qemu_blockalign(bs, qiov->size);
if (type & QEMU_AIO_WRITE) {
char *p = waiocb->buf;
int i;
for (i = 0; i < qiov->niov; ++i) {
memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len);
p += qiov->iov[i].iov_len;
}
iov_to_buf(qiov->iov, qiov->niov, 0, waiocb->buf, qiov->size);
}
waiocb->is_linear = false;
} else {

View File

@ -5,6 +5,29 @@
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* later. See the COPYING file in the top-level directory.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "sysemu/blockdev.h"
@ -22,6 +45,7 @@
#include "sysemu/arch_init.h"
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
extern QemuOptsList qemu_common_drive_opts;
static const char *const if_name[IF_COUNT] = {
[IF_NONE] = "none",
@ -191,6 +215,7 @@ static void drive_uninit(DriveInfo *dinfo)
bdrv_delete(dinfo->bdrv);
g_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
g_free(dinfo->serial);
g_free(dinfo);
}
@ -255,7 +280,7 @@ static int parse_block_error_action(const char *buf, bool is_read)
}
}
static bool do_check_io_limits(BlockIOLimit *io_limits)
static bool do_check_io_limits(BlockIOLimit *io_limits, Error **errp)
{
bool bps_flag;
bool iops_flag;
@ -269,13 +294,25 @@ static bool do_check_io_limits(BlockIOLimit *io_limits)
&& ((io_limits->iops[BLOCK_IO_LIMIT_READ] != 0)
|| (io_limits->iops[BLOCK_IO_LIMIT_WRITE] != 0));
if (bps_flag || iops_flag) {
error_setg(errp, "bps(iops) and bps_rd/bps_wr(iops_rd/iops_wr) "
"cannot be used at the same time");
return false;
}
if (io_limits->bps[BLOCK_IO_LIMIT_TOTAL] < 0 ||
io_limits->bps[BLOCK_IO_LIMIT_WRITE] < 0 ||
io_limits->bps[BLOCK_IO_LIMIT_READ] < 0 ||
io_limits->iops[BLOCK_IO_LIMIT_TOTAL] < 0 ||
io_limits->iops[BLOCK_IO_LIMIT_WRITE] < 0 ||
io_limits->iops[BLOCK_IO_LIMIT_READ] < 0) {
error_setg(errp, "bps and iops values must be 0 or greater");
return false;
}
return true;
}
DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
{
const char *buf;
const char *file = NULL;
@ -298,10 +335,37 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
bool copy_on_read;
bool locked;
int ret;
Error *error = NULL;
QemuOpts *opts;
QDict *bs_opts;
const char *id;
translation = BIOS_ATA_TRANSLATION_AUTO;
media = MEDIA_DISK;
/* Check common options by copying from all_opts to opts, all other options
* are stored in bs_opts. */
id = qemu_opts_id(all_opts);
opts = qemu_opts_create(&qemu_common_drive_opts, id, 1, &error);
if (error_is_set(&error)) {
qerror_report_err(error);
error_free(error);
return NULL;
}
bs_opts = qdict_new();
qemu_opts_to_qdict(all_opts, bs_opts);
qemu_opts_absorb_qdict(opts, bs_opts, &error);
if (error_is_set(&error)) {
qerror_report_err(error);
error_free(error);
return NULL;
}
if (id) {
qdict_del(bs_opts, "id");
}
/* extract parameters */
bus_id = qemu_opt_get_number(opts, "bus", 0);
unit_id = qemu_opt_get_number(opts, "unit", -1);
@ -381,6 +445,13 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
}
}
if ((buf = qemu_opt_get(opts, "discard")) != NULL) {
if (bdrv_parse_discard_flags(buf, &bdrv_flags) != 0) {
error_report("invalid discard option");
return NULL;
}
}
bdrv_flags |= BDRV_O_CACHE_WB;
if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
if (bdrv_parse_cache_flags(buf, &bdrv_flags) != 0) {
@ -430,9 +501,9 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
io_limits.iops[BLOCK_IO_LIMIT_WRITE] =
qemu_opt_get_number(opts, "iops_wr", 0);
if (!do_check_io_limits(&io_limits)) {
error_report("bps(iops) and bps_rd/bps_wr(iops_rd/iops_wr) "
"cannot be used at the same time");
if (!do_check_io_limits(&io_limits, &error)) {
error_report("%s", error_get_pretty(error));
error_free(error);
return NULL;
}
@ -547,10 +618,12 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
dinfo->heads = heads;
dinfo->secs = secs;
dinfo->trans = translation;
dinfo->opts = opts;
dinfo->opts = all_opts;
dinfo->refcount = 1;
dinfo->serial = serial;
dinfo->locked = locked;
if (serial != NULL) {
dinfo->serial = g_strdup(serial);
}
QTAILQ_INSERT_TAIL(&drives, dinfo, next);
bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
@ -571,17 +644,20 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
case IF_MTD:
break;
case IF_VIRTIO:
{
/* add virtio block device */
opts = qemu_opts_create_nofail(qemu_find_opts("device"));
QemuOpts *devopts;
devopts = qemu_opts_create_nofail(qemu_find_opts("device"));
if (arch_type == QEMU_ARCH_S390X) {
qemu_opt_set(opts, "driver", "virtio-blk-s390");
qemu_opt_set(devopts, "driver", "virtio-blk-s390");
} else {
qemu_opt_set(opts, "driver", "virtio-blk-pci");
qemu_opt_set(devopts, "driver", "virtio-blk-pci");
}
qemu_opt_set(opts, "drive", dinfo->id);
qemu_opt_set(devopts, "drive", dinfo->id);
if (devaddr)
qemu_opt_set(opts, "addr", devaddr);
qemu_opt_set(devopts, "addr", devaddr);
break;
}
default:
abort();
}
@ -619,18 +695,30 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
error_report("warning: disabling copy_on_read on readonly drive");
}
ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv);
ret = bdrv_open(dinfo->bdrv, file, bs_opts, bdrv_flags, drv);
bs_opts = NULL;
if (ret < 0) {
error_report("could not open disk image %s: %s",
file, strerror(-ret));
if (ret == -EMEDIUMTYPE) {
error_report("could not open disk image %s: not in %s format",
file, drv->format_name);
} else {
error_report("could not open disk image %s: %s",
file, strerror(-ret));
}
goto err;
}
if (bdrv_key_required(dinfo->bdrv))
autostart = 0;
qemu_opts_del(opts);
return dinfo;
err:
qemu_opts_del(opts);
QDECREF(bs_opts);
bdrv_delete(dinfo->bdrv);
g_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
@ -646,21 +734,17 @@ void do_commit(Monitor *mon, const QDict *qdict)
if (!strcmp(device, "all")) {
ret = bdrv_commit_all();
if (ret == -EBUSY) {
qerror_report(QERR_DEVICE_IN_USE, device);
return;
}
} else {
bs = bdrv_find(device);
if (!bs) {
qerror_report(QERR_DEVICE_NOT_FOUND, device);
monitor_printf(mon, "Device '%s' not found\n", device);
return;
}
ret = bdrv_commit(bs);
if (ret == -EBUSY) {
qerror_report(QERR_DEVICE_IN_USE, device);
return;
}
}
if (ret < 0) {
monitor_printf(mon, "'commit' error for '%s': %s\n", device,
strerror(-ret));
}
}
@ -794,7 +878,7 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp)
bdrv_img_create(new_image_file, format,
states->old_bs->filename,
states->old_bs->drv->format_name,
NULL, -1, flags, &local_err);
NULL, -1, flags, &local_err, false);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
goto delete_and_fail;
@ -803,7 +887,9 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp)
/* We will manually add the backing_hd field to the bs later */
states->new_bs = bdrv_new("");
ret = bdrv_open(states->new_bs, new_image_file,
/* TODO Inherit bs->options or only take explicit options with an
* extended QMP command? */
ret = bdrv_open(states->new_bs, new_image_file, NULL,
flags | BDRV_O_NO_BACKING, drv);
if (ret != 0) {
error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file);
@ -904,7 +990,7 @@ static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
int bdrv_flags, BlockDriver *drv,
const char *password, Error **errp)
{
if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
if (bdrv_open(bs, filename, NULL, bdrv_flags, drv) < 0) {
error_set(errp, QERR_OPEN_FILE_FAILED, filename);
return;
}
@ -978,8 +1064,7 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
io_limits.iops[BLOCK_IO_LIMIT_READ] = iops_rd;
io_limits.iops[BLOCK_IO_LIMIT_WRITE]= iops_wr;
if (!do_check_io_limits(&io_limits)) {
error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
if (!do_check_io_limits(&io_limits, errp)) {
return;
}
@ -1192,16 +1277,19 @@ void qmp_block_commit(const char *device,
drive_get_ref(drive_get_by_blockdev(bs));
}
#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
void qmp_drive_mirror(const char *device, const char *target,
bool has_format, const char *format,
enum MirrorSyncMode sync,
bool has_mode, enum NewImageMode mode,
bool has_speed, int64_t speed,
bool has_granularity, uint32_t granularity,
bool has_buf_size, int64_t buf_size,
bool has_on_source_error, BlockdevOnError on_source_error,
bool has_on_target_error, BlockdevOnError on_target_error,
Error **errp)
{
BlockDriverInfo bdi;
BlockDriverState *bs;
BlockDriverState *source, *target_bs;
BlockDriver *proto_drv;
@ -1223,6 +1311,21 @@ void qmp_drive_mirror(const char *device, const char *target,
if (!has_mode) {
mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
}
if (!has_granularity) {
granularity = 0;
}
if (!has_buf_size) {
buf_size = DEFAULT_MIRROR_BUF_SIZE;
}
if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) {
error_set(errp, QERR_INVALID_PARAMETER, device);
return;
}
if (granularity & (granularity - 1)) {
error_set(errp, QERR_INVALID_PARAMETER, device);
return;
}
bs = bdrv_find(device);
if (!bs) {
@ -1263,13 +1366,13 @@ void qmp_drive_mirror(const char *device, const char *target,
return;
}
bdrv_get_geometry(bs, &size);
size *= 512;
if (sync == MIRROR_SYNC_MODE_FULL && mode != NEW_IMAGE_MODE_EXISTING) {
/* create new image w/o backing file */
assert(format && drv);
bdrv_get_geometry(bs, &size);
size *= 512;
bdrv_img_create(target, format,
NULL, NULL, NULL, size, flags, &local_err);
NULL, NULL, NULL, size, flags, &local_err, false);
} else {
switch (mode) {
case NEW_IMAGE_MODE_EXISTING:
@ -1280,7 +1383,7 @@ void qmp_drive_mirror(const char *device, const char *target,
bdrv_img_create(target, format,
source->filename,
source->drv->format_name,
NULL, -1, flags, &local_err);
NULL, size, flags, &local_err, false);
break;
default:
abort();
@ -1292,8 +1395,11 @@ void qmp_drive_mirror(const char *device, const char *target,
return;
}
/* Mirroring takes care of copy-on-write using the source's backing
* file.
*/
target_bs = bdrv_new("");
ret = bdrv_open(target_bs, target, flags | BDRV_O_NO_BACKING, drv);
ret = bdrv_open(target_bs, target, NULL, flags | BDRV_O_NO_BACKING, drv);
if (ret < 0) {
bdrv_delete(target_bs);
@ -1301,18 +1407,8 @@ void qmp_drive_mirror(const char *device, const char *target,
return;
}
/* We need a backing file if we will copy parts of a cluster. */
if (bdrv_get_info(target_bs, &bdi) >= 0 && bdi.cluster_size != 0 &&
bdi.cluster_size >= BDRV_SECTORS_PER_DIRTY_CHUNK * 512) {
ret = bdrv_open_backing_file(target_bs);
if (ret < 0) {
bdrv_delete(target_bs);
error_set(errp, QERR_OPEN_FILE_FAILED, target);
return;
}
}
mirror_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
mirror_start(bs, target_bs, speed, granularity, buf_size, sync,
on_source_error, on_target_error,
block_job_cb, bs, &local_err);
if (local_err != NULL) {
bdrv_delete(target_bs);
@ -1431,3 +1527,141 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp)
bdrv_iterate(do_qmp_query_block_jobs_one, &prev);
return dummy.next;
}
QemuOptsList qemu_common_drive_opts = {
.name = "drive",
.head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),
.desc = {
{
.name = "bus",
.type = QEMU_OPT_NUMBER,
.help = "bus number",
},{
.name = "unit",
.type = QEMU_OPT_NUMBER,
.help = "unit number (i.e. lun for scsi)",
},{
.name = "if",
.type = QEMU_OPT_STRING,
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
},{
.name = "index",
.type = QEMU_OPT_NUMBER,
.help = "index number",
},{
.name = "cyls",
.type = QEMU_OPT_NUMBER,
.help = "number of cylinders (ide disk geometry)",
},{
.name = "heads",
.type = QEMU_OPT_NUMBER,
.help = "number of heads (ide disk geometry)",
},{
.name = "secs",
.type = QEMU_OPT_NUMBER,
.help = "number of sectors (ide disk geometry)",
},{
.name = "trans",
.type = QEMU_OPT_STRING,
.help = "chs translation (auto, lba. none)",
},{
.name = "media",
.type = QEMU_OPT_STRING,
.help = "media type (disk, cdrom)",
},{
.name = "snapshot",
.type = QEMU_OPT_BOOL,
.help = "enable/disable snapshot mode",
},{
.name = "file",
.type = QEMU_OPT_STRING,
.help = "disk image",
},{
.name = "discard",
.type = QEMU_OPT_STRING,
.help = "discard operation (ignore/off, unmap/on)",
},{
.name = "cache",
.type = QEMU_OPT_STRING,
.help = "host cache usage (none, writeback, writethrough, "
"directsync, unsafe)",
},{
.name = "aio",
.type = QEMU_OPT_STRING,
.help = "host AIO implementation (threads, native)",
},{
.name = "format",
.type = QEMU_OPT_STRING,
.help = "disk format (raw, qcow2, ...)",
},{
.name = "serial",
.type = QEMU_OPT_STRING,
.help = "disk serial number",
},{
.name = "rerror",
.type = QEMU_OPT_STRING,
.help = "read error action",
},{
.name = "werror",
.type = QEMU_OPT_STRING,
.help = "write error action",
},{
.name = "addr",
.type = QEMU_OPT_STRING,
.help = "pci address (virtio only)",
},{
.name = "readonly",
.type = QEMU_OPT_BOOL,
.help = "open drive file as read-only",
},{
.name = "iops",
.type = QEMU_OPT_NUMBER,
.help = "limit total I/O operations per second",
},{
.name = "iops_rd",
.type = QEMU_OPT_NUMBER,
.help = "limit read operations per second",
},{
.name = "iops_wr",
.type = QEMU_OPT_NUMBER,
.help = "limit write operations per second",
},{
.name = "bps",
.type = QEMU_OPT_NUMBER,
.help = "limit total bytes per second",
},{
.name = "bps_rd",
.type = QEMU_OPT_NUMBER,
.help = "limit read bytes per second",
},{
.name = "bps_wr",
.type = QEMU_OPT_NUMBER,
.help = "limit write bytes per second",
},{
.name = "copy-on-read",
.type = QEMU_OPT_BOOL,
.help = "copy read data from backing file into image file",
},{
.name = "boot",
.type = QEMU_OPT_BOOL,
.help = "(deprecated, ignored)",
},{
.name = "locked",
.type = QEMU_OPT_BOOL,
.help = "emulate a security locked drive",
},
{ /* end of list */ }
},
};
QemuOptsList qemu_drive_opts = {
.name = "drive",
.head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
.desc = {
/*
* no elements => accept any params
* validation will happen later
*/
{ /* end of list */ }
},
};

View File

@ -34,8 +34,6 @@
#include "qemu/timer.h"
#include "qemu/envlist.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
int singlestep;
#if defined(CONFIG_USE_GUEST_BASE)
unsigned long mmap_min_addr;
@ -691,11 +689,12 @@ static void usage(void)
"-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
"\n"
"Debug options:\n"
"-d options activate log (default logfile=%s)\n"
"-D logfile override default logfile location\n"
"-p pagesize set the host page size to 'pagesize'\n"
"-singlestep always run in singlestep mode\n"
"-strace log system calls\n"
"-d item1[,...] enable logging of specified items\n"
" (use '-d help' for a list of log items)\n"
"-D logfile write logs to 'logfile' (default stderr)\n"
"-p pagesize set the host page size to 'pagesize'\n"
"-singlestep always run in singlestep mode\n"
"-strace log system calls\n"
"\n"
"Environment variables:\n"
"QEMU_STRACE Print system calls and arguments similar to the\n"
@ -709,8 +708,7 @@ static void usage(void)
,
TARGET_ARCH,
interp_prefix,
x86_stack_size,
DEBUG_LOGFILE);
x86_stack_size);
exit(1);
}
@ -733,7 +731,7 @@ int main(int argc, char **argv)
{
const char *filename;
const char *cpu_model;
const char *log_file = DEBUG_LOGFILE;
const char *log_file = NULL;
const char *log_mask = NULL;
struct target_pt_regs regs1, *regs = &regs1;
struct image_info info1, *info = &info1;
@ -861,20 +859,16 @@ int main(int argc, char **argv)
}
/* init debug */
cpu_set_log_filename(log_file);
qemu_set_log_filename(log_file);
if (log_mask) {
int mask;
const CPULogItem *item;
mask = cpu_str_to_log_mask(log_mask);
mask = qemu_str_to_log_mask(log_mask);
if (!mask) {
printf("Log items (comma separated):\n");
for (item = cpu_log_items; item->mask != 0; item++) {
printf("%-10s %s\n", item->name, item->help);
}
qemu_print_log_usage(stdout);
exit(1);
}
cpu_set_log(mask);
qemu_set_log(mask);
}
if (optind >= argc) {
@ -917,7 +911,7 @@ int main(int argc, char **argv)
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
#if defined(TARGET_SPARC) || defined(TARGET_PPC)
cpu_reset(ENV_GET_CPU(env));
#endif
thread_env = env;

View File

@ -74,7 +74,7 @@ void mmap_unlock(void)
}
#endif
void *qemu_vmalloc(size_t size)
static void *bsd_vmalloc(size_t size)
{
void *p;
mmap_lock();
@ -98,7 +98,7 @@ void *g_malloc(size_t size)
{
char * p;
size += 16;
p = qemu_vmalloc(size);
p = bsd_vmalloc(size);
*(size_t *)p = size;
return p + 16;
}

392
configure vendored
View File

@ -158,6 +158,7 @@ vnc_tls=""
vnc_sasl=""
vnc_jpeg=""
vnc_png=""
vnc_ws=""
xen=""
xen_ctrl_version=""
xen_pci_passthrough=""
@ -176,6 +177,8 @@ strip_opt="yes"
tcg_interpreter="no"
bigendian="no"
mingw32="no"
gcov="no"
gcov_tool="gcov"
EXESUF=""
prefix="/usr/local"
mandir="\${prefix}/share/man"
@ -212,7 +215,6 @@ trace_backend="nop"
trace_file="trace"
spice=""
rbd=""
smartcard=""
smartcard_nss=""
usb_redir=""
opengl=""
@ -223,6 +225,10 @@ libiscsi=""
coroutine=""
seccomp=""
glusterfs=""
virtio_blk_data_plane=""
gtk=""
gtkabi="2.0"
tpm="no"
# parse CC options first
for opt do
@ -237,8 +243,10 @@ for opt do
--cpu=*) cpu="$optarg"
;;
--extra-cflags=*) QEMU_CFLAGS="$optarg $QEMU_CFLAGS"
EXTRA_CFLAGS="$optarg"
;;
--extra-ldflags=*) LDFLAGS="$optarg $LDFLAGS"
EXTRA_LDFLAGS="$optarg"
;;
--enable-debug-info) debug_info="yes"
;;
@ -261,6 +269,8 @@ else
fi
ar="${AR-${cross_prefix}ar}"
as="${AS-${cross_prefix}as}"
cpp="${CPP-$cc -E}"
objcopy="${OBJCOPY-${cross_prefix}objcopy}"
ld="${LD-${cross_prefix}ld}"
libtool="${LIBTOOL-${cross_prefix}libtool}"
@ -599,6 +609,8 @@ for opt do
;;
--python=*) python="$optarg"
;;
--gcov=*) gcov_tool="$optarg"
;;
--smbd=*) smbd="$optarg"
;;
--extra-cflags=*)
@ -619,6 +631,8 @@ for opt do
;;
--enable-gprof) gprof="yes"
;;
--enable-gcov) gcov="yes"
;;
--static)
static="yes"
LDFLAGS="-static $LDFLAGS"
@ -656,6 +670,8 @@ for opt do
;;
--without-system-pixman) pixman="internal"
;;
--without-pixman) pixman="none"
;;
--disable-sdl) sdl="no"
;;
--enable-sdl) sdl="yes"
@ -712,6 +728,10 @@ for opt do
;;
--enable-vnc-png) vnc_png="yes"
;;
--disable-vnc-ws) vnc_ws="no"
;;
--enable-vnc-ws) vnc_ws="yes"
;;
--disable-slirp) slirp="no"
;;
--disable-uuid) uuid="no"
@ -850,10 +870,6 @@ for opt do
;;
--enable-xfsctl) xfs="yes"
;;
--disable-smartcard) smartcard="no"
;;
--enable-smartcard) smartcard="yes"
;;
--disable-smartcard-nss) smartcard_nss="no"
;;
--enable-smartcard-nss) smartcard_nss="yes"
@ -880,6 +896,18 @@ for opt do
;;
--enable-glusterfs) glusterfs="yes"
;;
--disable-virtio-blk-data-plane) virtio_blk_data_plane="no"
;;
--enable-virtio-blk-data-plane) virtio_blk_data_plane="yes"
;;
--disable-gtk) gtk="no"
;;
--enable-gtk) gtk="yes"
;;
--with-gtkabi=*) gtkabi="$optarg"
;;
--enable-tpm) tpm="yes"
;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
@ -961,6 +989,10 @@ microblaze-linux-user \
microblazeel-linux-user \
mips-linux-user \
mipsel-linux-user \
mips64-linux-user \
mips64el-linux-user \
mipsn32-linux-user \
mipsn32el-linux-user \
or32-linux-user \
ppc-linux-user \
ppc64-linux-user \
@ -1030,6 +1062,8 @@ echo " --disable-strip disable stripping binaries"
echo " --disable-werror disable compilation abort on warning"
echo " --disable-sdl disable SDL"
echo " --enable-sdl enable SDL"
echo " --disable-gtk disable gtk UI"
echo " --enable-gtk enable gtk UI"
echo " --disable-virtfs disable VirtFS"
echo " --enable-virtfs enable VirtFS"
echo " --disable-vnc disable VNC"
@ -1057,6 +1091,8 @@ echo " --disable-vnc-jpeg disable JPEG lossy compression for VNC server"
echo " --enable-vnc-jpeg enable JPEG lossy compression for VNC server"
echo " --disable-vnc-png disable PNG compression for VNC server (default)"
echo " --enable-vnc-png enable PNG compression for VNC server"
echo " --disable-vnc-ws disable Websockets support for VNC server"
echo " --enable-vnc-ws enable Websockets support for VNC server"
echo " --disable-curses disable curses output"
echo " --enable-curses enable curses output"
echo " --disable-curl disable curl connectivity"
@ -1089,7 +1125,6 @@ echo " --fmod-inc path to FMOD includes"
echo " --oss-lib path to OSS library"
echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
echo " --cpu=CPU Build for host CPU [$cpu]"
echo " --sparc_cpu=V Build qemu for Sparc architecture v7, v8, v8plus, v8plusa, v9"
echo " --disable-uuid disable uuid support"
echo " --enable-uuid enable uuid support"
echo " --disable-vde disable support for vde network"
@ -1114,8 +1149,6 @@ echo " --enable-spice enable spice"
echo " --enable-rbd enable building the rados block device (rbd)"
echo " --disable-libiscsi disable iscsi support"
echo " --enable-libiscsi enable iscsi support"
echo " --disable-smartcard disable smartcard support"
echo " --enable-smartcard enable smartcard support"
echo " --disable-smartcard-nss disable smartcard nss support"
echo " --enable-smartcard-nss enable smartcard nss support"
echo " --disable-usb-redir disable usb network redirection support"
@ -1128,6 +1161,9 @@ echo " --with-coroutine=BACKEND coroutine backend. Supported options:"
echo " gthread, ucontext, sigaltstack, windows"
echo " --enable-glusterfs enable GlusterFS backend"
echo " --disable-glusterfs disable GlusterFS backend"
echo " --enable-gcov enable test coverage analysis with gcov"
echo " --gcov=GCOV use specified gcov [$gcov_tool]"
echo " --enable-tpm enable TPM support"
echo ""
echo "NOTE: The object files are built at the place where configure is launched"
exit 1
@ -1162,7 +1198,7 @@ fi
z_version=`cut -f3 -d. $source_path/VERSION`
if test -z "$werror" ; then
if test "$z_version" = "50" -a \
if test -d "$source_path/.git" -a \
"$linux" = "yes" ; then
werror="yes"
else
@ -1416,7 +1452,7 @@ fi
if test "$seccomp" != "no" ; then
if $pkg_config --atleast-version=1.0.0 libseccomp --modversion >/dev/null 2>&1; then
LIBS=`$pkg_config --libs libseccomp`
libs_softmmu="$libs_softmmu `$pkg_config --libs libseccomp`"
seccomp="yes"
else
if test "$seccomp" = "yes"; then
@ -1617,6 +1653,36 @@ if test "$sparse" != "no" ; then
fi
fi
##########################################
# GTK probe
if test "$gtk" != "no"; then
gtkpackage="gtk+-$gtkabi"
if test "$gtkabi" = "3.0" ; then
gtkversion="3.0.0"
vtepackage="vte-2.90"
vteversion="0.32.0"
else
gtkversion="2.18.0"
vtepackage="vte"
vteversion="0.24.0"
fi
if $pkg_config --exists "$gtkpackage >= $gtkversion" && \
$pkg_config --exists "$vtepackage >= $vteversion"; then
gtk_cflags=`$pkg_config --cflags $gtkpackage 2>/dev/null`
gtk_libs=`$pkg_config --libs $gtkpackage 2>/dev/null`
vte_cflags=`$pkg_config --cflags $vtepackage 2>/dev/null`
vte_libs=`$pkg_config --libs $vtepackage 2>/dev/null`
libs_softmmu="$gtk_libs $vte_libs $libs_softmmu"
gtk="yes"
else
if test "$gtk" = "yes" ; then
feature_not_found "gtk"
fi
gtk="no"
fi
fi
##########################################
# SDL probe
@ -1701,8 +1767,8 @@ EOF
fi
##########################################
# VNC TLS detection
if test "$vnc" = "yes" -a "$vnc_tls" != "no" ; then
# VNC TLS/WS detection
if test "$vnc" = "yes" -a \( "$vnc_tls" != "no" -o "$vnc_ws" != "no" \) ; then
cat > $TMPC <<EOF
#include <gnutls/gnutls.h>
int main(void) { gnutls_session_t s; gnutls_init(&s, GNUTLS_SERVER); return 0; }
@ -1710,14 +1776,23 @@ EOF
vnc_tls_cflags=`$pkg_config --cflags gnutls 2> /dev/null`
vnc_tls_libs=`$pkg_config --libs gnutls 2> /dev/null`
if compile_prog "$vnc_tls_cflags" "$vnc_tls_libs" ; then
vnc_tls=yes
if test "$vnc_tls" != "no" ; then
vnc_tls=yes
fi
if test "$vnc_ws" != "no" ; then
vnc_ws=yes
fi
libs_softmmu="$vnc_tls_libs $libs_softmmu"
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_tls_cflags"
else
if test "$vnc_tls" = "yes" ; then
feature_not_found "vnc-tls"
fi
if test "$vnc_ws" = "yes" ; then
feature_not_found "vnc-ws"
fi
vnc_tls=no
vnc_ws=no
fi
fi
@ -2028,7 +2103,7 @@ fi
if test "$mingw32" = "yes" ; then
curses_list="-lpdcurses"
else
curses_list="-lncurses -lcurses"
curses_list="-lncurses:-lcurses:$($pkg_config --libs ncurses 2>/dev/null)"
fi
if test "$curses" != "no" ; then
@ -2041,13 +2116,16 @@ int main(void) {
return s != 0;
}
EOF
IFS=:
for curses_lib in $curses_list; do
unset IFS
if compile_prog "" "$curses_lib" ; then
curses_found=yes
libs_softmmu="$curses_lib $libs_softmmu"
break
fi
done
unset IFS
if test "$curses_found" = "yes" ; then
curses=yes
else
@ -2130,13 +2208,25 @@ fi
# pixman support probe
if test "$pixman" = ""; then
if $pkg_config pixman-1 > /dev/null 2>&1; then
if test "$want_tools" = "no" -a "$softmmu" = "no"; then
pixman="none"
elif $pkg_config pixman-1 > /dev/null 2>&1; then
pixman="system"
else
pixman="internal"
fi
fi
if test "$pixman" = "system"; then
if test "$pixman" = "none"; then
if test "$want_tools" != "no" -o "$softmmu" != "no"; then
echo "ERROR: pixman disabled but system emulation or tools build"
echo " enabled. You can turn off pixman only if you also"
echo " disable all system emulation targets and the tools"
echo " build with '--disable-tools --disable-system'."
exit 1
fi
pixman_cflags=
pixman_libs=
elif test "$pixman" = "system"; then
pixman_cflags=`$pkg_config --cflags pixman-1 2>/dev/null`
pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null`
else
@ -2259,6 +2349,17 @@ EOF
fi
fi
##########################################
# adjust virtio-blk-data-plane based on linux-aio
if test "$virtio_blk_data_plane" = "yes" -a \
"$linux_aio" != "yes" ; then
echo "Error: virtio-blk-data-plane requires Linux AIO, please try --enable-linux-aio"
exit 1
elif test -z "$virtio_blk_data_plane" ; then
virtio_blk_data_plane=$linux_aio
fi
##########################################
# attr probe
@ -2323,6 +2424,7 @@ int main(void) { return 0; }
EOF
if compile_prog "" "$fdt_libs" ; then
fdt=yes
libs_softmmu="$libs_softmmu $fdt_libs"
else
if test "$fdt" = "yes" ; then
feature_not_found "fdt"
@ -2345,7 +2447,7 @@ if test "$opengl" != "no" ; then
int main(void) { return GL_VERSION != 0; }
EOF
else
opengl_libs="-lGL"
opengl_libs="-lGL -lX11"
cat > $TMPC << EOF
#include <X11/Xlib.h>
#include <GL/gl.h>
@ -2560,6 +2662,22 @@ if compile_prog "" "" ; then
fallocate=yes
fi
# check for fallocate hole punching
fallocate_punch_hole=no
cat > $TMPC << EOF
#include <fcntl.h>
#include <linux/falloc.h>
int main(void)
{
fallocate(0, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 0);
return 0;
}
EOF
if compile_prog "" "" ; then
fallocate_punch_hole=yes
fi
# check for sync_file_range
sync_file_range=no
cat > $TMPC << EOF
@ -2659,6 +2777,20 @@ if compile_prog "" "" ; then
epoll_pwait=yes
fi
# check for sendfile support
sendfile=no
cat > $TMPC << EOF
#include <sys/sendfile.h>
int main(void)
{
return sendfile(0, 0, 0, 0);
}
EOF
if compile_prog "" "" ; then
sendfile=yes
fi
# Check if tools are available to build documentation.
if test "$docs" != "no" ; then
if has makeinfo && has pod2man; then
@ -2681,7 +2813,7 @@ if compile_prog "" "" ; then
byteswap_h=yes
fi
# Search for bswap_32 function
# Search for bswap32 function
bswap_h=no
cat > $TMPC << EOF
#include <sys/endian.h>
@ -2703,7 +2835,13 @@ if test "$libiscsi" != "no" ; then
#include <iscsi/iscsi.h>
int main(void) { iscsi_unmap_sync(NULL,0,0,0,NULL,0); return 0; }
EOF
if compile_prog "" "-liscsi" ; then
if $pkg_config --atleast-version=1.7.0 libiscsi --modversion >/dev/null 2>&1; then
libiscsi="yes"
libiscsi_cflags=$($pkg_config --cflags libiscsi 2>/dev/null)
libiscsi_libs=$($pkg_config --libs libiscsi 2>/dev/null)
CFLAGS="$CFLAGS $libiscsi_cflags"
LIBS="$LIBS $libiscsi_libs"
elif compile_prog "" "-liscsi" ; then
libiscsi="yes"
LIBS="$LIBS -liscsi"
else
@ -2771,7 +2909,7 @@ EOF
spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
if $pkg_config --atleast-version=0.12.0 spice-server >/dev/null 2>&1 && \
$pkg_config --atleast-version=0.12.2 spice-protocol > /dev/null 2>&1 && \
$pkg_config --atleast-version=0.12.3 spice-protocol > /dev/null 2>&1 && \
compile_prog "$spice_cflags" "$spice_libs" ; then
spice="yes"
libs_softmmu="$libs_softmmu $spice_libs"
@ -2787,47 +2925,42 @@ EOF
fi
# check for libcacard for smartcard support
if test "$smartcard" != "no" ; then
smartcard="yes"
smartcard_cflags=""
# TODO - what's the minimal nss version we support?
if test "$smartcard_nss" != "no"; then
cat > $TMPC << EOF
smartcard_cflags=""
# TODO - what's the minimal nss version we support?
if test "$smartcard_nss" != "no"; then
cat > $TMPC << EOF
#include <pk11pub.h>
int main(void) { PK11_FreeSlot(0); return 0; }
EOF
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
# the configure test but fail to compile QEMU later.
if test "$werror" = "yes"; then
test_cflags="-Werror $test_cflags"
fi
if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 && \
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"
fi
smartcard_nss="no"
fi
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
# the configure test but fail to compile QEMU later.
if test "$werror" = "yes"; then
test_cflags="-Werror $test_cflags"
fi
if test -n "$libtool" &&
$pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 && \
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"
fi
smartcard_nss="no"
fi
fi
if test "$smartcard" = "no" ; then
smartcard_nss="no"
fi
# check for usbredirparser for usb network redirection support
if test "$usb_redir" != "no" ; then
if $pkg_config --atleast-version=0.5.3 libusbredirparser-0.5 >/dev/null 2>&1 ; then
if $pkg_config --atleast-version=0.6 libusbredirparser-0.5 >/dev/null 2>&1 ; then
usb_redir="yes"
usb_redir_cflags=$($pkg_config --cflags libusbredirparser-0.5 2>/dev/null)
usb_redir_libs=$($pkg_config --libs libusbredirparser-0.5 2>/dev/null)
@ -3039,20 +3172,27 @@ if compile_prog "" "" ; then
fi
########################################
# check whether we can disable the -Wunused-but-set-variable
# option with a pragma (this is needed to silence a warning in
# some versions of the valgrind VALGRIND_STACK_DEREGISTER macro.)
# This test has to be compiled with -Werror as otherwise an
# unknown pragma is only a warning.
# check whether we can disable warning option with a pragma (this is needed
# to silence warnings in the headers of some versions of external libraries).
# This test has to be compiled with -Werror as otherwise an unknown pragma is
# only a warning.
#
# If we can't selectively disable warning in the code, disable -Werror so that
# the build doesn't fail anyway.
pragma_disable_unused_but_set=no
cat > $TMPC << EOF
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
int main(void) {
return 0;
}
EOF
if compile_prog "-Werror" "" ; then
pragma_disable_unused_but_set=yes
pragma_diagnostic_available=yes
else
werror=no
fi
########################################
@ -3085,14 +3225,49 @@ if compile_prog "" "" ; then
has_environ=yes
fi
########################################
# check if cpuid.h is usable.
cpuid_h=no
cat > $TMPC << EOF
#include <cpuid.h>
int main(void) {
return 0;
}
EOF
if compile_prog "" "" ; then
cpuid_h=yes
fi
########################################
# check if __[u]int128_t is usable.
int128=no
cat > $TMPC << EOF
__int128_t a;
__uint128_t b;
int main (void) {
a = a + b;
b = a * b;
return 0;
}
EOF
if compile_prog "" "" ; then
int128=yes
fi
##########################################
# End of CC checks
# After here, no more $cc or $ld runs
if test "$debug" = "no" ; then
if test "$gcov" = "yes" ; then
CFLAGS="-fprofile-arcs -ftest-coverage -g $CFLAGS"
LDFLAGS="-fprofile-arcs -ftest-coverage $LDFLAGS"
elif test "$debug" = "no" ; then
CFLAGS="-O2 -D_FORTIFY_SOURCE=2 $CFLAGS"
fi
# Disable zero malloc errors for official releases unless explicitly told to
# enable/disable
if test -z "$zero_malloc" ; then
@ -3132,6 +3307,7 @@ fi
qemu_confdir=$sysconfdir$confsuffix
qemu_datadir=$datadir$confsuffix
qemu_localedir="$datadir/locale"
tools=""
if test "$want_tools" = "yes" ; then
@ -3158,9 +3334,6 @@ if test "$softmmu" = yes ; then
tools="qemu-ga\$(EXESUF) $tools"
fi
fi
if test "$smartcard_nss" = "yes" ; then
tools="vscclient\$(EXESUF) $tools"
fi
fi
# Mac OS X ships with a broken assembler
@ -3218,6 +3391,7 @@ if test "$darwin" = "yes" ; then
fi
echo "pixman $pixman"
echo "SDL support $sdl"
echo "GTK support $gtk"
echo "curses support $curses"
echo "curl support $curl"
echo "mingw32 support $mingw32"
@ -3232,6 +3406,7 @@ if test "$vnc" = "yes" ; then
echo "VNC SASL support $vnc_sasl"
echo "VNC JPEG support $vnc_jpeg"
echo "VNC PNG support $vnc_png"
echo "VNC WS support $vnc_ws"
fi
if test -n "$sparc_cpu"; then
echo "Target Sparc Arch $sparc_cpu"
@ -3273,6 +3448,10 @@ echo "build guest agent $guest_agent"
echo "seccomp support $seccomp"
echo "coroutine backend $coroutine_backend"
echo "GlusterFS support $glusterfs"
echo "virtio-blk-data-plane $virtio_blk_data_plane"
echo "gcov $gcov_tool"
echo "gcov enabled $gcov"
echo "TPM support $tpm"
if test "$sdl_too_old" = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@ -3281,6 +3460,8 @@ fi
config_host_mak="config-host.mak"
config_host_ld="config-host.ld"
echo "# Automatically generated by configure - do not modify" >config-all-disas.mak
echo "# Automatically generated by configure - do not modify" > $config_host_mak
printf "# Configured with:" >> $config_host_mak
printf " '%s'" "$0" "$@" >> $config_host_mak
@ -3299,6 +3480,9 @@ echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
echo "qemu_localstatedir=$local_statedir" >> $config_host_mak
echo "qemu_helperdir=$libexecdir" >> $config_host_mak
echo "extra_cflags=$EXTRA_CFLAGS" >> $config_host_mak
echo "extra_ldflags=$EXTRA_LDFLAGS" >> $config_host_mak
echo "qemu_localedir=$qemu_localedir" >> $config_host_mak
echo "ARCH=$ARCH" >> $config_host_mak
if test "$debug_tcg" = "yes" ; then
@ -3403,6 +3587,10 @@ fi
if test "$vnc_png" = "yes" ; then
echo "CONFIG_VNC_PNG=y" >> $config_host_mak
fi
if test "$vnc_ws" = "yes" ; then
echo "CONFIG_VNC_WS=y" >> $config_host_mak
echo "VNC_WS_CFLAGS=$vnc_ws_cflags" >> $config_host_mak
fi
if test "$fnmatch" = "yes" ; then
echo "CONFIG_FNMATCH=y" >> $config_host_mak
fi
@ -3451,6 +3639,9 @@ fi
if test "$fallocate" = "yes" ; then
echo "CONFIG_FALLOCATE=y" >> $config_host_mak
fi
if test "$fallocate_punch_hole" = "yes" ; then
echo "CONFIG_FALLOCATE_PUNCH_HOLE=y" >> $config_host_mak
fi
if test "$sync_file_range" = "yes" ; then
echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak
fi
@ -3469,6 +3660,9 @@ fi
if test "$epoll_pwait" = "yes" ; then
echo "CONFIG_EPOLL_PWAIT=y" >> $config_host_mak
fi
if test "$sendfile" = "yes" ; then
echo "CONFIG_SENDFILE=y" >> $config_host_mak
fi
if test "$inotify" = "yes" ; then
echo "CONFIG_INOTIFY=y" >> $config_host_mak
fi
@ -3493,6 +3687,11 @@ if test "$bluez" = "yes" ; then
echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
fi
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
if test "$gtk" = "yes" ; then
echo "CONFIG_GTK=y" >> $config_host_mak
echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
fi
if test "$xen" = "yes" ; then
echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
@ -3544,10 +3743,6 @@ if test "$spice" = "yes" ; then
echo "CONFIG_SPICE=y" >> $config_host_mak
fi
if test "$smartcard" = "yes" ; then
echo "CONFIG_SMARTCARD=y" >> $config_host_mak
fi
if test "$smartcard_nss" = "yes" ; then
echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak
echo "libcacard_libs=$libcacard_libs" >> $config_host_mak
@ -3598,8 +3793,8 @@ if test "$linux_magic_h" = "yes" ; then
echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak
fi
if test "$pragma_disable_unused_but_set" = "yes" ; then
echo "CONFIG_PRAGMA_DISABLE_UNUSED_BUT_SET=y" >> $config_host_mak
if test "$pragma_diagnostic_available" = "yes" ; then
echo "CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE=y" >> $config_host_mak
fi
if test "$valgrind_h" = "yes" ; then
@ -3610,14 +3805,26 @@ if test "$has_environ" = "yes" ; then
echo "CONFIG_HAS_ENVIRON=y" >> $config_host_mak
fi
if test "$cpuid_h" = "yes" ; then
echo "CONFIG_CPUID_H=y" >> $config_host_mak
fi
if test "$int128" = "yes" ; then
echo "CONFIG_INT128=y" >> $config_host_mak
fi
if test "$glusterfs" = "yes" ; then
echo "CONFIG_GLUSTERFS=y" >> $config_host_mak
fi
if test "$virtio_blk_data_plane" = "yes" ; then
echo "CONFIG_VIRTIO_BLK_DATA_PLANE=y" >> $config_host_mak
fi
# USB host support
case "$usb" in
linux)
echo "HOST_USB=linux" >> $config_host_mak
echo "HOST_USB=linux legacy" >> $config_host_mak
;;
bsd)
echo "HOST_USB=bsd" >> $config_host_mak
@ -3663,13 +3870,21 @@ echo "MAKE=$make" >> $config_host_mak
echo "INSTALL=$install" >> $config_host_mak
echo "INSTALL_DIR=$install -d -m 0755" >> $config_host_mak
echo "INSTALL_DATA=$install -c -m 0644" >> $config_host_mak
echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak
if test -n "$libtool"; then
echo "INSTALL_PROG=\$(LIBTOOL) --mode=install $install -c -m 0755" >> $config_host_mak
echo "INSTALL_LIB=\$(LIBTOOL) --mode=install $install -c -m 0644" >> $config_host_mak
else
echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak
echo "INSTALL_LIB=$install -c -m 0644" >> $config_host_mak
fi
echo "PYTHON=$python" >> $config_host_mak
echo "CC=$cc" >> $config_host_mak
echo "CC_I386=$cc_i386" >> $config_host_mak
echo "HOST_CC=$host_cc" >> $config_host_mak
echo "OBJCC=$objcc" >> $config_host_mak
echo "AR=$ar" >> $config_host_mak
echo "AS=$as" >> $config_host_mak
echo "CPP=$cpp" >> $config_host_mak
echo "OBJCOPY=$objcopy" >> $config_host_mak
echo "LD=$ld" >> $config_host_mak
echo "WINDRES=$windres" >> $config_host_mak
@ -3696,6 +3911,10 @@ echo "EXESUF=$EXESUF" >> $config_host_mak
echo "LIBS_QGA+=$libs_qga" >> $config_host_mak
echo "POD2MAN=$POD2MAN" >> $config_host_mak
echo "TRANSLATE_OPT_CFLAGS=$TRANSLATE_OPT_CFLAGS" >> $config_host_mak
if test "$gcov" = "yes" ; then
echo "CONFIG_GCOV=y" >> $config_host_mak
echo "GCOV=$gcov_tool" >> $config_host_mak
fi
# generate list of library paths for linker script
@ -3808,7 +4027,6 @@ case "$target_arch2" in
target_nptl="yes"
gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml"
target_llong_alignment=4
target_libs_softmmu="$fdt_libs"
;;
cris)
target_nptl="yes"
@ -3826,7 +4044,6 @@ case "$target_arch2" in
TARGET_ARCH=microblaze
bflt="yes"
target_nptl="yes"
target_libs_softmmu="$fdt_libs"
;;
mips|mipsel)
TARGET_ARCH=mips
@ -3834,9 +4051,10 @@ case "$target_arch2" in
target_nptl="yes"
;;
mipsn32|mipsn32el)
TARGET_ARCH=mipsn32
TARGET_ARCH=mips64
TARGET_BASE_ARCH=mips
echo "TARGET_ABI_MIPSN32=y" >> $config_target_mak
echo "TARGET_ABI32=y" >> $config_target_mak
;;
mips64|mips64el)
TARGET_ARCH=mips64
@ -3851,21 +4069,18 @@ case "$target_arch2" in
ppc)
gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
target_nptl="yes"
target_libs_softmmu="$fdt_libs"
;;
ppcemb)
TARGET_BASE_ARCH=ppc
TARGET_ABI_DIR=ppc
gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
target_nptl="yes"
target_libs_softmmu="$fdt_libs"
;;
ppc64)
TARGET_BASE_ARCH=ppc
TARGET_ABI_DIR=ppc
gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
target_long_alignment=8
target_libs_softmmu="$fdt_libs"
;;
ppc64abi32)
TARGET_ARCH=ppc64
@ -3873,7 +4088,6 @@ case "$target_arch2" in
TARGET_ABI_DIR=ppc
echo "TARGET_ABI32=y" >> $config_target_mak
gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
target_libs_softmmu="$fdt_libs"
;;
sh4|sh4eb)
TARGET_ARCH=sh4
@ -3955,7 +4169,7 @@ case "$target_arch2" in
echo "CONFIG_NO_XEN=y" >> $config_target_mak
esac
case "$target_arch2" in
i386|x86_64|ppcemb|ppc|ppc64|s390x)
arm|i386|x86_64|ppcemb|ppc|ppc64|s390x)
# Make sure the target and host cpus are compatible
if test "$kvm" = "yes" -a "$target_softmmu" = "yes" -a \
\( "$target_arch2" = "$cpu" -o \
@ -3975,18 +4189,12 @@ case "$target_arch2" in
i386|x86_64)
echo "CONFIG_HAVE_GET_MEMORY_MAPPING=y" >> $config_target_mak
esac
if test "$target_arch2" = "ppc64" -a "$fdt" = "yes"; then
echo "CONFIG_PSERIES=y" >> $config_target_mak
fi
if test "$target_bigendian" = "yes" ; then
echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak
fi
if test "$target_softmmu" = "yes" ; then
echo "CONFIG_SOFTMMU=y" >> $config_target_mak
echo "LIBS+=$libs_softmmu $target_libs_softmmu" >> $config_target_mak
if test "$smartcard_nss" = "yes" ; then
echo "subdir-$target: subdir-libcacard" >> $config_host_mak
fi
case "$target_arch2" in
i386|x86_64)
echo "CONFIG_HAVE_CORE_DUMP=y" >> $config_target_mak
@ -4155,6 +4363,12 @@ if test "$gprof" = "yes" ; then
fi
fi
if test "$tpm" = "yes"; then
if test "$target_softmmu" = "yes" ; then
echo "CONFIG_TPM=y" >> $config_host_mak
fi
fi
if test "$ARCH" = "tci"; then
linker_script=""
else
@ -4187,15 +4401,16 @@ DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32"
DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas"
DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS qapi-generated"
DIRS="$DIRS libcacard libcacard/libcacard libcacard/trace"
FILES="Makefile tests/tcg/Makefile qdict-test-data.txt"
FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
FILES="$FILES tests/tcg/lm32/Makefile libcacard/Makefile"
FILES="$FILES tests/tcg/lm32/Makefile po/Makefile"
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
FILES="$FILES pc-bios/spapr-rtas/Makefile"
FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile"
FILES="$FILES pc-bios/qemu-icon.bmp"
for bios_file in \
$source_path/pc-bios/*.bin \
$source_path/pc-bios/*.aml \
$source_path/pc-bios/*.rom \
$source_path/pc-bios/*.dtb \
$source_path/pc-bios/openbios-* \
@ -4215,9 +4430,10 @@ for rom in seabios vgabios ; do
config_mak=roms/$rom/config.mak
echo "# Automatically generated by configure - do not modify" > $config_mak
echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak
echo "AS=$as" >> $config_mak
echo "CC=$cc" >> $config_mak
echo "BCC=bcc" >> $config_mak
echo "CPP=${cross_prefix}cpp" >> $config_mak
echo "CPP=$cpp" >> $config_mak
echo "OBJCOPY=objcopy" >> $config_mak
echo "IASL=iasl" >> $config_mak
echo "LD=$ld" >> $config_mak

View File

@ -33,19 +33,10 @@
#include "qemu-common.h"
#include "block/coroutine_int.h"
enum {
/* Maximum free pool size prevents holding too many freed coroutines */
POOL_MAX_SIZE = 64,
};
/** Free list to speed up creation */
static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool);
static unsigned int pool_size;
typedef struct {
Coroutine base;
void *stack;
jmp_buf env;
sigjmp_buf env;
} CoroutineUContext;
/**
@ -59,7 +50,7 @@ typedef struct {
CoroutineUContext leader;
/** Information for the signal handler (trampoline) */
jmp_buf tr_reenter;
sigjmp_buf tr_reenter;
volatile sig_atomic_t tr_called;
void *tr_handler;
} CoroutineThreadState;
@ -85,17 +76,6 @@ static void qemu_coroutine_thread_cleanup(void *opaque)
g_free(s);
}
static void __attribute__((destructor)) coroutine_cleanup(void)
{
Coroutine *co;
Coroutine *tmp;
QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
g_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
g_free(co);
}
}
static void __attribute__((constructor)) coroutine_init(void)
{
int ret;
@ -115,8 +95,8 @@ static void __attribute__((constructor)) coroutine_init(void)
static void coroutine_bootstrap(CoroutineUContext *self, Coroutine *co)
{
/* Initialize longjmp environment and switch back the caller */
if (!setjmp(self->env)) {
longjmp(*(jmp_buf *)co->entry_arg, 1);
if (!sigsetjmp(self->env, 0)) {
siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
}
while (true) {
@ -145,14 +125,14 @@ static void coroutine_trampoline(int signal)
/*
* Here we have to do a bit of a ping pong between the caller, given that
* this is a signal handler and we have to do a return "soon". Then the
* caller can reestablish everything and do a longjmp here again.
* caller can reestablish everything and do a siglongjmp here again.
*/
if (!setjmp(coTS->tr_reenter)) {
if (!sigsetjmp(coTS->tr_reenter, 0)) {
return;
}
/*
* Ok, the caller has longjmp'ed back to us, so now prepare
* Ok, the caller has siglongjmp'ed back to us, so now prepare
* us for the real machine state switching. We have to jump
* into another function here to get a new stack context for
* the auto variables (which have to be auto-variables
@ -164,7 +144,7 @@ static void coroutine_trampoline(int signal)
coroutine_bootstrap(self, co);
}
static Coroutine *coroutine_new(void)
Coroutine *qemu_coroutine_new(void)
{
const size_t stack_size = 1 << 20;
CoroutineUContext *co;
@ -179,7 +159,7 @@ static Coroutine *coroutine_new(void)
/* The way to manipulate stack is with the sigaltstack function. We
* prepare a stack, with it delivering a signal to ourselves and then
* put setjmp/longjmp where needed.
* put sigsetjmp/siglongjmp where needed.
* This has been done keeping coroutine-ucontext as a model and with the
* pth ideas (GNU Portable Threads). See coroutine-ucontext for the basics
* of the coroutines and see pth_mctx.c (from the pth project) for the
@ -220,7 +200,7 @@ static Coroutine *coroutine_new(void)
/*
* Now transfer control onto the signal stack and set it up.
* It will return immediately via "return" after the setjmp()
* It will return immediately via "return" after the sigsetjmp()
* was performed. Be careful here with race conditions. The
* signal can be delivered the first time sigsuspend() is
* called.
@ -261,8 +241,8 @@ static Coroutine *coroutine_new(void)
* type-conversion warnings related to the `volatile' qualifier and
* the fact that `jmp_buf' usually is an array type.
*/
if (!setjmp(old_env)) {
longjmp(coTS->tr_reenter, 1);
if (!sigsetjmp(old_env, 0)) {
siglongjmp(coTS->tr_reenter, 1);
}
/*
@ -272,31 +252,10 @@ static Coroutine *coroutine_new(void)
return &co->base;
}
Coroutine *qemu_coroutine_new(void)
{
Coroutine *co;
co = QSLIST_FIRST(&pool);
if (co) {
QSLIST_REMOVE_HEAD(&pool, pool_next);
pool_size--;
} else {
co = coroutine_new();
}
return co;
}
void qemu_coroutine_delete(Coroutine *co_)
{
CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
if (pool_size < POOL_MAX_SIZE) {
QSLIST_INSERT_HEAD(&pool, &co->base, pool_next);
co->base.caller = NULL;
pool_size++;
return;
}
g_free(co->stack);
g_free(co);
}
@ -311,9 +270,9 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
s->current = to_;
ret = setjmp(from->env);
ret = sigsetjmp(from->env, 0);
if (ret == 0) {
longjmp(to->env, action);
siglongjmp(to->env, action);
}
return ret;
}

View File

@ -34,19 +34,10 @@
#include <valgrind/valgrind.h>
#endif
enum {
/* Maximum free pool size prevents holding too many freed coroutines */
POOL_MAX_SIZE = 64,
};
/** Free list to speed up creation */
static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool);
static unsigned int pool_size;
typedef struct {
Coroutine base;
void *stack;
jmp_buf env;
sigjmp_buf env;
#ifdef CONFIG_VALGRIND_H
unsigned int valgrind_stack_id;
@ -96,17 +87,6 @@ static void qemu_coroutine_thread_cleanup(void *opaque)
g_free(s);
}
static void __attribute__((destructor)) coroutine_cleanup(void)
{
Coroutine *co;
Coroutine *tmp;
QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
g_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
g_free(co);
}
}
static void __attribute__((constructor)) coroutine_init(void)
{
int ret;
@ -130,8 +110,8 @@ static void coroutine_trampoline(int i0, int i1)
co = &self->base;
/* Initialize longjmp environment and switch back the caller */
if (!setjmp(self->env)) {
longjmp(*(jmp_buf *)co->entry_arg, 1);
if (!sigsetjmp(self->env, 0)) {
siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
}
while (true) {
@ -140,19 +120,20 @@ static void coroutine_trampoline(int i0, int i1)
}
}
static Coroutine *coroutine_new(void)
Coroutine *qemu_coroutine_new(void)
{
const size_t stack_size = 1 << 20;
CoroutineUContext *co;
ucontext_t old_uc, uc;
jmp_buf old_env;
sigjmp_buf old_env;
union cc_arg arg = {0};
/* The ucontext functions preserve signal masks which incurs a system call
* overhead. setjmp()/longjmp() does not preserve signal masks but only
* works on the current stack. Since we need a way to create and switch to
* a new stack, use the ucontext functions for that but setjmp()/longjmp()
* for everything else.
/* The ucontext functions preserve signal masks which incurs a
* system call overhead. sigsetjmp(buf, 0)/siglongjmp() does not
* preserve signal masks but only works on the current stack.
* Since we need a way to create and switch to a new stack, use
* the ucontext functions for that but sigsetjmp()/siglongjmp() for
* everything else.
*/
if (getcontext(&uc) == -1) {
@ -178,29 +159,15 @@ static Coroutine *coroutine_new(void)
makecontext(&uc, (void (*)(void))coroutine_trampoline,
2, arg.i[0], arg.i[1]);
/* swapcontext() in, longjmp() back out */
if (!setjmp(old_env)) {
/* swapcontext() in, siglongjmp() back out */
if (!sigsetjmp(old_env, 0)) {
swapcontext(&old_uc, &uc);
}
return &co->base;
}
Coroutine *qemu_coroutine_new(void)
{
Coroutine *co;
co = QSLIST_FIRST(&pool);
if (co) {
QSLIST_REMOVE_HEAD(&pool, pool_next);
pool_size--;
} else {
co = coroutine_new();
}
return co;
}
#ifdef CONFIG_VALGRIND_H
#ifdef CONFIG_PRAGMA_DISABLE_UNUSED_BUT_SET
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
/* Work around an unused variable in the valgrind.h macro... */
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif
@ -208,7 +175,7 @@ static inline void valgrind_stack_deregister(CoroutineUContext *co)
{
VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id);
}
#ifdef CONFIG_PRAGMA_DISABLE_UNUSED_BUT_SET
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
#pragma GCC diagnostic error "-Wunused-but-set-variable"
#endif
#endif
@ -217,13 +184,6 @@ void qemu_coroutine_delete(Coroutine *co_)
{
CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
if (pool_size < POOL_MAX_SIZE) {
QSLIST_INSERT_HEAD(&pool, &co->base, pool_next);
co->base.caller = NULL;
pool_size++;
return;
}
#ifdef CONFIG_VALGRIND_H
valgrind_stack_deregister(co);
#endif
@ -242,9 +202,9 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
s->current = to_;
ret = setjmp(from->env);
ret = sigsetjmp(from->env, 0);
if (ret == 0) {
longjmp(to->env, action);
siglongjmp(to->env, action);
}
return ret;
}

View File

@ -23,8 +23,6 @@
#include "qemu/atomic.h"
#include "sysemu/qtest.h"
int tb_invalidated_flag;
//#define CONFIG_DEBUG_EXEC
bool qemu_cpu_has_work(CPUState *cpu)
@ -34,8 +32,10 @@ bool qemu_cpu_has_work(CPUState *cpu)
void cpu_loop_exit(CPUArchState *env)
{
env->current_tb = NULL;
longjmp(env->jmp_env, 1);
CPUState *cpu = ENV_GET_CPU(env);
cpu->current_tb = NULL;
siglongjmp(env->jmp_env, 1);
}
/* exit the current TB from a signal handler. The host registers are
@ -47,16 +47,38 @@ void cpu_resume_from_signal(CPUArchState *env, void *puc)
/* XXX: restore cpu registers saved in host registers */
env->exception_index = -1;
longjmp(env->jmp_env, 1);
siglongjmp(env->jmp_env, 1);
}
#endif
/* Execute a TB, and fix up the CPU state afterwards if necessary */
static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
{
CPUArchState *env = cpu->env_ptr;
tcg_target_ulong next_tb = tcg_qemu_tb_exec(env, tb_ptr);
if ((next_tb & TB_EXIT_MASK) > TB_EXIT_IDX1) {
/* We didn't start executing this TB (eg because the instruction
* counter hit zero); we must restore the guest PC to the address
* of the start of the TB.
*/
TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
cpu_pc_from_tb(env, tb);
}
if ((next_tb & TB_EXIT_MASK) == TB_EXIT_REQUESTED) {
/* We were asked to stop executing TBs (probably a pending
* interrupt. We've now stopped, so clear the flag.
*/
cpu->tcg_exit_req = 0;
}
return next_tb;
}
/* Execute the code without caching the generated code. An interpreter
could be used if available. */
static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
TranslationBlock *orig_tb)
{
tcg_target_ulong next_tb;
CPUState *cpu = ENV_GET_CPU(env);
TranslationBlock *tb;
/* Should never happen.
@ -66,16 +88,10 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
max_cycles);
env->current_tb = tb;
cpu->current_tb = tb;
/* execute the generated code */
next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr);
env->current_tb = NULL;
if ((next_tb & 3) == 2) {
/* Restore PC. This may happen if async event occurs before
the TB starts executing. */
cpu_pc_from_tb(env, tb);
}
cpu_tb_exec(cpu, tb->tc_ptr);
cpu->current_tb = NULL;
tb_phys_invalidate(tb, -1);
tb_free(tb);
}
@ -90,13 +106,13 @@ static TranslationBlock *tb_find_slow(CPUArchState *env,
tb_page_addr_t phys_pc, phys_page1;
target_ulong virt_page2;
tb_invalidated_flag = 0;
tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
/* find translated block using physical mappings */
phys_pc = get_page_addr_code(env, pc);
phys_page1 = phys_pc & TARGET_PAGE_MASK;
h = tb_phys_hash_func(phys_pc);
ptb1 = &tb_phys_hash[h];
ptb1 = &tcg_ctx.tb_ctx.tb_phys_hash[h];
for(;;) {
tb = *ptb1;
if (!tb)
@ -128,8 +144,8 @@ static TranslationBlock *tb_find_slow(CPUArchState *env,
/* Move the last found TB to the head of the list */
if (likely(*ptb1)) {
*ptb1 = tb->phys_hash_next;
tb->phys_hash_next = tb_phys_hash[h];
tb_phys_hash[h] = tb;
tb->phys_hash_next = tcg_ctx.tb_ctx.tb_phys_hash[h];
tcg_ctx.tb_ctx.tb_phys_hash[h] = tb;
}
/* we add the TB in the virtual pc hash table */
env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
@ -182,23 +198,27 @@ volatile sig_atomic_t exit_request;
int cpu_exec(CPUArchState *env)
{
CPUState *cpu = ENV_GET_CPU(env);
#if !(defined(CONFIG_USER_ONLY) && \
(defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X)))
CPUClass *cc = CPU_GET_CLASS(cpu);
#endif
int ret, interrupt_request;
TranslationBlock *tb;
uint8_t *tc_ptr;
tcg_target_ulong next_tb;
if (env->halted) {
if (cpu->halted) {
if (!cpu_has_work(cpu)) {
return EXCP_HALTED;
}
env->halted = 0;
cpu->halted = 0;
}
cpu_single_env = env;
if (unlikely(exit_request)) {
env->exit_request = 1;
cpu->exit_request = 1;
}
#if defined(TARGET_I386)
@ -233,7 +253,7 @@ int cpu_exec(CPUArchState *env)
/* prepare setjmp context for exception handling */
for(;;) {
if (setjmp(env->jmp_env) == 0) {
if (sigsetjmp(env->jmp_env, 0) == 0) {
/* if an exception is pending, we execute it here */
if (env->exception_index >= 0) {
if (env->exception_index >= EXCP_INTERRUPT) {
@ -249,12 +269,12 @@ int cpu_exec(CPUArchState *env)
which will be handled outside the cpu execution
loop */
#if defined(TARGET_I386)
do_interrupt(env);
cc->do_interrupt(cpu);
#endif
ret = env->exception_index;
break;
#else
do_interrupt(env);
cc->do_interrupt(cpu);
env->exception_index = -1;
#endif
}
@ -262,14 +282,14 @@ int cpu_exec(CPUArchState *env)
next_tb = 0; /* force lookup of first TB */
for(;;) {
interrupt_request = env->interrupt_request;
interrupt_request = cpu->interrupt_request;
if (unlikely(interrupt_request)) {
if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
/* Mask out external interrupts for this step. */
interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
}
if (interrupt_request & CPU_INTERRUPT_DEBUG) {
env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
cpu->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
env->exception_index = EXCP_DEBUG;
cpu_loop_exit(env);
}
@ -277,8 +297,8 @@ int cpu_exec(CPUArchState *env)
defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
if (interrupt_request & CPU_INTERRUPT_HALT) {
env->interrupt_request &= ~CPU_INTERRUPT_HALT;
env->halted = 1;
cpu->interrupt_request &= ~CPU_INTERRUPT_HALT;
cpu->halted = 1;
env->exception_index = EXCP_HLT;
cpu_loop_exit(env);
}
@ -286,7 +306,7 @@ int cpu_exec(CPUArchState *env)
#if defined(TARGET_I386)
#if !defined(CONFIG_USER_ONLY)
if (interrupt_request & CPU_INTERRUPT_POLL) {
env->interrupt_request &= ~CPU_INTERRUPT_POLL;
cpu->interrupt_request &= ~CPU_INTERRUPT_POLL;
apic_poll_irq(env->apic_state);
}
#endif
@ -303,17 +323,17 @@ int cpu_exec(CPUArchState *env)
!(env->hflags & HF_SMM_MASK)) {
cpu_svm_check_intercept_param(env, SVM_EXIT_SMI,
0);
env->interrupt_request &= ~CPU_INTERRUPT_SMI;
cpu->interrupt_request &= ~CPU_INTERRUPT_SMI;
do_smm_enter(env);
next_tb = 0;
} else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
!(env->hflags2 & HF2_NMI_MASK)) {
env->interrupt_request &= ~CPU_INTERRUPT_NMI;
cpu->interrupt_request &= ~CPU_INTERRUPT_NMI;
env->hflags2 |= HF2_NMI_MASK;
do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
next_tb = 0;
} else if (interrupt_request & CPU_INTERRUPT_MCE) {
env->interrupt_request &= ~CPU_INTERRUPT_MCE;
cpu->interrupt_request &= ~CPU_INTERRUPT_MCE;
do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
next_tb = 0;
} else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
@ -325,7 +345,8 @@ int cpu_exec(CPUArchState *env)
int intno;
cpu_svm_check_intercept_param(env, SVM_EXIT_INTR,
0);
env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
cpu->interrupt_request &= ~(CPU_INTERRUPT_HARD |
CPU_INTERRUPT_VIRQ);
intno = cpu_get_pic_interrupt(env);
qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
do_interrupt_x86_hardirq(env, intno, 1);
@ -343,7 +364,7 @@ int cpu_exec(CPUArchState *env)
intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
do_interrupt_x86_hardirq(env, intno, 1);
env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
cpu->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
next_tb = 0;
#endif
}
@ -354,15 +375,16 @@ int cpu_exec(CPUArchState *env)
}
if (interrupt_request & CPU_INTERRUPT_HARD) {
ppc_hw_interrupt(env);
if (env->pending_interrupts == 0)
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
if (env->pending_interrupts == 0) {
cpu->interrupt_request &= ~CPU_INTERRUPT_HARD;
}
next_tb = 0;
}
#elif defined(TARGET_LM32)
if ((interrupt_request & CPU_INTERRUPT_HARD)
&& (env->ie & IE_IE)) {
env->exception_index = EXCP_IRQ;
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
#elif defined(TARGET_MICROBLAZE)
@ -371,7 +393,7 @@ int cpu_exec(CPUArchState *env)
&& !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
&& !(env->iflags & (D_FLAG | IMM_FLAG))) {
env->exception_index = EXCP_IRQ;
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
#elif defined(TARGET_MIPS)
@ -380,7 +402,7 @@ int cpu_exec(CPUArchState *env)
/* Raise it */
env->exception_index = EXCP_EXT_INTERRUPT;
env->error_code = 0;
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
#elif defined(TARGET_OPENRISC)
@ -396,7 +418,7 @@ int cpu_exec(CPUArchState *env)
}
if (idx >= 0) {
env->exception_index = idx;
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
}
@ -411,7 +433,7 @@ int cpu_exec(CPUArchState *env)
cpu_pil_allowed(env, pil)) ||
type != TT_EXTINT) {
env->exception_index = env->interrupt_index;
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
}
@ -420,7 +442,7 @@ int cpu_exec(CPUArchState *env)
if (interrupt_request & CPU_INTERRUPT_FIQ
&& !(env->uncached_cpsr & CPSR_F)) {
env->exception_index = EXCP_FIQ;
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
/* ARMv7-M interrupt return works by loading a magic value
@ -436,19 +458,19 @@ int cpu_exec(CPUArchState *env)
&& ((IS_M(env) && env->regs[15] < 0xfffffff0)
|| !(env->uncached_cpsr & CPSR_I))) {
env->exception_index = EXCP_IRQ;
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
#elif defined(TARGET_UNICORE32)
if (interrupt_request & CPU_INTERRUPT_HARD
&& !(env->uncached_asr & ASR_I)) {
env->exception_index = UC32_EXCP_INTR;
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
#elif defined(TARGET_SH4)
if (interrupt_request & CPU_INTERRUPT_HARD) {
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
#elif defined(TARGET_ALPHA)
@ -479,7 +501,7 @@ int cpu_exec(CPUArchState *env)
if (idx >= 0) {
env->exception_index = idx;
env->error_code = 0;
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
}
@ -488,7 +510,7 @@ int cpu_exec(CPUArchState *env)
&& (env->pregs[PR_CCS] & I_FLAG)
&& !env->locked_irq) {
env->exception_index = EXCP_IRQ;
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
if (interrupt_request & CPU_INTERRUPT_NMI) {
@ -500,7 +522,7 @@ int cpu_exec(CPUArchState *env)
}
if ((env->pregs[PR_CCS] & m_flag_archval)) {
env->exception_index = EXCP_NMI;
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
}
@ -520,27 +542,27 @@ int cpu_exec(CPUArchState *env)
#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->psw.mask & PSW_MASK_EXT)) {
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
#elif defined(TARGET_XTENSA)
if (interrupt_request & CPU_INTERRUPT_HARD) {
env->exception_index = EXC_IRQ;
do_interrupt(env);
cc->do_interrupt(cpu);
next_tb = 0;
}
#endif
/* Don't use the cached interrupt_request value,
do_interrupt may have updated the EXITTB flag. */
if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
if (cpu->interrupt_request & CPU_INTERRUPT_EXITTB) {
cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
/* ensure that no TB jump will be modified as
the program flow was changed */
next_tb = 0;
}
}
if (unlikely(env->exit_request)) {
env->exit_request = 0;
if (unlikely(cpu->exit_request)) {
cpu->exit_request = 0;
env->exception_index = EXCP_INTERRUPT;
cpu_loop_exit(env);
}
@ -563,16 +585,16 @@ int cpu_exec(CPUArchState *env)
#endif
}
#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
spin_lock(&tb_lock);
spin_lock(&tcg_ctx.tb_ctx.tb_lock);
tb = tb_find_fast(env);
/* Note: we do it here to avoid a gcc bug on Mac OS X when
doing it in tb_find_slow */
if (tb_invalidated_flag) {
if (tcg_ctx.tb_ctx.tb_invalidated_flag) {
/* as some TB could have been invalidated because
of memory exceptions while generating the code, we
must recompute the hash index here */
next_tb = 0;
tb_invalidated_flag = 0;
tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
}
#ifdef CONFIG_DEBUG_EXEC
qemu_log_mask(CPU_LOG_EXEC, "Trace %p [" TARGET_FMT_lx "] %s\n",
@ -583,26 +605,38 @@ int cpu_exec(CPUArchState *env)
spans two pages, we cannot safely do a direct
jump. */
if (next_tb != 0 && tb->page_addr[1] == -1) {
tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK),
next_tb & TB_EXIT_MASK, tb);
}
spin_unlock(&tb_lock);
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
/* cpu_interrupt might be called while translating the
TB, but before it is linked into a potentially
infinite loop and becomes env->current_tb. Avoid
starting execution if there is a pending interrupt. */
env->current_tb = tb;
cpu->current_tb = tb;
barrier();
if (likely(!env->exit_request)) {
if (likely(!cpu->exit_request)) {
tc_ptr = tb->tc_ptr;
/* execute the generated code */
next_tb = tcg_qemu_tb_exec(env, tc_ptr);
if ((next_tb & 3) == 2) {
next_tb = cpu_tb_exec(cpu, tc_ptr);
switch (next_tb & TB_EXIT_MASK) {
case TB_EXIT_REQUESTED:
/* Something asked us to stop executing
* chained TBs; just continue round the main
* loop. Whatever requested the exit will also
* have set something else (eg exit_request or
* interrupt_request) which we will handle
* next time around the loop.
*/
tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
next_tb = 0;
break;
case TB_EXIT_ICOUNT_EXPIRED:
{
/* Instruction counter expired. */
int insns_left;
tb = (TranslationBlock *)(next_tb & ~3);
/* Restore PC. */
cpu_pc_from_tb(env, tb);
tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
insns_left = env->icount_decr.u32;
if (env->icount_extra && insns_left >= 0) {
/* Refill decrementer and continue execution. */
@ -623,9 +657,13 @@ int cpu_exec(CPUArchState *env)
next_tb = 0;
cpu_loop_exit(env);
}
break;
}
default:
break;
}
}
env->current_tb = NULL;
cpu->current_tb = NULL;
/* reset soft MMU for next block (it can currently
only be set by a memory fault) */
} /* for(;;) */

66
cpus.c
View File

@ -72,7 +72,7 @@ static bool cpu_thread_is_idle(CPUArchState *env)
if (cpu->stopped || !runstate_is_running()) {
return true;
}
if (!env->halted || qemu_cpu_has_work(cpu) ||
if (!cpu->halted || qemu_cpu_has_work(cpu) ||
kvm_async_interrupts_enabled()) {
return false;
}
@ -390,13 +390,15 @@ void hw_error(const char *fmt, ...)
{
va_list ap;
CPUArchState *env;
CPUState *cpu;
va_start(ap, fmt);
fprintf(stderr, "qemu: hardware error: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
for(env = first_cpu; env != NULL; env = env->next_cpu) {
fprintf(stderr, "CPU #%d:\n", env->cpu_index);
for (env = first_cpu; env != NULL; env = env->next_cpu) {
cpu = ENV_GET_CPU(env);
fprintf(stderr, "CPU #%d:\n", cpu->cpu_index);
cpu_dump_state(env, stderr, fprintf, CPU_DUMP_FPU);
}
va_end(ap);
@ -515,7 +517,7 @@ static void qemu_init_sigbus(void)
prctl(PR_MCE_KILL, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY, 0, 0);
}
static void qemu_kvm_eat_signals(CPUArchState *env)
static void qemu_kvm_eat_signals(CPUState *cpu)
{
struct timespec ts = { 0, 0 };
siginfo_t siginfo;
@ -536,7 +538,7 @@ static void qemu_kvm_eat_signals(CPUArchState *env)
switch (r) {
case SIGBUS:
if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) {
if (kvm_on_sigbus_vcpu(cpu, siginfo.si_code, siginfo.si_addr)) {
sigbus_reraise();
}
break;
@ -558,7 +560,7 @@ static void qemu_init_sigbus(void)
{
}
static void qemu_kvm_eat_signals(CPUArchState *env)
static void qemu_kvm_eat_signals(CPUState *cpu)
{
}
#endif /* !CONFIG_LINUX */
@ -725,7 +727,7 @@ static void qemu_kvm_wait_io_event(CPUArchState *env)
qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
}
qemu_kvm_eat_signals(env);
qemu_kvm_eat_signals(cpu);
qemu_wait_io_event_common(cpu);
}
@ -740,7 +742,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
cpu->thread_id = qemu_get_thread_id();
cpu_single_env = env;
r = kvm_init_vcpu(env);
r = kvm_init_vcpu(cpu);
if (r < 0) {
fprintf(stderr, "kvm_init_vcpu failed: %s\n", strerror(-r));
exit(1);
@ -1041,8 +1043,8 @@ void qemu_init_vcpu(void *_env)
CPUArchState *env = _env;
CPUState *cpu = ENV_GET_CPU(env);
env->nr_cores = smp_cores;
env->nr_threads = smp_threads;
cpu->nr_cores = smp_cores;
cpu->nr_threads = smp_threads;
cpu->stopped = true;
if (kvm_enabled()) {
qemu_kvm_start_vcpu(env);
@ -1160,38 +1162,19 @@ static void tcg_exec_all(void)
void set_numa_modes(void)
{
CPUArchState *env;
CPUState *cpu;
int i;
for (env = first_cpu; env != NULL; env = env->next_cpu) {
cpu = ENV_GET_CPU(env);
for (i = 0; i < nb_numa_nodes; i++) {
if (test_bit(env->cpu_index, node_cpumask[i])) {
env->numa_node = i;
if (test_bit(cpu->cpu_index, node_cpumask[i])) {
cpu->numa_node = i;
}
}
}
}
void set_cpu_log(const char *optarg)
{
int mask;
const CPULogItem *item;
mask = cpu_str_to_log_mask(optarg);
if (!mask) {
printf("Log items (comma separated):\n");
for (item = cpu_log_items; item->mask != 0; item++) {
printf("%-10s %s\n", item->name, item->help);
}
exit(1);
}
cpu_set_log(mask);
}
void set_cpu_log_filename(const char *optarg)
{
cpu_set_log_filename(optarg);
}
void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
{
/* XXX: implement xxx_cpu_list for targets that still miss it */
@ -1213,9 +1196,9 @@ CpuInfoList *qmp_query_cpus(Error **errp)
info = g_malloc0(sizeof(*info));
info->value = g_malloc0(sizeof(*info->value));
info->value->CPU = env->cpu_index;
info->value->CPU = cpu->cpu_index;
info->value->current = (env == first_cpu);
info->value->halted = env->halted;
info->value->halted = cpu->halted;
info->value->thread_id = cpu->thread_id;
#if defined(TARGET_I386)
info->value->has_pc = true;
@ -1251,23 +1234,20 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename,
FILE *f;
uint32_t l;
CPUArchState *env;
CPUState *cpu;
uint8_t buf[1024];
if (!has_cpu) {
cpu_index = 0;
}
for (env = first_cpu; env; env = env->next_cpu) {
if (cpu_index == env->cpu_index) {
break;
}
}
if (env == NULL) {
cpu = qemu_get_cpu(cpu_index);
if (cpu == NULL) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
"a CPU number");
return;
}
env = cpu->env_ptr;
f = fopen(filename, "wb");
if (!f) {
@ -1329,7 +1309,7 @@ void qmp_inject_nmi(Error **errp)
for (env = first_cpu; env != NULL; env = env->next_cpu) {
if (!env->apic_state) {
cpu_interrupt(env, CPU_INTERRUPT_NMI);
cpu_interrupt(CPU(x86_env_get_cpu(env)), CPU_INTERRUPT_NMI);
} else {
apic_deliver_nmi(env->apic_state);
}

View File

@ -54,6 +54,7 @@ static const CPUTLBEntry s_cputlb_empty_entry = {
*/
void tlb_flush(CPUArchState *env, int flush_global)
{
CPUState *cpu = ENV_GET_CPU(env);
int i;
#if defined(DEBUG_TLB)
@ -61,7 +62,7 @@ void tlb_flush(CPUArchState *env, int flush_global)
#endif
/* must reset current TB so that interrupts cannot modify the
links while we are modifying them */
env->current_tb = NULL;
cpu->current_tb = NULL;
for (i = 0; i < CPU_TLB_SIZE; i++) {
int mmu_idx;
@ -92,6 +93,7 @@ static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
void tlb_flush_page(CPUArchState *env, target_ulong addr)
{
CPUState *cpu = ENV_GET_CPU(env);
int i;
int mmu_idx;
@ -110,7 +112,7 @@ void tlb_flush_page(CPUArchState *env, target_ulong addr)
}
/* must reset current TB so that interrupts cannot modify the
links while we are modifying them */
env->current_tb = NULL;
cpu->current_tb = NULL;
addr &= TARGET_PAGE_MASK;
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);

View File

@ -1,6 +1,7 @@
# Default configuration for alpha-softmmu
include pci.mak
include usb.mak
CONFIG_SERIAL=y
CONFIG_I8254=y
CONFIG_PCKBD=y

View File

@ -1,6 +1,7 @@
# Default configuration for arm-softmmu
include pci.mak
include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_VGA=y
CONFIG_ISA_MMIO=y
@ -46,3 +47,5 @@ CONFIG_XGMAC=y
CONFIG_VERSATILE_PCI=y
CONFIG_VERSATILE_I2C=y
CONFIG_SDHCI=y

View File

@ -1,6 +1,7 @@
# Default configuration for i386-softmmu
include pci.mak
include usb.mak
CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
@ -25,3 +26,5 @@ CONFIG_HPET=y
CONFIG_APPLESMC=y
CONFIG_I8259=y
CONFIG_PFLASH_CFI01=y
CONFIG_TPM_TIS=y
CONFIG_TPM_PASSTHROUGH=y

View File

@ -1,5 +1,6 @@
# Default configuration for m68k-softmmu
include pci.mak
include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_PTIMER=y

View File

@ -1,6 +1,7 @@
# Default configuration for mips-softmmu
include pci.mak
include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y

View File

@ -1,6 +1,7 @@
# Default configuration for mips64-softmmu
include pci.mak
include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y

View File

@ -1,6 +1,7 @@
# Default configuration for mips64el-softmmu
include pci.mak
include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y

View File

@ -1,6 +1,7 @@
# Default configuration for mipsel-softmmu
include pci.mak
include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y

View File

@ -21,3 +21,4 @@ CONFIG_ESP=y
CONFIG_ESP_PCI=y
CONFIG_SERIAL=y
CONFIG_SERIAL_PCI=y
CONFIG_IPACK=y

View File

@ -1,6 +1,7 @@
# Default configuration for ppc-softmmu
include pci.mak
include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
@ -8,6 +9,7 @@ CONFIG_M48T59=y
CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
CONFIG_I8254=y
CONFIG_PCKBD=y
CONFIG_FDC=y
@ -16,6 +18,7 @@ CONFIG_I82374=y
CONFIG_OPENPIC=y
CONFIG_PREP_PCI=y
CONFIG_I82378=y
CONFIG_PC87312=y
CONFIG_MACIO=y
CONFIG_PCSPK=y
CONFIG_CUDA=y
@ -37,3 +40,4 @@ CONFIG_PFLASH_CFI02=y
CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
CONFIG_E500=$(CONFIG_FDT)

View File

@ -1,6 +1,7 @@
# Default configuration for ppc64-softmmu
include pci.mak
include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
@ -8,13 +9,18 @@ CONFIG_M48T59=y
CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
CONFIG_I8254=y
CONFIG_PCKBD=y
CONFIG_FDC=y
CONFIG_DMA=y
CONFIG_I82374=y
CONFIG_OPENPIC=y
CONFIG_PREP_PCI=y
CONFIG_I82378=y
CONFIG_PC87312=y
CONFIG_MACIO=y
CONFIG_PCSPK=y
CONFIG_CUDA=y
CONFIG_ADB=y
CONFIG_MAC_NVRAM=y
@ -34,3 +40,5 @@ CONFIG_PFLASH_CFI02=y
CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
CONFIG_PSERIES=$(CONFIG_FDT)
CONFIG_E500=$(CONFIG_FDT)

View File

@ -1,6 +1,7 @@
# Default configuration for ppcemb-softmmu
include pci.mak
include usb.mak
CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
@ -34,3 +35,4 @@ CONFIG_PFLASH_CFI02=y
CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
CONFIG_E500=$(CONFIG_FDT)

View File

@ -1,6 +1,7 @@
# Default configuration for sh4-softmmu
include pci.mak
include usb.mak
CONFIG_SERIAL=y
CONFIG_PTIMER=y
CONFIG_PFLASH_CFI02=y

View File

@ -1,6 +1,7 @@
# Default configuration for sh4eb-softmmu
include pci.mak
include usb.mak
CONFIG_SERIAL=y
CONFIG_PTIMER=y
CONFIG_PFLASH_CFI02=y

View File

@ -1,6 +1,7 @@
# Default configuration for sparc64-softmmu
include pci.mak
include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_M48T59=y
CONFIG_PTIMER=y

8
default-configs/usb.mak Normal file
View File

@ -0,0 +1,8 @@
CONFIG_USB_TABLET_WACOM=y
CONFIG_USB_STORAGE_BOT=y
CONFIG_USB_STORAGE_UAS=y
CONFIG_USB_SMARTCARD=y
CONFIG_USB_AUDIO=y
CONFIG_USB_SERIAL=y
CONFIG_USB_NETWORK=y
CONFIG_USB_BLUETOOTH=y

View File

@ -1,6 +1,7 @@
# Default configuration for x86_64-softmmu
include pci.mak
include usb.mak
CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
@ -25,3 +26,5 @@ CONFIG_HPET=y
CONFIG_APPLESMC=y
CONFIG_I8259=y
CONFIG_PFLASH_CFI01=y
CONFIG_TPM_TIS=y
CONFIG_TPM_PASSTHROUGH=y

View File

@ -22,8 +22,8 @@
* THE SOFTWARE.
*/
#include "hw.h"
#include "boards.h"
#include "hw/hw.h"
#include "hw/boards.h"
#include "sysemu/blockdev.h"
#include "qemu/config-file.h"
#include "sysemu/sysemu.h"
@ -47,15 +47,6 @@ DriveInfo *add_init_drive(const char *optstr)
return dinfo;
}
#if !defined(TARGET_I386)
int pci_drive_hot_add(Monitor *mon, const QDict *qdict, DriveInfo *dinfo)
{
/* On non-x86 we don't do PCI hotplug */
monitor_printf(mon, "Can't hot-add drive to type %d\n", dinfo->type);
return -1;
}
#endif
void drive_hot_add(Monitor *mon, const QDict *qdict)
{
DriveInfo *dinfo = NULL;

View File

@ -1,16 +1,18 @@
universal-obj-$(CONFIG_ALPHA_DIS) += alpha.o
universal-obj-$(CONFIG_ARM_DIS) += arm.o
universal-obj-$(CONFIG_CRIS_DIS) += cris.o
universal-obj-$(CONFIG_HPPA_DIS) += hppa.o
universal-obj-$(CONFIG_I386_DIS) += i386.o
universal-obj-$(CONFIG_IA64_DIS) += ia64.o
universal-obj-$(CONFIG_M68K_DIS) += m68k.o
universal-obj-$(CONFIG_MICROBLAZE_DIS) += microblaze.o
universal-obj-$(CONFIG_MIPS_DIS) += mips.o
universal-obj-$(CONFIG_PPC_DIS) += ppc.o
universal-obj-$(CONFIG_S390_DIS) += s390.o
universal-obj-$(CONFIG_SH4_DIS) += sh4.o
universal-obj-$(CONFIG_SPARC_DIS) += sparc.o
universal-obj-$(CONFIG_LM32_DIS) += lm32.o
common-obj-$(CONFIG_ALPHA_DIS) += alpha.o
common-obj-$(CONFIG_ARM_DIS) += arm.o
common-obj-$(CONFIG_CRIS_DIS) += cris.o
common-obj-$(CONFIG_HPPA_DIS) += hppa.o
common-obj-$(CONFIG_I386_DIS) += i386.o
common-obj-$(CONFIG_IA64_DIS) += ia64.o
common-obj-$(CONFIG_M68K_DIS) += m68k.o
common-obj-$(CONFIG_MICROBLAZE_DIS) += microblaze.o
common-obj-$(CONFIG_MIPS_DIS) += mips.o
common-obj-$(CONFIG_PPC_DIS) += ppc.o
common-obj-$(CONFIG_S390_DIS) += s390.o
common-obj-$(CONFIG_SH4_DIS) += sh4.o
common-obj-$(CONFIG_SPARC_DIS) += sparc.o
common-obj-$(CONFIG_LM32_DIS) += lm32.o
universal-obj-$(CONFIG_TCI_DIS) += tci.o
# TODO: As long as the TCG interpreter and its generated code depend
# on the QEMU target, we cannot compile the disassembler here.
#common-obj-$(CONFIG_TCI_DIS) += tci.o

View File

@ -226,7 +226,7 @@ struct dis_private {
bfd_byte the_buffer[MAX_MNEM_SIZE];
bfd_vma insn_start;
int orig_sizeflag;
jmp_buf bailout;
sigjmp_buf bailout;
};
enum address_mode
@ -303,7 +303,7 @@ fetch_data2(struct disassemble_info *info, bfd_byte *addr)
STATUS. */
if (priv->max_fetched == priv->the_buffer)
(*info->memory_error_func) (status, start, info);
longjmp (priv->bailout, 1);
siglongjmp(priv->bailout, 1);
}
else
priv->max_fetched = addr;
@ -3661,7 +3661,7 @@ print_insn (bfd_vma pc, disassemble_info *info)
start_codep = priv.the_buffer;
codep = priv.the_buffer;
if (setjmp (priv.bailout) != 0)
if (sigsetjmp(priv.bailout, 0) != 0)
{
const char *name;
@ -4720,7 +4720,8 @@ print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp)
buf[0] = '0';
buf[1] = 'x';
snprintf_vma (tmp, sizeof(tmp), disp);
for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++);
for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++) {
}
pstrcpy (buf + 2, bufsize - 2, tmp + i);
}
else

View File

@ -624,7 +624,7 @@ struct private
bfd_byte *max_fetched;
bfd_byte the_buffer[MAXLEN];
bfd_vma insn_start;
jmp_buf bailout;
sigjmp_buf bailout;
};
/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
@ -644,7 +644,7 @@ fetch_data2(struct disassemble_info *info, bfd_byte *addr)
if (status != 0)
{
(*info->memory_error_func) (status, start, info);
longjmp (priv->bailout, 1);
siglongjmp(priv->bailout, 1);
}
else
priv->max_fetched = addr;
@ -1912,9 +1912,10 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
priv.max_fetched = priv.the_buffer;
priv.insn_start = memaddr;
if (setjmp (priv.bailout) != 0)
/* Error return. */
return -1;
if (sigsetjmp(priv.bailout, 0) != 0) {
/* Error return. */
return -1;
}
switch (info->mach)
{

View File

@ -589,6 +589,16 @@ static const struct s390_operand s390_operands[] =
{ 4, 32, S390_OPERAND_CCODE },
#define I8_32 46 /* 8 bit signed value starting at 32 */
{ 8, 32, S390_OPERAND_SIGNED },
#define U8_24 47 /* 8 bit unsigned value starting at 24 */
{ 8, 24, 0 },
#define U8_32 48 /* 8 bit unsigned value starting at 32 */
{ 8, 32, 0 },
#define I16_32 49
{ 16, 32, S390_OPERAND_SIGNED },
#define M4_16 50 /* 4-bit condition-code starting at 12 */
{ 4, 16, S390_OPERAND_CCODE },
#define I8_16 51
{ 8, 16, S390_OPERAND_SIGNED },
/* QEMU-END */
};
@ -663,7 +673,9 @@ static const struct s390_operand s390_operands[] =
This is just a workaround for existing code e.g. glibc. */
#define INSTR_RRE_RR_OPT 4, { R_24,RO_28,0,0,0,0 } /* efpc, sfpc */
#define INSTR_RRF_F0FF 4, { F_16,F_24,F_28,0,0,0 } /* e.g. madbr */
#define INSTR_RRF_F0FF2 4, { F_24,F_16,F_28,0,0,0 } /* e.g. cpsdr */
/* QEMU-MOD */
#define INSTR_RRF_F0FF2 4, { F_24,F_28,F_16,0,0,0 } /* e.g. cpsdr */
/* QEMU-END */
#define INSTR_RRF_F0FR 4, { F_24,F_16,R_28,0,0,0 } /* e.g. iedtr */
#define INSTR_RRF_FUFF 4, { F_24,F_16,F_28,U4_20,0,0 } /* e.g. didbr */
#define INSTR_RRF_RURR 4, { R_24,R_28,R_16,U4_20,0,0 } /* e.g. .insn */
@ -801,11 +813,35 @@ static const struct s390_operand s390_operands[] =
#define MASK_SSF_RRDRD { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
/* QEMU-ADD: */
#define INSTR_RIE_MRRP 6, { M4_32,R_8,R_12,J16_16,0,0 } /* e.g. crj */
#define INSTR_RIE_MRRP 6, { M4_32, R_8, R_12, J16_16, 0, 0 } /* e.g. crj */
#define MASK_RIE_MRRP { 0xff, 0x00, 0x00, 0x00, 0x0f, 0xff }
#define INSTR_RIE_MRIP 6, { M4_12,R_8,I8_32,J16_16,0,0 } /* e.g. cij */
#define INSTR_RIE_MRIP 6, { M4_12, R_8, I8_32, J16_16, 0, 0 } /* e.g. cij */
#define MASK_RIE_MRIP { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
#define INSTR_RIE_RRIII 6, { R_8, R_12, U8_16, U8_24, U8_32, 0 } /* risbg */
#define MASK_RIE_RRIII { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
#define INSTR_RIE_MRI 6, { M4_32, R_8, I16_16, 0, 0, 0 } /* e.g. cit */
#define MASK_RIE_MRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
#define INSTR_RIE_MRU 6, { M4_32, R_8, U16_16, 0, 0, 0 } /* e.g. clfit */
#define MASK_RIE_MRU { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
#define INSTR_RIE_RRI 6, { R_8, R_12, I16_16, 0, 0, 0 }
#define MASK_RIE_RRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
#define INSTR_RXY_URRD 6, { U8_8, D20_20, X_12, B_16, 0, 0 }
#define MASK_RXY_URRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
#define INSTR_SIL_DRI 6, { D_20, B_16, I16_32, 0, 0, 0 }
#define MASK_SIL_DRI { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
#define INSTR_RSY_MRRD 6, { M4_12, R_8, D20_20, B_16, 0, 0 }
#define MASK_SRY_MRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
#define INSTR_RRF_MRR 6, { M4_16, R_24, R_28, 0, 0, 0 }
#define MASK_RRF_MRR { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
#define INSTR_SIY_DRI 6, { D20_20, B_16, I8_16, 0, 0, 0 }
#define MASK_SIY_DRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
/* QEMU-END */
/* The opcode formats table (blueprints for .insn pseudo mnemonic). */
@ -926,6 +962,30 @@ static const struct s390_opcode s390_opcodes[] =
{ "ldeb", OP48(0xed0000000004LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
{ "brxlg", OP48(0xec0000000045LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2},
{ "brxhg", OP48(0xec0000000044LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2},
/* QEMU-ADD: */
{ "crj", OP48(0xec0000000076LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
{ "cgrj", OP48(0xec0000000064LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
{ "clrj", OP48(0xec0000000077LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
{ "clgrj", OP48(0xec0000000065LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
{ "cij", OP48(0xec000000007eLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
{ "cgij", OP48(0xec000000007cLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
{ "clij", OP48(0xec000000007fLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
{ "clgij", OP48(0xec000000007dLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
{ "risbg", OP48(0xec0000000055LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6},
{ "risbhg", OP48(0xec000000005dLL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6},
{ "risblg", OP48(0xec0000000051LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6},
{ "rnsbg", OP48(0xec0000000054LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6},
{ "rosbg", OP48(0xec0000000056LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6},
{ "rxsbg", OP48(0xec0000000057LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6},
{ "cit", OP48(0xec0000000072LL), MASK_RIE_MRI, INSTR_RIE_MRI, 3, 6},
{ "cgit", OP48(0xec0000000070LL), MASK_RIE_MRI, INSTR_RIE_MRI, 3, 6},
{ "clfit", OP48(0xec0000000073LL), MASK_RIE_MRU, INSTR_RIE_MRU, 3, 6},
{ "clgit", OP48(0xec0000000071LL), MASK_RIE_MRU, INSTR_RIE_MRU, 3, 6},
{ "ahik", OP48(0xec00000000d8LL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6},
{ "aghik", OP48(0xec00000000d9LL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6},
{ "alhsik", OP48(0xec00000000daLL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6},
{ "alghsik", OP48(0xec00000000dbLL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6},
/* QEMU-END */
{ "tp", OP48(0xeb00000000c0LL), MASK_RSL_R0RD, INSTR_RSL_R0RD, 3, 0},
{ "stamy", OP48(0xeb000000009bLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3},
{ "lamy", OP48(0xeb000000009aLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3},
@ -985,6 +1045,20 @@ static const struct s390_opcode s390_opcodes[] =
{ "srag", OP48(0xeb000000000aLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
{ "lmg", OP48(0xeb0000000004LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
{ "lmg", OP48(0xeb0000000004LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
/* QEMU-ADD: */
{ "loc", OP48(0xeb00000000f2LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6},
{ "locg", OP48(0xeb00000000e2LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6},
{ "stoc", OP48(0xeb00000000f3LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6},
{ "stocg", OP48(0xeb00000000e3LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6},
{ "srak", OP48(0xeb00000000dcLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6},
{ "slak", OP48(0xeb00000000ddLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6},
{ "srlk", OP48(0xeb00000000deLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6},
{ "sllk", OP48(0xeb00000000dfLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6},
{ "asi", OP48(0xeb000000006aLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6},
{ "alsi", OP48(0xeb000000006eLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6},
{ "agsi", OP48(0xeb000000007aLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6},
{ "algsi", OP48(0xeb000000007eLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6},
/* QEMU-END */
{ "unpka", OP8(0xeaLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
{ "pka", OP8(0xe9LL), MASK_SS_L2RDRD, INSTR_SS_L2RDRD, 3, 0},
{ "mvcin", OP8(0xe8LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
@ -993,6 +1067,17 @@ static const struct s390_opcode s390_opcodes[] =
{ "tprot", OP16(0xe501LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0},
{ "strag", OP48(0xe50000000002LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 2, 2},
{ "lasp", OP16(0xe500LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0},
/* QEMU-ADD: */
{ "mvhhi", OP16(0xe544LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6},
{ "mvghi", OP16(0xe548LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6},
{ "mvhi", OP16(0xe54cLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6},
{ "chhsi", OP16(0xe554LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6},
{ "clhhsi", OP16(0xe555LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6},
{ "cghsi", OP16(0xe558LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6},
{ "clghsi", OP16(0xe559LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6},
{ "chsi", OP16(0xe55cLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6},
{ "clfhsi", OP16(0xe55dLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6},
/* QEMU-END */
{ "slb", OP48(0xe30000000099LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
{ "slb", OP48(0xe30000000099LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
{ "alc", OP48(0xe30000000098LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
@ -1116,6 +1201,9 @@ static const struct s390_opcode s390_opcodes[] =
{ "lrag", OP48(0xe30000000003LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
{ "lrag", OP48(0xe30000000003LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
{ "ltg", OP48(0xe30000000002LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4},
/* QEMU-ADD: */
{ "pfd", OP48(0xe30000000036LL), MASK_RXY_URRD, INSTR_RXY_URRD, 3, 6},
/* QEMU-END */
{ "unpku", OP8(0xe2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
{ "pku", OP8(0xe1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
{ "edmk", OP8(0xdfLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
@ -1135,6 +1223,32 @@ static const struct s390_opcode s390_opcodes[] =
{ "csst", OP16(0xc802LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5},
{ "ectg", OP16(0xc801LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5},
{ "mvcos", OP16(0xc800LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 4},
/* QEMU-ADD: */
{ "exrl", OP16(0xc600ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "pfdrl", OP16(0xc602ll), MASK_RIL_UP, INSTR_RIL_UP, 3, 6},
{ "cghrl", OP16(0xc604ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "chrl", OP16(0xc605ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "clghrl", OP16(0xc606ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "clhrl", OP16(0xc607ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "cgrl", OP16(0xc608ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "clgrl", OP16(0xc60all), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "cgfrl", OP16(0xc60cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "crl", OP16(0xc60dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "clgfrl", OP16(0xc60ell), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "clrl", OP16(0xc60fll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "llhrl", OP16(0xc400ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "lghrl", OP16(0xc404ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "lhrl", OP16(0xc405ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "llghrl", OP16(0xc406ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "sthrl", OP16(0xc407ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "lgrl", OP16(0xc408ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "stgrl", OP16(0xc40bll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "lgfrl", OP16(0xc40cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "lrl", OP16(0xc40dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "llgfrl", OP16(0xc40ell), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "strl", OP16(0xc40fll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
/* QEMU-END */
{ "clfi", OP16(0xc20fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
{ "clgfi", OP16(0xc20eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
{ "cfi", OP16(0xc20dLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4},
@ -1265,6 +1379,29 @@ static const struct s390_opcode s390_opcodes[] =
{ "ltgr", OP16(0xb902LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
{ "lngr", OP16(0xb901LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
{ "lpgr", OP16(0xb900LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
/* QEMU-ADD: */
{ "crt", OP16(0xb972LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6},
{ "cgrt", OP16(0xb960LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6},
{ "clrt", OP16(0xb973LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6},
{ "clgrt", OP16(0xb961LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6},
{ "locr", OP16(0xb9f2LL), MASK_RRF_MRR, INSTR_RRF_MRR, 3, 6},
{ "locgr", OP16(0xb9e2LL), MASK_RRF_MRR, INSTR_RRF_MRR, 3, 6},
{ "popcnt", OP16(0xb9e1LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 6},
{ "ngrk", OP16(0xb9e4LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
{ "ogrk", OP16(0xb9e6LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
{ "xgrk", OP16(0xb9e7LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
{ "agrk", OP16(0xb9e8LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
{ "sgrk", OP16(0xb9e9LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
{ "algrk", OP16(0xb9eaLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
{ "slgrk", OP16(0xb9ebLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
{ "nrk", OP16(0xb9f4LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
{ "ork", OP16(0xb9f6LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
{ "xrk", OP16(0xb9f7LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
{ "ark", OP16(0xb9f8LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
{ "srk", OP16(0xb9f9LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
{ "alrk", OP16(0xb9faLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
{ "slrk", OP16(0xb9fbLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6},
/* QEMU-END */
{ "lctl", OP8(0xb7LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0},
{ "stctl", OP8(0xb6LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0},
{ "rrxtr", OP16(0xb3ffLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5},
@ -1426,6 +1563,20 @@ static const struct s390_opcode s390_opcodes[] =
{ "ltebr", OP16(0xb302LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
{ "lnebr", OP16(0xb301LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
{ "lpebr", OP16(0xb300LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
/* QEMU-ADD: */
{ "clfebr", OP16(0xb39cLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6},
{ "clfdbr", OP16(0xb39dLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6},
{ "clfxbr", OP16(0xb39eLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6},
{ "clgebr", OP16(0xb3acLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6},
{ "clgdbr", OP16(0xb3adLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6},
{ "clgxbr", OP16(0xb3aeLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6},
{ "celfbr", OP16(0xb390LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6},
{ "cdlfbr", OP16(0xb391LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6},
{ "cxlfbr", OP16(0xb392LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6},
{ "celgbr", OP16(0xb3a0LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6},
{ "cdlgbr", OP16(0xb3a1LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6},
{ "cxlgbr", OP16(0xb3a2LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6},
/* QEMU-END */
{ "trap4", OP16(0xb2ffLL), MASK_S_RD, INSTR_S_RD, 3, 0},
{ "lfas", OP16(0xb2bdLL), MASK_S_RD, INSTR_S_RD, 2, 5},
{ "srnmt", OP16(0xb2b9LL), MASK_S_RD, INSTR_S_RD, 2, 5},
@ -1774,22 +1925,6 @@ static const struct s390_opcode s390_opcodes[] =
{ "sckpf", OP16(0x0107LL), MASK_E, INSTR_E, 3, 0},
{ "upt", OP16(0x0102LL), MASK_E, INSTR_E, 3, 0},
{ "pr", OP16(0x0101LL), MASK_E, INSTR_E, 3, 0},
/* QEMU-ADD: */
{ "crj", OP48(0xec0000000076LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
{ "cgrj", OP48(0xec0000000064LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
{ "clrj", OP48(0xec0000000077LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
{ "clgrj", OP48(0xec0000000065LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
{ "cij", OP48(0xec000000007eLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
{ "cgij", OP48(0xec000000007cLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
{ "clij", OP48(0xec000000007fLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
{ "clgij", OP48(0xec000000007dLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
{ "lrl", OP16(0xc40dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "lgrl", OP16(0xc408ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
{ "lgfrl", OP16(0xc40cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
/* QEMU-END */
};
static const int s390_num_opcodes =

View File

@ -55,10 +55,7 @@ QEMUFile with:
QEMUFile *qemu_fopen_ops(void *opaque,
QEMUFilePutBufferFunc *put_buffer,
QEMUFileGetBufferFunc *get_buffer,
QEMUFileCloseFunc *close,
QEMUFileRateLimit *rate_limit,
QEMUFileSetRateLimit *set_rate_limit,
QEMUFileGetRateLimit *get_rate_limit);
QEMUFileCloseFunc *close);
The functions have the following functionality:
@ -80,24 +77,9 @@ Close a file and return an error code.
typedef int (QEMUFileCloseFunc)(void *opaque);
Called to determine if the file has exceeded its bandwidth allocation. The
bandwidth capping is a soft limit, not a hard limit.
typedef int (QEMUFileRateLimit)(void *opaque);
Called to change the current bandwidth allocation. This function must return
the new actual bandwidth. It should be new_rate if everything goes OK, and
the old rate otherwise.
typedef size_t (QEMUFileSetRateLimit)(void *opaque, size_t new_rate);
typedef size_t (QEMUFileGetRateLimit)(void *opaque);
You can use any internal state that you need using the opaque void *
pointer that is passed to all functions.
The rate limiting functions are used to limit the bandwidth used by
QEMU migration.
The important functions for us are put_buffer()/get_buffer() that
allow to write/read a buffer into the QEMUFile.

129
docs/q35-chipset.cfg Normal file
View File

@ -0,0 +1,129 @@
################################################################
#
# qemu -M q35 creates a bare machine with just the very essential
# chipset devices being present:
#
# 00.0 - Host bridge
# 1f.0 - ISA bridge / LPC
# 1f.2 - SATA (AHCI) controller
# 1f.3 - SMBus controller
#
# This config file documents the other devices and how they are
# created. You can simply use "-readconfig $thisfile" to create
# them all. Here is a overview:
#
# 19.0 - Ethernet controller (not created, our e1000 emulation
# doesn't emulate the ich9 device).
# 1a.* - USB Controller #2 (ehci + uhci companions)
# 1b.0 - HD Audio Controller
# 1c.* - PCI Express Ports
# 1d.* - USB Controller #1 (ehci + uhci companions,
# "qemu -M q35 -usb" creates these too)
# 1e.0 - PCI Bridge
#
[device "ich9-ehci-2"]
driver = "ich9-usb-ehci2"
multifunction = "on"
bus = "pcie.0"
addr = "1a.7"
[device "ich9-uhci-4"]
driver = "ich9-usb-uhci4"
multifunction = "on"
bus = "pcie.0"
addr = "1a.0"
masterbus = "ich9-ehci-2.0"
firstport = "0"
[device "ich9-uhci-5"]
driver = "ich9-usb-uhci5"
multifunction = "on"
bus = "pcie.0"
addr = "1a.1"
masterbus = "ich9-ehci-2.0"
firstport = "2"
[device "ich9-uhci-6"]
driver = "ich9-usb-uhci6"
multifunction = "on"
bus = "pcie.0"
addr = "1a.2"
masterbus = "ich9-ehci-2.0"
firstport = "4"
[device "ich9-hda-audio"]
driver = "ich9-intel-hda"
bus = "pcie.0"
addr = "1b.0"
[device "ich9-pcie-port-1"]
driver = "ioh3420"
multifunction = "on"
bus = "pcie.0"
addr = "1c.0"
port = "1"
chassis = "1"
[device "ich9-pcie-port-2"]
driver = "ioh3420"
multifunction = "on"
bus = "pcie.0"
addr = "1c.1"
port = "2"
chassis = "2"
[device "ich9-pcie-port-3"]
driver = "ioh3420"
multifunction = "on"
bus = "pcie.0"
addr = "1c.2"
port = "3"
chassis = "3"
[device "ich9-pcie-port-4"]
driver = "ioh3420"
multifunction = "on"
bus = "pcie.0"
addr = "1c.3"
port = "4"
chassis = "4"
[device "ich9-ehci-1"]
driver = "ich9-usb-ehci1"
multifunction = "on"
bus = "pcie.0"
addr = "1d.7"
[device "ich9-uhci-1"]
driver = "ich9-usb-uhci1"
multifunction = "on"
bus = "pcie.0"
addr = "1d.0"
masterbus = "ich9-ehci-1.0"
firstport = "0"
[device "ich9-uhci-2"]
driver = "ich9-usb-uhci2"
multifunction = "on"
bus = "pcie.0"
addr = "1d.1"
masterbus = "ich9-ehci-1.0"
firstport = "2"
[device "ich9-uhci-3"]
driver = "ich9-usb-uhci3"
multifunction = "on"
bus = "pcie.0"
addr = "1d.2"
masterbus = "ich9-ehci-1.0"
firstport = "4"
[device "ich9-pci-bridge"]
driver = "i82801b11-bridge"
bus = "pcie.0"
addr = "1e.0"

50
docs/specs/pci-ids.txt Normal file
View File

@ -0,0 +1,50 @@
PCI IDs for qemu
================
Red Hat, Inc. donates a part of its device ID range to qemu, to be used for
virtual devices. The vendor IDs are 1af4 (formerly Qumranet ID) and 1b36.
Contact Gerd Hoffmann <kraxel@redhat.com> to get a device ID assigned
for your devices.
1af4 vendor ID
--------------
The 1000 -> 10ff device ID range is used as follows for virtio-pci devices.
Note that this allocation separate from the virtio device IDs, which are
maintained as part of the virtio specification.
1af4:1000 network device
1af4:1001 block device
1af4:1002 balloon device
1af4:1003 console device
1af4:1004 SCSI host bus adapter device
1af4:1005 entropy generator device
1af4:1009 9p filesystem device
1af4:10f0 Available for experimental usage without registration. Must get
to official ID when the code leaves the test lab (i.e. when seeking
1af4:10ff upstream merge or shipping a distro/product) to avoid conflicts.
1af4:1100 Used as PCI Subsystem ID for existing hardware devices emulated
by qemu.
1af4:1110 ivshmem device (shared memory, docs/specs/ivshmem_device_spec.txt)
All other device IDs are reserved.
1b36 vendor ID
--------------
The 0000 -> 00ff device ID range is used as follows for QEMU-specific
PCI devices (other than virtio):
1b36:0001 PCI-PCI bridge
1b36:0002 PCI serial port (16550A) adapter (docs/specs/pci-serial.txt)
1b36:0003 PCI Dual-port 16550A adapter (docs/specs/pci-serial.txt)
1b36:0004 PCI Quad-port 16550A adapter (docs/specs/pci-serial.txt)
All these devices are documented in docs/specs.
The 0100 device ID is used for the QXL video card device.

View File

@ -23,7 +23,7 @@ for debugging, profiling, and observing execution.
4. Pretty-print the binary trace file:
./simpletrace.py trace-events trace-*
./scripts/simpletrace.py trace-events trace-*
== Trace events ==
@ -198,7 +198,7 @@ The "simple" backend produces binary trace files that can be formatted with the
simpletrace.py script. The script takes the "trace-events" file and the binary
trace:
./simpletrace.py trace-events trace-12345
./scripts/simpletrace.py trace-events trace-12345
You must ensure that the same "trace-events" file was used to build QEMU,
otherwise trace event declarations may have changed and output will not be

View File

@ -2,7 +2,7 @@
qemu usb storage emulation
--------------------------
QEMU has two emulations for usb storage devices.
QEMU has three devices for usb storage emulation.
Number one emulates the classic bulk-only transport protocol which is
used by 99% of the usb sticks on the marked today and is called
@ -31,6 +31,15 @@ with tree logical units:
-device scsi-cd,bus=uas.0,scsi-id=0,lun=5,drive=uas-cdrom
Number three emulates the classic bulk-only transport protocol too.
It's called "usb-bot". It shares most code with "usb-storage", and
the guest will not be able to see the difference. The qemu command
line interface is simliar to usb-uas though, i.e. no automatic scsi
disk creation. It also features support for up to 16 LUNs. The LUN
numbers must be continous, i.e. for three devices you must use 0+1+2.
The 0+1+5 numbering from the "usb-uas" example isn't going to work
with "usb-bot".
enjoy,
Gerd

View File

@ -0,0 +1,104 @@
virtio balloon memory statistics
================================
The virtio balloon driver supports guest memory statistics reporting. These
statistics are available to QEMU users as QOM (QEMU Object Model) device
properties via a polling mechanism.
Before querying the available stats, clients first have to enable polling.
This is done by writing a time interval value (in seconds) to the
guest-stats-polling-interval property. This value can be:
> 0 enables polling in the specified interval. If polling is already
enabled, the polling time interval is changed to the new value
0 disables polling. Previous polled statistics are still valid and
can be queried.
Once polling is enabled, the virtio-balloon device in QEMU will start
polling the guest's balloon driver for new stats in the specified time
interval.
To retrieve those stats, clients have to query the guest-stats property,
which will return a dictionary containing:
o A key named 'stats', containing all available stats. If the guest
doesn't support a particular stat, or if it couldn't be retrieved,
its value will be -1. Currently, the following stats are supported:
- stat-swap-in
- stat-swap-out
- stat-major-faults
- stat-minor-faults
- stat-free-memory
- stat-total-memory
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
It's also important to note the following:
- Previously polled statistics remain available even if the polling is
later disabled
- As noted above, if a guest doesn't support a particular stat its value
will always be -1. However, it's also possible that a guest temporarily
couldn't update one or even all stats. If this happens, just wait for
the next update
- 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, 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
respond to the request the timer will never be re-armed, which has
the same effect as disabling polling
Here are a few examples. QEMU is started with '-balloon virtio', which
generates '/machine/peripheral-anon/device[1]' as the QOM path for the
balloon device.
Enable polling with 2 seconds interval:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 2 } }
{ "return": {} }
Change polling to 10 seconds:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 10 } }
{ "return": {} }
Get stats:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Disable polling:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "stats-polling-interval", "value": 0 } }
{ "return": {} }

8
dump.c
View File

@ -271,11 +271,13 @@ static int write_elf64_note(DumpState *s)
static int write_elf64_notes(DumpState *s)
{
CPUArchState *env;
CPUState *cpu;
int ret;
int id;
for (env = first_cpu; env != NULL; env = env->next_cpu) {
id = cpu_index(env);
cpu = ENV_GET_CPU(env);
id = cpu_index(cpu);
ret = cpu_write_elf64_note(fd_write_vmcore, env, id, s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf notes.\n");
@ -321,11 +323,13 @@ static int write_elf32_note(DumpState *s)
static int write_elf32_notes(DumpState *s)
{
CPUArchState *env;
CPUState *cpu;
int ret;
int id;
for (env = first_cpu; env != NULL; env = env->next_cpu) {
id = cpu_index(env);
cpu = ENV_GET_CPU(env);
id = cpu_index(cpu);
ret = cpu_write_elf32_note(fd_write_vmcore, env, id, s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf notes.\n");

72
exec.c
View File

@ -78,7 +78,7 @@ DEFINE_TLS(CPUArchState *,cpu_single_env);
/* 0 = Do not count executed instructions.
1 = Precise instruction counting.
2 = Adaptive rate instruction counting. */
int use_icount = 0;
int use_icount;
#if !defined(CONFIG_USER_ONLY)
@ -219,16 +219,16 @@ void cpu_exec_init_all(void)
#endif
}
#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
#if !defined(CONFIG_USER_ONLY)
static int cpu_common_post_load(void *opaque, int version_id)
{
CPUArchState *env = opaque;
CPUState *cpu = opaque;
/* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
version_id is increased. */
env->interrupt_request &= ~0x01;
tlb_flush(env, 1);
cpu->interrupt_request &= ~0x01;
tlb_flush(cpu->env_ptr, 1);
return 0;
}
@ -240,31 +240,35 @@ static const VMStateDescription vmstate_cpu_common = {
.minimum_version_id_old = 1,
.post_load = cpu_common_post_load,
.fields = (VMStateField []) {
VMSTATE_UINT32(halted, CPUArchState),
VMSTATE_UINT32(interrupt_request, CPUArchState),
VMSTATE_UINT32(halted, CPUState),
VMSTATE_UINT32(interrupt_request, CPUState),
VMSTATE_END_OF_LIST()
}
};
#else
#define vmstate_cpu_common vmstate_dummy
#endif
CPUArchState *qemu_get_cpu(int cpu)
CPUState *qemu_get_cpu(int index)
{
CPUArchState *env = first_cpu;
CPUState *cpu = NULL;
while (env) {
if (env->cpu_index == cpu)
cpu = ENV_GET_CPU(env);
if (cpu->cpu_index == index) {
break;
}
env = env->next_cpu;
}
return env;
return env ? cpu : NULL;
}
void cpu_exec_init(CPUArchState *env)
{
#ifndef CONFIG_USER_ONLY
CPUState *cpu = ENV_GET_CPU(env);
#endif
CPUClass *cc = CPU_GET_CLASS(cpu);
CPUArchState **penv;
int cpu_index;
@ -278,8 +282,8 @@ void cpu_exec_init(CPUArchState *env)
penv = &(*penv)->next_cpu;
cpu_index++;
}
env->cpu_index = cpu_index;
env->numa_node = 0;
cpu->cpu_index = cpu_index;
cpu->numa_node = 0;
QTAILQ_INIT(&env->breakpoints);
QTAILQ_INIT(&env->watchpoints);
#ifndef CONFIG_USER_ONLY
@ -289,11 +293,15 @@ void cpu_exec_init(CPUArchState *env)
#if defined(CONFIG_USER_ONLY)
cpu_list_unlock();
#endif
vmstate_register(NULL, cpu_index, &vmstate_cpu_common, cpu);
#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
vmstate_register(NULL, cpu_index, &vmstate_cpu_common, env);
register_savevm(NULL, "cpu", cpu_index, CPU_SAVE_VERSION,
cpu_save, cpu_load, env);
assert(cc->vmsd == NULL);
#endif
if (cc->vmsd != NULL) {
vmstate_register(NULL, cpu_index, cc->vmsd, cpu);
}
}
#if defined(TARGET_HAS_ICE)
@ -484,15 +492,12 @@ void cpu_single_step(CPUArchState *env, int enabled)
#endif
}
void cpu_reset_interrupt(CPUArchState *env, int mask)
{
env->interrupt_request &= ~mask;
}
void cpu_exit(CPUArchState *env)
{
env->exit_request = 1;
cpu_unlink_tb(env);
CPUState *cpu = ENV_GET_CPU(env);
cpu->exit_request = 1;
cpu->tcg_exit_req = 1;
}
void cpu_abort(CPUArchState *env, const char *fmt, ...)
@ -531,7 +536,6 @@ CPUArchState *cpu_copy(CPUArchState *env)
{
CPUArchState *new_env = cpu_init(env->cpu_model_str);
CPUArchState *next_cpu = new_env->next_cpu;
int cpu_index = new_env->cpu_index;
#if defined(TARGET_HAS_ICE)
CPUBreakpoint *bp;
CPUWatchpoint *wp;
@ -539,9 +543,8 @@ CPUArchState *cpu_copy(CPUArchState *env)
memcpy(new_env, env, sizeof(CPUArchState));
/* Preserve chaining and index. */
/* Preserve chaining. */
new_env->next_cpu = next_cpu;
new_env->cpu_index = cpu_index;
/* Clone all break/watchpoints.
Note: Once we support ptrace with hw-debug register access, make sure
@ -843,6 +846,8 @@ static void *file_ram_alloc(RAMBlock *block,
const char *path)
{
char *filename;
char *sanitized_name;
char *c;
void *area;
int fd;
#ifdef MAP_POPULATE
@ -864,18 +869,25 @@ static void *file_ram_alloc(RAMBlock *block,
return NULL;
}
if (asprintf(&filename, "%s/qemu_back_mem.XXXXXX", path) == -1) {
return NULL;
/* Make name safe to use with mkstemp by replacing '/' with '_'. */
sanitized_name = g_strdup(block->mr->name);
for (c = sanitized_name; *c != '\0'; c++) {
if (*c == '/')
*c = '_';
}
filename = g_strdup_printf("%s/qemu_back_mem.%s.XXXXXX", path,
sanitized_name);
g_free(sanitized_name);
fd = mkstemp(filename);
if (fd < 0) {
perror("unable to create backing store for hugepages");
free(filename);
g_free(filename);
return NULL;
}
unlink(filename);
free(filename);
g_free(filename);
memory = (memory+hpagesize-1) & ~(hpagesize-1);
@ -1466,7 +1478,7 @@ static void check_watchpoint(int offset, int len_mask, int flags)
/* We re-entered the check after replacing the TB. Now raise
* the debug interrupt so that is will trigger after the
* current instruction. */
cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
cpu_interrupt(ENV_GET_CPU(env), CPU_INTERRUPT_DEBUG);
return;
}
vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;

View File

@ -1271,11 +1271,18 @@ float64 int64_to_float64( int64 a STATUS_PARAM )
}
float64 uint64_to_float64( uint64 a STATUS_PARAM )
float64 uint64_to_float64(uint64 a STATUS_PARAM)
{
if ( a == 0 ) return float64_zero;
return normalizeRoundAndPackFloat64( 0, 0x43C, a STATUS_VAR );
int exp = 0x43C;
if (a == 0) {
return float64_zero;
}
if ((int64_t)a < 0) {
shift64RightJamming(a, 1, &a);
exp += 1;
}
return normalizeRoundAndPackFloat64(0, exp, a STATUS_VAR);
}
/*----------------------------------------------------------------------------
@ -1332,6 +1339,14 @@ float128 int64_to_float128( int64 a STATUS_PARAM )
}
float128 uint64_to_float128(uint64 a STATUS_PARAM)
{
if (a == 0) {
return float128_zero;
}
return normalizeRoundAndPackFloat128(0, 0x406E, a, 0 STATUS_VAR);
}
/*----------------------------------------------------------------------------
| Returns the result of converting the single-precision floating-point value
| `a' to the 32-bit two's complement integer format. The conversion is
@ -2219,7 +2234,7 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
}
}
/* Zero plus something non-zero : just return the something */
return make_float32(float32_val(c) ^ (signflip << 31));
return packFloat32(cSign ^ signflip, cExp, cSig);
}
if (aExp == 0) {
@ -3772,7 +3787,7 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
}
}
/* Zero plus something non-zero : just return the something */
return make_float64(float64_val(c) ^ ((uint64_t)signflip << 63));
return packFloat64(cSign ^ signflip, cExp, cSig);
}
if (aExp == 0) {

View File

@ -1,9 +1,10 @@
ifeq ($(CONFIG_REALLY_VIRTFS),y)
common-obj-y = qemu-fsdev.o virtio-9p-marshal.o
# Toplevel always builds this; targets without virtio will put it in
# common-obj-y
extra-obj-y = qemu-fsdev-dummy.o
else
common-obj-y = qemu-fsdev-dummy.o
endif
common-obj-y += qemu-fsdev-opts.o
# Toplevel always builds this; targets without virtio will put it in
# common-obj-y
common-obj-$(CONFIG_ALL) += qemu-fsdev-dummy.o

View File

@ -20,10 +20,3 @@ int qemu_fsdev_add(QemuOpts *opts)
{
return 0;
}
static void fsdev_register_config(void)
{
qemu_add_opts(&qemu_fsdev_opts);
qemu_add_opts(&qemu_virtfs_opts);
}
machine_init(fsdev_register_config);

85
fsdev/qemu-fsdev-opts.c Normal file
View File

@ -0,0 +1,85 @@
/*
* Virtio 9p
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* later. See the COPYING file in the top-level directory.
*/
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "qemu/module.h"
static QemuOptsList qemu_fsdev_opts = {
.name = "fsdev",
.implied_opt_name = "fsdriver",
.head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
.desc = {
{
.name = "fsdriver",
.type = QEMU_OPT_STRING,
}, {
.name = "path",
.type = QEMU_OPT_STRING,
}, {
.name = "security_model",
.type = QEMU_OPT_STRING,
}, {
.name = "writeout",
.type = QEMU_OPT_STRING,
}, {
.name = "readonly",
.type = QEMU_OPT_BOOL,
}, {
.name = "socket",
.type = QEMU_OPT_STRING,
}, {
.name = "sock_fd",
.type = QEMU_OPT_NUMBER,
},
{ /*End of list */ }
},
};
static QemuOptsList qemu_virtfs_opts = {
.name = "virtfs",
.implied_opt_name = "fsdriver",
.head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
.desc = {
{
.name = "fsdriver",
.type = QEMU_OPT_STRING,
}, {
.name = "path",
.type = QEMU_OPT_STRING,
}, {
.name = "mount_tag",
.type = QEMU_OPT_STRING,
}, {
.name = "security_model",
.type = QEMU_OPT_STRING,
}, {
.name = "writeout",
.type = QEMU_OPT_STRING,
}, {
.name = "readonly",
.type = QEMU_OPT_BOOL,
}, {
.name = "socket",
.type = QEMU_OPT_STRING,
}, {
.name = "sock_fd",
.type = QEMU_OPT_NUMBER,
},
{ /*End of list */ }
},
};
static void fsdev_register_config(void)
{
qemu_add_opts(&qemu_fsdev_opts);
qemu_add_opts(&qemu_virtfs_opts);
}
machine_init(fsdev_register_config);

View File

@ -97,11 +97,3 @@ FsDriverEntry *get_fsdev_fsentry(char *id)
}
return NULL;
}
static void fsdev_register_config(void)
{
qemu_add_opts(&qemu_fsdev_opts);
qemu_add_opts(&qemu_virtfs_opts);
}
machine_init(fsdev_register_config);

View File

@ -1039,7 +1039,7 @@ int main(int argc, char **argv)
}
switch (c) {
case 'p':
rpath = strdup(optarg);
rpath = g_strdup(optarg);
break;
case 'n':
is_daemon = false;
@ -1048,7 +1048,7 @@ int main(int argc, char **argv)
sock = atoi(optarg);
break;
case 's':
sock_name = strdup(optarg);
sock_name = g_strdup(optarg);
break;
case 'u':
own_u = atoi(optarg);

102
gdbstub.c
View File

@ -40,6 +40,7 @@
#include "cpu.h"
#include "qemu/sockets.h"
#include "sysemu/kvm.h"
#include "qemu/bitops.h"
#ifndef TARGET_CPU_MEMORY_RW_DEBUG
static inline int target_memory_rw_debug(CPUArchState *env, target_ulong addr,
@ -1535,27 +1536,34 @@ static int cpu_gdb_write_register(CPUAlphaState *env, uint8_t *mem_buf, int n)
}
#elif defined (TARGET_S390X)
#define NUM_CORE_REGS S390_NUM_TOTAL_REGS
#define NUM_CORE_REGS S390_NUM_REGS
static int cpu_gdb_read_register(CPUS390XState *env, uint8_t *mem_buf, int n)
{
uint64_t val;
int cc_op;
switch (n) {
case S390_PSWM_REGNUM: GET_REGL(env->psw.mask); break;
case S390_PSWA_REGNUM: GET_REGL(env->psw.addr); break;
case S390_R0_REGNUM ... S390_R15_REGNUM:
GET_REGL(env->regs[n-S390_R0_REGNUM]); break;
case S390_A0_REGNUM ... S390_A15_REGNUM:
GET_REG32(env->aregs[n-S390_A0_REGNUM]); break;
case S390_FPC_REGNUM: GET_REG32(env->fpc); break;
case S390_F0_REGNUM ... S390_F15_REGNUM:
/* XXX */
break;
case S390_PC_REGNUM: GET_REGL(env->psw.addr); break;
case S390_CC_REGNUM:
env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst,
env->cc_vr);
GET_REG32(env->cc_op);
break;
case S390_PSWM_REGNUM:
cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr);
val = deposit64(env->psw.mask, 44, 2, cc_op);
GET_REGL(val);
break;
case S390_PSWA_REGNUM:
GET_REGL(env->psw.addr);
break;
case S390_R0_REGNUM ... S390_R15_REGNUM:
GET_REGL(env->regs[n-S390_R0_REGNUM]);
break;
case S390_A0_REGNUM ... S390_A15_REGNUM:
GET_REG32(env->aregs[n-S390_A0_REGNUM]);
break;
case S390_FPC_REGNUM:
GET_REG32(env->fpc);
break;
case S390_F0_REGNUM ... S390_F15_REGNUM:
GET_REG64(env->fregs[n-S390_F0_REGNUM].ll);
break;
}
return 0;
@ -1570,20 +1578,30 @@ static int cpu_gdb_write_register(CPUS390XState *env, uint8_t *mem_buf, int n)
tmp32 = ldl_p(mem_buf);
switch (n) {
case S390_PSWM_REGNUM: env->psw.mask = tmpl; break;
case S390_PSWA_REGNUM: env->psw.addr = tmpl; break;
case S390_R0_REGNUM ... S390_R15_REGNUM:
env->regs[n-S390_R0_REGNUM] = tmpl; break;
case S390_A0_REGNUM ... S390_A15_REGNUM:
env->aregs[n-S390_A0_REGNUM] = tmp32; r=4; break;
case S390_FPC_REGNUM: env->fpc = tmp32; r=4; break;
case S390_F0_REGNUM ... S390_F15_REGNUM:
/* XXX */
break;
case S390_PC_REGNUM: env->psw.addr = tmpl; break;
case S390_CC_REGNUM: env->cc_op = tmp32; r=4; break;
case S390_PSWM_REGNUM:
env->psw.mask = tmpl;
env->cc_op = extract64(tmpl, 44, 2);
break;
case S390_PSWA_REGNUM:
env->psw.addr = tmpl;
break;
case S390_R0_REGNUM ... S390_R15_REGNUM:
env->regs[n-S390_R0_REGNUM] = tmpl;
break;
case S390_A0_REGNUM ... S390_A15_REGNUM:
env->aregs[n-S390_A0_REGNUM] = tmp32;
r = 4;
break;
case S390_FPC_REGNUM:
env->fpc = tmp32;
r = 4;
break;
case S390_F0_REGNUM ... S390_F15_REGNUM:
env->fregs[n-S390_F0_REGNUM].ll = tmpl;
break;
default:
return 0;
}
return r;
}
#elif defined (TARGET_LM32)
@ -2048,9 +2066,11 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
static CPUArchState *find_cpu(uint32_t thread_id)
{
CPUArchState *env;
CPUState *cpu;
for (env = first_cpu; env != NULL; env = env->next_cpu) {
if (cpu_index(env) == thread_id) {
cpu = ENV_GET_CPU(env);
if (cpu_index(cpu) == thread_id) {
return env;
}
}
@ -2078,7 +2098,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
case '?':
/* TODO: Make this return the correct value for user-mode. */
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
cpu_index(s->c_cpu));
cpu_index(ENV_GET_CPU(s->c_cpu)));
put_packet(s, buf);
/* Remove all the breakpoints when this query is issued,
* because gdb is doing and initial connect and the state
@ -2373,7 +2393,8 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
} else if (strcmp(p,"sThreadInfo") == 0) {
report_cpuinfo:
if (s->query_cpu) {
snprintf(buf, sizeof(buf), "m%x", cpu_index(s->query_cpu));
snprintf(buf, sizeof(buf), "m%x",
cpu_index(ENV_GET_CPU(s->query_cpu)));
put_packet(s, buf);
s->query_cpu = s->query_cpu->next_cpu;
} else
@ -2383,10 +2404,11 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
thread = strtoull(p+16, (char **)&p, 16);
env = find_cpu(thread);
if (env != NULL) {
CPUState *cpu = ENV_GET_CPU(env);
cpu_synchronize_state(env);
len = snprintf((char *)mem_buf, sizeof(mem_buf),
"CPU#%d [%s]", env->cpu_index,
env->halted ? "halted " : "running");
"CPU#%d [%s]", cpu->cpu_index,
cpu->halted ? "halted " : "running");
memtohex(buf, mem_buf, len);
put_packet(s, buf);
}
@ -2493,6 +2515,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
{
GDBState *s = gdbserver_state;
CPUArchState *env = s->c_cpu;
CPUState *cpu = ENV_GET_CPU(env);
char buf[256];
const char *type;
int ret;
@ -2521,7 +2544,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
}
snprintf(buf, sizeof(buf),
"T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
GDB_SIGNAL_TRAP, cpu_index(env), type,
GDB_SIGNAL_TRAP, cpu_index(cpu), type,
env->watchpoint_hit->vaddr);
env->watchpoint_hit = NULL;
goto send_packet;
@ -2554,7 +2577,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
ret = GDB_SIGNAL_UNKNOWN;
break;
}
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_index(env));
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_index(cpu));
send_packet:
put_packet(s, buf);
@ -2818,7 +2841,7 @@ static void gdb_accept(void)
GDBState *s;
struct sockaddr_in sockaddr;
socklen_t len;
int val, fd;
int fd;
for(;;) {
len = sizeof(sockaddr);
@ -2835,8 +2858,7 @@ static void gdb_accept(void)
}
/* set short latency */
val = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
socket_set_nodelay(fd);
s = g_malloc0(sizeof(GDBState));
s->c_cpu = first_cpu;

View File

@ -295,14 +295,14 @@ ETEXI
.name = "log",
.args_type = "items:s",
.params = "item1[,...]",
.help = "activate logging of the specified items to '/tmp/qemu.log'",
.help = "activate logging of the specified items",
.mhandler.cmd = do_log,
},
STEXI
@item log @var{item1}[,...]
@findex log
Activate logging of the specified items to @file{/tmp/qemu.log}.
Activate logging of the specified items.
ETEXI
{
@ -837,6 +837,44 @@ STEXI
@item nmi @var{cpu}
@findex nmi
Inject an NMI on the given CPU (x86 only).
ETEXI
{
.name = "ringbuf_write",
.args_type = "device:s,data:s",
.params = "device data",
.help = "Write to a ring buffer character device",
.mhandler.cmd = hmp_ringbuf_write,
},
STEXI
@item ringbuf_write @var{device} @var{data}
@findex ringbuf_write
Write @var{data} to ring buffer character device @var{device}.
@var{data} must be a UTF-8 string.
ETEXI
{
.name = "ringbuf_read",
.args_type = "device:s,size:i",
.params = "device size",
.help = "Read from a ring buffer character device",
.mhandler.cmd = hmp_ringbuf_read,
},
STEXI
@item ringbuf_read @var{device}
@findex ringbuf_read
Read and print up to @var{size} bytes from ring buffer character
device @var{device}.
Certain non-printable characters are printed \uXXXX, where XXXX is the
character code in hexadecimal. Character \ is printed \\.
Bug: can screw up when the buffer contains invalid UTF-8 sequences,
NUL characters, after the ring buffer lost data, and when reading
stops because the size limit is reached.
ETEXI
{
@ -1131,7 +1169,7 @@ ETEXI
{
.name = "netdev_add",
.args_type = "netdev:O",
.params = "[user|tap|socket],id=str[,prop=value][,...]",
.params = "[user|tap|socket|hubport],id=str[,prop=value][,...]",
.help = "add host network device",
.mhandler.cmd = hmp_netdev_add,
},
@ -1482,6 +1520,38 @@ Password is invalidated at the given time. @var{nsec} are the seconds
passed since 1970, i.e. unix epoch.
@end table
ETEXI
{
.name = "chardev-add",
.args_type = "args:s",
.params = "args",
.help = "add chardev",
.mhandler.cmd = hmp_chardev_add,
},
STEXI
@item chardev_add args
@findex chardev_add
chardev_add accepts the same parameters as the -chardev command line switch.
ETEXI
{
.name = "chardev-remove",
.args_type = "id:s",
.params = "id",
.help = "remove chardev",
.mhandler.cmd = hmp_chardev_remove,
},
STEXI
@item chardev_remove id
@findex chardev_remove
Removes the chardev @var{id}.
ETEXI
{
@ -1489,7 +1559,8 @@ ETEXI
.args_type = "item:s?",
.params = "[subcommand]",
.help = "show various information about the system state",
.mhandler.cmd = do_info,
.mhandler.cmd = do_info_help,
.sub_table = info_cmds,
},
STEXI
@ -1570,6 +1641,8 @@ show device tree
show qdev device model list
@item info roms
show roms
@item info tpm
show the TPM device
@end table
ETEXI

173
hmp.c
View File

@ -31,7 +31,7 @@ static void hmp_handle_error(Monitor *mon, Error **errp)
}
}
void hmp_info_name(Monitor *mon)
void hmp_info_name(Monitor *mon, const QDict *qdict)
{
NameInfo *info;
@ -42,7 +42,7 @@ void hmp_info_name(Monitor *mon)
qapi_free_NameInfo(info);
}
void hmp_info_version(Monitor *mon)
void hmp_info_version(Monitor *mon, const QDict *qdict)
{
VersionInfo *info;
@ -55,7 +55,7 @@ void hmp_info_version(Monitor *mon)
qapi_free_VersionInfo(info);
}
void hmp_info_kvm(Monitor *mon)
void hmp_info_kvm(Monitor *mon, const QDict *qdict)
{
KvmInfo *info;
@ -70,7 +70,7 @@ void hmp_info_kvm(Monitor *mon)
qapi_free_KvmInfo(info);
}
void hmp_info_status(Monitor *mon)
void hmp_info_status(Monitor *mon, const QDict *qdict)
{
StatusInfo *info;
@ -89,7 +89,7 @@ void hmp_info_status(Monitor *mon)
qapi_free_StatusInfo(info);
}
void hmp_info_uuid(Monitor *mon)
void hmp_info_uuid(Monitor *mon, const QDict *qdict)
{
UuidInfo *info;
@ -98,7 +98,7 @@ void hmp_info_uuid(Monitor *mon)
qapi_free_UuidInfo(info);
}
void hmp_info_chardev(Monitor *mon)
void hmp_info_chardev(Monitor *mon, const QDict *qdict)
{
ChardevInfoList *char_info, *info;
@ -111,7 +111,7 @@ void hmp_info_chardev(Monitor *mon)
qapi_free_ChardevInfoList(char_info);
}
void hmp_info_mice(Monitor *mon)
void hmp_info_mice(Monitor *mon, const QDict *qdict)
{
MouseInfoList *mice_list, *mouse;
@ -131,7 +131,7 @@ void hmp_info_mice(Monitor *mon)
qapi_free_MouseInfoList(mice_list);
}
void hmp_info_migrate(Monitor *mon)
void hmp_info_migrate(Monitor *mon, const QDict *qdict)
{
MigrationInfo *info;
MigrationCapabilityStatusList *caps, *cap;
@ -209,7 +209,7 @@ void hmp_info_migrate(Monitor *mon)
qapi_free_MigrationCapabilityStatusList(caps);
}
void hmp_info_migrate_capabilities(Monitor *mon)
void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict)
{
MigrationCapabilityStatusList *caps, *cap;
@ -228,13 +228,13 @@ void hmp_info_migrate_capabilities(Monitor *mon)
qapi_free_MigrationCapabilityStatusList(caps);
}
void hmp_info_migrate_cache_size(Monitor *mon)
void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict)
{
monitor_printf(mon, "xbzrel cache size: %" PRId64 " kbytes\n",
qmp_query_migrate_cache_size(NULL) >> 10);
}
void hmp_info_cpus(Monitor *mon)
void hmp_info_cpus(Monitor *mon, const QDict *qdict)
{
CpuInfoList *cpu_list, *cpu;
@ -272,7 +272,7 @@ void hmp_info_cpus(Monitor *mon)
qapi_free_CpuInfoList(cpu_list);
}
void hmp_info_block(Monitor *mon)
void hmp_info_block(Monitor *mon, const QDict *qdict)
{
BlockInfoList *block_list, *info;
@ -326,7 +326,7 @@ void hmp_info_block(Monitor *mon)
qapi_free_BlockInfoList(block_list);
}
void hmp_info_blockstats(Monitor *mon)
void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
{
BlockStatsList *stats_list, *stats;
@ -360,7 +360,7 @@ void hmp_info_blockstats(Monitor *mon)
qapi_free_BlockStatsList(stats_list);
}
void hmp_info_vnc(Monitor *mon)
void hmp_info_vnc(Monitor *mon, const QDict *qdict)
{
VncInfo *info;
Error *err = NULL;
@ -406,7 +406,7 @@ out:
qapi_free_VncInfo(info);
}
void hmp_info_spice(Monitor *mon)
void hmp_info_spice(Monitor *mon, const QDict *qdict)
{
SpiceChannelList *chan;
SpiceInfo *info;
@ -453,7 +453,7 @@ out:
qapi_free_SpiceInfo(info);
}
void hmp_info_balloon(Monitor *mon)
void hmp_info_balloon(Monitor *mon, const QDict *qdict)
{
BalloonInfo *info;
Error *err = NULL;
@ -465,29 +465,7 @@ void hmp_info_balloon(Monitor *mon)
return;
}
monitor_printf(mon, "balloon: actual=%" PRId64, info->actual >> 20);
if (info->has_mem_swapped_in) {
monitor_printf(mon, " mem_swapped_in=%" PRId64, info->mem_swapped_in);
}
if (info->has_mem_swapped_out) {
monitor_printf(mon, " mem_swapped_out=%" PRId64, info->mem_swapped_out);
}
if (info->has_major_page_faults) {
monitor_printf(mon, " major_page_faults=%" PRId64,
info->major_page_faults);
}
if (info->has_minor_page_faults) {
monitor_printf(mon, " minor_page_faults=%" PRId64,
info->minor_page_faults);
}
if (info->has_free_mem) {
monitor_printf(mon, " free_mem=%" PRId64, info->free_mem);
}
if (info->has_total_mem) {
monitor_printf(mon, " total_mem=%" PRId64, info->total_mem);
}
monitor_printf(mon, "\n");
monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20);
qapi_free_BalloonInfo(info);
}
@ -570,7 +548,7 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
}
}
void hmp_info_pci(Monitor *mon)
void hmp_info_pci(Monitor *mon, const QDict *qdict)
{
PciInfoList *info_list, *info;
Error *err = NULL;
@ -593,7 +571,7 @@ void hmp_info_pci(Monitor *mon)
qapi_free_PciInfoList(info_list);
}
void hmp_info_block_jobs(Monitor *mon)
void hmp_info_block_jobs(Monitor *mon, const QDict *qdict)
{
BlockJobInfoList *list;
Error *err = NULL;
@ -629,6 +607,50 @@ void hmp_info_block_jobs(Monitor *mon)
}
}
void hmp_info_tpm(Monitor *mon, const QDict *qdict)
{
TPMInfoList *info_list, *info;
Error *err = NULL;
unsigned int c = 0;
TPMPassthroughOptions *tpo;
info_list = qmp_query_tpm(&err);
if (err) {
monitor_printf(mon, "TPM device not supported\n");
error_free(err);
return;
}
if (info_list) {
monitor_printf(mon, "TPM device:\n");
}
for (info = info_list; info; info = info->next) {
TPMInfo *ti = info->value;
monitor_printf(mon, " tpm%d: model=%s\n",
c, TpmModel_lookup[ti->model]);
monitor_printf(mon, " \\ %s: type=%s",
ti->id, TpmType_lookup[ti->type]);
switch (ti->tpm_options->kind) {
case TPM_TYPE_OPTIONS_KIND_TPM_PASSTHROUGH_OPTIONS:
tpo = ti->tpm_options->tpm_passthrough_options;
monitor_printf(mon, "%s%s%s%s",
tpo->has_path ? ",path=" : "",
tpo->has_path ? tpo->path : "",
tpo->has_cancel_path ? ",cancel-path=" : "",
tpo->has_cancel_path ? tpo->cancel_path : "");
break;
case TPM_TYPE_OPTIONS_KIND_MAX:
break;
}
monitor_printf(mon, "\n");
c++;
}
qapi_free_TPMInfoList(info_list);
}
void hmp_quit(Monitor *mon, const QDict *qdict)
{
monitor_suspend(mon);
@ -684,6 +706,48 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict)
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 *errp = NULL;
qmp_ringbuf_write(chardev, data, false, 0, &errp);
hmp_handle_error(mon, &errp);
}
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 *errp = NULL;
int i;
data = qmp_ringbuf_read(chardev, size, false, 0, &errp);
if (errp) {
monitor_printf(mon, "%s\n", error_get_pretty(errp));
error_free(errp);
return;
}
for (i = 0; data[i]; i++) {
unsigned char ch = data[i];
if (ch == '\\') {
monitor_printf(mon, "\\\\");
} else if ((ch < 0x20 && ch != '\n' && ch != '\t') || ch == 0x7F) {
monitor_printf(mon, "\\u%04X", ch);
} else {
monitor_printf(mon, "%c", ch);
}
}
monitor_printf(mon, "\n");
g_free(data);
}
static void hmp_cont_cb(void *opaque, int err)
{
if (!err) {
@ -796,7 +860,7 @@ 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,
true, mode, false, 0, false, 0, false, 0,
false, 0, false, 0, &errp);
hmp_handle_error(mon, &errp);
}
@ -880,7 +944,7 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
qapi_free_MigrationCapabilityStatusList(caps);
if (err) {
monitor_printf(mon, "migrate_set_parameter: %s\n",
monitor_printf(mon, "migrate_set_capability: %s\n",
error_get_pretty(err));
error_free(err);
}
@ -1336,3 +1400,26 @@ void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
qmp_nbd_server_stop(&errp);
hmp_handle_error(mon, &errp);
}
void hmp_chardev_add(Monitor *mon, const QDict *qdict)
{
const char *args = qdict_get_str(qdict, "args");
Error *err = NULL;
QemuOpts *opts;
opts = qemu_opts_parse(qemu_find_opts("chardev"), args, 1);
if (opts == NULL) {
error_setg(&err, "Parsing chardev args failed");
} else {
qemu_chr_new_from_opts(opts, NULL, &err);
}
hmp_handle_error(mon, &err);
}
void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
{
Error *local_err = NULL;
qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err);
hmp_handle_error(mon, &local_err);
}

41
hmp.h
View File

@ -18,24 +18,25 @@
#include "qapi-types.h"
#include "qapi/qmp/qdict.h"
void hmp_info_name(Monitor *mon);
void hmp_info_version(Monitor *mon);
void hmp_info_kvm(Monitor *mon);
void hmp_info_status(Monitor *mon);
void hmp_info_uuid(Monitor *mon);
void hmp_info_chardev(Monitor *mon);
void hmp_info_mice(Monitor *mon);
void hmp_info_migrate(Monitor *mon);
void hmp_info_migrate_capabilities(Monitor *mon);
void hmp_info_migrate_cache_size(Monitor *mon);
void hmp_info_cpus(Monitor *mon);
void hmp_info_block(Monitor *mon);
void hmp_info_blockstats(Monitor *mon);
void hmp_info_vnc(Monitor *mon);
void hmp_info_spice(Monitor *mon);
void hmp_info_balloon(Monitor *mon);
void hmp_info_pci(Monitor *mon);
void hmp_info_block_jobs(Monitor *mon);
void hmp_info_name(Monitor *mon, const QDict *qdict);
void hmp_info_version(Monitor *mon, const QDict *qdict);
void hmp_info_kvm(Monitor *mon, const QDict *qdict);
void hmp_info_status(Monitor *mon, const QDict *qdict);
void hmp_info_uuid(Monitor *mon, const QDict *qdict);
void hmp_info_chardev(Monitor *mon, const QDict *qdict);
void hmp_info_mice(Monitor *mon, const QDict *qdict);
void hmp_info_migrate(Monitor *mon, const QDict *qdict);
void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict);
void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict);
void hmp_info_cpus(Monitor *mon, const QDict *qdict);
void hmp_info_block(Monitor *mon, const QDict *qdict);
void hmp_info_blockstats(Monitor *mon, const QDict *qdict);
void hmp_info_vnc(Monitor *mon, const QDict *qdict);
void hmp_info_spice(Monitor *mon, const QDict *qdict);
void hmp_info_balloon(Monitor *mon, const QDict *qdict);
void hmp_info_pci(Monitor *mon, const QDict *qdict);
void hmp_info_block_jobs(Monitor *mon, const QDict *qdict);
void hmp_info_tpm(Monitor *mon, const QDict *qdict);
void hmp_quit(Monitor *mon, const QDict *qdict);
void hmp_stop(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict);
@ -43,6 +44,8 @@ void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
void hmp_cpu(Monitor *mon, const QDict *qdict);
void hmp_memsave(Monitor *mon, const QDict *qdict);
void hmp_pmemsave(Monitor *mon, const QDict *qdict);
void hmp_ringbuf_write(Monitor *mon, const QDict *qdict);
void hmp_ringbuf_read(Monitor *mon, const QDict *qdict);
void hmp_cont(Monitor *mon, const QDict *qdict);
void hmp_system_wakeup(Monitor *mon, const QDict *qdict);
void hmp_inject_nmi(Monitor *mon, const QDict *qdict);
@ -80,5 +83,7 @@ void hmp_screen_dump(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
void hmp_chardev_add(Monitor *mon, const QDict *qdict);
void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
#endif

View File

@ -14,9 +14,9 @@
#include "hw/virtio.h"
#include "hw/pc.h"
#include "qemu/sockets.h"
#include "hw/virtio-pci.h"
#include "virtio-9p.h"
#include "fsdev/qemu-fsdev.h"
#include "virtio-9p-device.h"
#include "virtio-9p-xattr.h"
#include "virtio-9p-coth.h"
@ -85,11 +85,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
}
s->ctx.export_flags = fse->export_flags;
if (fse->path) {
s->ctx.fs_root = g_strdup(fse->path);
} else {
s->ctx.fs_root = NULL;
}
s->ctx.fs_root = g_strdup(fse->path);
s->ctx.exops.get_st_gen = NULL;
len = strlen(conf->tag);
if (len > MAX_TAG_LEN - 1) {
@ -98,7 +94,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
exit(1);
}
s->tag = strdup(conf->tag);
s->tag = g_strdup(conf->tag);
s->ctx.uid = -1;
s->ops = fse->ops;
@ -140,54 +136,3 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
return &s->vdev;
}
static int virtio_9p_init_pci(PCIDevice *pci_dev)
{
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
VirtIODevice *vdev;
vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
vdev->nvectors = proxy->nvectors;
virtio_init_pci(proxy, vdev);
/* make the actual value visible */
proxy->nvectors = vdev->nvectors;
return 0;
}
static Property virtio_9p_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
DEFINE_PROP_END_OF_LIST(),
};
static void virtio_9p_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = virtio_9p_init_pci;
k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
k->device_id = 0x1009;
k->revision = VIRTIO_PCI_ABI_VERSION;
k->class_id = 0x2;
dc->props = virtio_9p_properties;
dc->reset = virtio_pci_reset;
}
static TypeInfo virtio_9p_info = {
.name = "virtio-9p-pci",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(VirtIOPCIProxy),
.class_init = virtio_9p_class_init,
};
static void virtio_9p_register_types(void)
{
type_register_static(&virtio_9p_info);
virtio_9p_set_fd_limit();
}
type_init(virtio_9p_register_types)

View File

@ -11,8 +11,8 @@
*
*/
#ifndef QEMU_9P_H
#define QEMU_9P_H
#ifndef QEMU_VIRTIO_9P_DEVICE_H
#define QEMU_VIRTIO_9P_DEVICE_H
typedef struct V9fsConf
{

View File

@ -46,7 +46,7 @@ static const char *local_mapped_attr_path(FsContext *ctx,
const char *path, char *buffer)
{
char *dir_name;
char *tmp_path = strdup(path);
char *tmp_path = g_strdup(path);
char *base_name = basename(tmp_path);
/* NULL terminate the directory */
@ -55,7 +55,7 @@ static const char *local_mapped_attr_path(FsContext *ctx,
snprintf(buffer, PATH_MAX, "%s/%s/%s/%s",
ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name);
free(tmp_path);
g_free(tmp_path);
return buffer;
}
@ -130,7 +130,7 @@ static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
{
int err;
char attr_dir[PATH_MAX];
char *tmp_path = strdup(path);
char *tmp_path = g_strdup(path);
snprintf(attr_dir, PATH_MAX, "%s/%s/%s",
ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
@ -139,7 +139,7 @@ static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
if (err < 0 && errno == EEXIST) {
err = 0;
}
free(tmp_path);
g_free(tmp_path);
return err;
}

Some files were not shown because too many files have changed in this diff Show More