Compare commits
75 Commits
pull-ui-20
...
v2.7.1
Author | SHA1 | Date | |
---|---|---|---|
|
0d83fccb4f | ||
|
4dde694191 | ||
|
7d17d68971 | ||
|
345f1cd9f6 | ||
|
8d5f2a7570 | ||
|
5f20161cf3 | ||
|
05838b4688 | ||
|
223d1a2da1 | ||
7f7ac2141e | |||
|
db1604cd60 | ||
|
cc1fd25295 | ||
|
ee99e42be4 | ||
|
0ef167c907 | ||
|
248a780fd3 | ||
|
80f630be21 | ||
|
353801cde4 | ||
|
c8a3159df4 | ||
|
48fdfebab6 | ||
|
6eb194ddd7 | ||
|
7e278ef797 | ||
|
6a5ea68e9e | ||
|
31454ebde5 | ||
|
5e4eb851dd | ||
|
dd11d33deb | ||
|
c4bf37e0b0 | ||
|
e9dbd28e2a | ||
|
92230a5963 | ||
|
48b3aa20ae | ||
|
f1372d6e14 | ||
|
63087cd74b | ||
|
9df69dcd14 | ||
|
95a0638043 | ||
|
1790a9d77d | ||
|
1b16ded6a5 | ||
|
ca83f87a66 | ||
|
2817466c55 | ||
|
e389e44a35 | ||
|
b1fdc94193 | ||
|
61781984db | ||
|
857efecf91 | ||
|
99837b0d36 | ||
|
b34c7bd463 | ||
|
f3467f56c1 | ||
|
5be5335661 | ||
|
af29bd3193 | ||
|
f72ca1ac6f | ||
|
4d45fe11d1 | ||
|
4a25ab2a04 | ||
|
95200ebb50 | ||
|
8e94512568 | ||
|
d40d148feb | ||
|
f9856029d5 | ||
|
a3a254550b | ||
|
533dedf059 | ||
|
54c26b7340 | ||
|
f5436d1dab | ||
|
3550eeafcd | ||
|
316c2c9448 | ||
|
98b4465f7d | ||
|
8342e1240b | ||
|
0b6ab25367 | ||
|
742886578d | ||
|
2f8e8c7396 | ||
069e885d83 | |||
|
bfb15f77bb | ||
|
c6a7b922f8 | ||
|
d06c61f310 | ||
|
91a2f46297 | ||
|
520d4b288f | ||
|
4b6542dd17 | ||
|
c1a77fd6fa | ||
|
2e68f28854 | ||
|
45a4f18e2e | ||
|
5c17966605 | ||
|
6ff3ab0d6b |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -53,8 +53,7 @@
|
||||
/qemu-bridge-helper
|
||||
/qemu-monitor.texi
|
||||
/qemu-monitor-info.texi
|
||||
/qemu-version.h
|
||||
/qemu-version.h.tmp
|
||||
/qmp-commands.txt
|
||||
/vscclient
|
||||
/fsdev/virtfs-proxy-helper
|
||||
*.[1-9]
|
||||
|
73
MAINTAINERS
73
MAINTAINERS
@@ -83,7 +83,6 @@ F: include/exec/cpu*.h
|
||||
F: include/exec/exec-all.h
|
||||
F: include/exec/helper*.h
|
||||
F: include/exec/tb-hash.h
|
||||
F: include/sysemu/cpus.h
|
||||
|
||||
FPU emulation
|
||||
M: Aurelien Jarno <aurelien@aurel32.net>
|
||||
@@ -172,7 +171,6 @@ L: qemu-ppc@nongnu.org
|
||||
S: Maintained
|
||||
F: target-ppc/
|
||||
F: hw/ppc/
|
||||
F: include/hw/ppc/
|
||||
F: disas/ppc.c
|
||||
|
||||
S390
|
||||
@@ -189,7 +187,6 @@ S: Odd Fixes
|
||||
F: target-sh4/
|
||||
F: hw/sh4/
|
||||
F: disas/sh4.c
|
||||
F: include/hw/sh4/
|
||||
|
||||
SPARC
|
||||
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
|
||||
@@ -205,7 +202,6 @@ M: Guan Xuetao <gxt@mprc.pku.edu.cn>
|
||||
S: Maintained
|
||||
F: target-unicore32/
|
||||
F: hw/unicore32/
|
||||
F: include/hw/unicore32/
|
||||
|
||||
X86
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
@@ -229,7 +225,6 @@ M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
|
||||
S: Maintained
|
||||
F: target-tricore/
|
||||
F: hw/tricore/
|
||||
F: include/hw/tricore/
|
||||
|
||||
Guest CPU Cores (KVM):
|
||||
----------------------
|
||||
@@ -461,6 +456,7 @@ S: Maintained
|
||||
F: hw/*/xilinx_*
|
||||
F: hw/*/cadence_*
|
||||
F: hw/misc/zynq_slcr.c
|
||||
F: include/hw/xilinx.h
|
||||
X: hw/ssi/xilinx_*
|
||||
|
||||
Xilinx ZynqMP
|
||||
@@ -469,7 +465,7 @@ M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/*/xlnx*.c
|
||||
F: include/hw/*/xlnx*.h
|
||||
F: include/hw/*/xlnx*.c
|
||||
|
||||
ARM ACPI Subsystem
|
||||
M: Shannon Zhao <zhaoshenglong@huawei.com>
|
||||
@@ -575,9 +571,6 @@ L: qemu-ppc@nongnu.org
|
||||
S: Supported
|
||||
F: hw/ppc/e500.[hc]
|
||||
F: hw/ppc/e500plat.c
|
||||
F: include/hw/ppc/ppc_e500.h
|
||||
F: include/hw/pci-host/ppce500.h
|
||||
F: pc-bios/u-boot.e500
|
||||
|
||||
mpc8544ds
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
@@ -595,8 +588,6 @@ F: hw/ppc/mac_newworld.c
|
||||
F: hw/pci-host/uninorth.c
|
||||
F: hw/pci-bridge/dec.[hc]
|
||||
F: hw/misc/macio/
|
||||
F: include/hw/ppc/mac_dbdma.h
|
||||
F: hw/nvram/mac_nvram.c
|
||||
|
||||
Old World
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
@@ -624,14 +615,6 @@ F: include/hw/*/spapr*
|
||||
F: hw/*/xics*
|
||||
F: include/hw/*/xics*
|
||||
F: pc-bios/spapr-rtas/*
|
||||
F: pc-bios/spapr-rtas.bin
|
||||
F: pc-bios/slof.bin
|
||||
F: docs/specs/ppc-spapr-hcalls.txt
|
||||
F: docs/specs/ppc-spapr-hotplug.txt
|
||||
F: tests/spapr*
|
||||
F: tests/libqos/*spapr*
|
||||
F: tests/rtas*
|
||||
F: tests/libqos/rtas*
|
||||
|
||||
virtex_ml507
|
||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
@@ -683,9 +666,6 @@ F: hw/s390x/
|
||||
F: include/hw/s390x/
|
||||
F: pc-bios/s390-ccw/
|
||||
F: hw/watchdog/wdt_diag288.c
|
||||
F: include/hw/watchdog/wdt_diag288.h
|
||||
F: pc-bios/s390-ccw.img
|
||||
F: default-configs/s390x-softmmu.mak
|
||||
T: git git://github.com/cohuck/qemu.git s390-next
|
||||
T: git git://github.com/borntraeger/qemu.git s390-next
|
||||
|
||||
@@ -715,7 +695,7 @@ F: hw/i2c/smbus_ich9.c
|
||||
F: hw/acpi/piix4.c
|
||||
F: hw/acpi/ich9.c
|
||||
F: include/hw/acpi/ich9.h
|
||||
F: include/hw/acpi/piix4.h
|
||||
F: include/hw/acpi/piix.h
|
||||
F: hw/misc/sga.c
|
||||
|
||||
PC Chipset
|
||||
@@ -735,10 +715,6 @@ F: hw/misc/pc-testdev.c
|
||||
F: hw/timer/hpet*
|
||||
F: hw/timer/i8254*
|
||||
F: hw/timer/mc146818rtc*
|
||||
F: include/hw/i2c/pm_smbus.h
|
||||
F: include/hw/timer/hpet.h
|
||||
F: include/hw/timer/i8254*
|
||||
F: include/hw/timer/mc146818rtc*
|
||||
|
||||
Machine core
|
||||
M: Eduardo Habkost <ehabkost@redhat.com>
|
||||
@@ -821,15 +797,16 @@ F: hw/mem/*
|
||||
F: hw/acpi/*
|
||||
F: hw/smbios/*
|
||||
F: hw/i386/acpi-build.[hc]
|
||||
F: hw/i386/*dsl
|
||||
F: hw/arm/virt-acpi-build.c
|
||||
F: include/hw/arm/virt-acpi-build.h
|
||||
F: scripts/acpi*py
|
||||
|
||||
ppc4xx
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/ppc/ppc4*.c
|
||||
F: include/hw/ppc/ppc4xx.h
|
||||
|
||||
ppce500
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
@@ -849,15 +826,13 @@ Network devices
|
||||
M: Jason Wang <jasowang@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: hw/net/
|
||||
F: tests/virtio-net-test.c
|
||||
T: git git://github.com/jasowang/qemu.git net
|
||||
|
||||
SCSI
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
S: Supported
|
||||
F: include/hw/scsi/*
|
||||
F: include/hw/scsi*
|
||||
F: hw/scsi/*
|
||||
F: tests/virtio-scsi-test.c
|
||||
T: git git://github.com/bonzini/qemu.git scsi-next
|
||||
|
||||
LSI53C895A
|
||||
@@ -910,7 +885,6 @@ S: Supported
|
||||
F: hw/*/virtio*
|
||||
F: net/vhost-user.c
|
||||
F: include/hw/virtio/
|
||||
F: tests/virtio-balloon-test.c
|
||||
|
||||
virtio-9p
|
||||
M: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
||||
@@ -928,7 +902,7 @@ L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: hw/block/virtio-blk.c
|
||||
F: hw/block/dataplane/*
|
||||
F: tests/virtio-blk-test.c
|
||||
F: hw/virtio/dataplane/*
|
||||
T: git git://github.com/stefanha/qemu.git block
|
||||
|
||||
virtio-ccw
|
||||
@@ -951,8 +925,6 @@ S: Supported
|
||||
F: hw/char/virtio-serial-bus.c
|
||||
F: hw/char/virtio-console.c
|
||||
F: include/hw/virtio/virtio-serial.h
|
||||
F: tests/virtio-console-test.c
|
||||
F: tests/virtio-serial-test.c
|
||||
|
||||
virtio-rng
|
||||
M: Amit Shah <amit.shah@redhat.com>
|
||||
@@ -961,7 +933,6 @@ F: hw/virtio/virtio-rng.c
|
||||
F: include/hw/virtio/virtio-rng.h
|
||||
F: include/sysemu/rng*.h
|
||||
F: backends/rng*.c
|
||||
F: tests/virtio-rng-test.c
|
||||
|
||||
nvme
|
||||
M: Keith Busch <keith.busch@intel.com>
|
||||
@@ -1093,6 +1064,12 @@ S: Supported
|
||||
F: qom/cpu.c
|
||||
F: include/qom/cpu.h
|
||||
|
||||
ICC Bus
|
||||
M: Igor Mammedov <imammedo@redhat.com>
|
||||
S: Supported
|
||||
F: include/hw/cpu/icc_bus.h
|
||||
F: hw/cpu/icc_bus.c
|
||||
|
||||
Device Tree
|
||||
M: Peter Crosthwaite <crosthwaite.peter@gmail.com>
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
@@ -1260,6 +1237,7 @@ M: Markus Armbruster <armbru@redhat.com>
|
||||
S: Supported
|
||||
F: qmp.c
|
||||
F: monitor.c
|
||||
F: qmp-commands.hx
|
||||
F: docs/*qmp-*
|
||||
F: scripts/qmp/
|
||||
T: git git://repo.or.cz/qemu/armbru.git qapi-next
|
||||
@@ -1279,11 +1257,6 @@ F: net/slirp.c
|
||||
F: include/net/slirp.h
|
||||
T: git git://git.kiszka.org/qemu.git queues/slirp
|
||||
|
||||
Stubs
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
S: Maintained
|
||||
F: stubs/
|
||||
|
||||
Tracing
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
S: Maintained
|
||||
@@ -1357,13 +1330,6 @@ F: include/qemu/throttle.h
|
||||
F: util/throttle.c
|
||||
L: qemu-block@nongnu.org
|
||||
|
||||
UUID
|
||||
M: Fam Zheng <famz@redhat.com>
|
||||
S: Supported
|
||||
F: util/uuid.c
|
||||
F: include/qemu/uuid.h
|
||||
F: tests/test-uuid.c
|
||||
|
||||
Usermode Emulation
|
||||
------------------
|
||||
Overall
|
||||
@@ -1614,7 +1580,7 @@ M: Kevin Wolf <kwolf@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/linux-aio.c
|
||||
F: include/block/raw-aio.h
|
||||
F: block/raw-aio.h
|
||||
F: block/raw-posix.c
|
||||
F: block/raw-win32.c
|
||||
F: block/raw_bsd.c
|
||||
@@ -1658,15 +1624,6 @@ L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: tests/image-fuzzer/
|
||||
|
||||
Replication
|
||||
M: Wen Congyang <wency@cn.fujitsu.com>
|
||||
M: Changlong Xie <xiecl.fnst@cn.fujitsu.com>
|
||||
S: Supported
|
||||
F: replication*
|
||||
F: block/replication.c
|
||||
F: tests/test-replication.c
|
||||
F: docs/block-replication.txt
|
||||
|
||||
Build and test automation
|
||||
-------------------------
|
||||
M: Alex Bennée <alex.bennee@linaro.org>
|
||||
|
55
Makefile
55
Makefile
@@ -76,8 +76,6 @@ GENERATED_HEADERS += trace/generated-ust-provider.h
|
||||
GENERATED_SOURCES += trace/generated-ust.c
|
||||
endif
|
||||
|
||||
GENERATED_HEADERS += module_block.h
|
||||
|
||||
# Don't try to regenerate Makefile or configure
|
||||
# We don't generate any of them
|
||||
Makefile: ;
|
||||
@@ -94,6 +92,7 @@ HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
|
||||
|
||||
ifdef BUILD_DOCS
|
||||
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8
|
||||
DOCS+=qmp-commands.txt
|
||||
ifdef CONFIG_VIRTFS
|
||||
DOCS+=fsdev/virtfs-proxy-helper.1
|
||||
endif
|
||||
@@ -247,6 +246,9 @@ Makefile: $(version-obj-y) $(version-lobj-y)
|
||||
libqemustub.a: $(stub-obj-y)
|
||||
libqemuutil.a: $(util-obj-y)
|
||||
|
||||
block-modules = $(foreach o,$(block-obj-m),"$(basename $(subst /,-,$o))",) NULL
|
||||
util/module.o-cflags = -D'CONFIG_BLOCK_MODULES=$(block-modules)'
|
||||
|
||||
######################################################################
|
||||
|
||||
qemu-img.o: qemu-img-cmds.h
|
||||
@@ -310,7 +312,7 @@ $(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py)
|
||||
qmp-commands.h qmp-marshal.c :\
|
||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
|
||||
$(gen-out-type) -o "." $<, \
|
||||
$(gen-out-type) -o "." -m $<, \
|
||||
" GEN $@")
|
||||
qmp-introspect.h qmp-introspect.c :\
|
||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
|
||||
@@ -351,11 +353,6 @@ ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) libqemuutil.a libqemustub.a
|
||||
ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) libqemuutil.a libqemustub.a
|
||||
$(call LINK, $^)
|
||||
|
||||
module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak
|
||||
$(call quiet-command,$(PYTHON) $< $@ \
|
||||
$(addprefix $(SRC_PATH)/,$(patsubst %.mo,%.c,$(block-obj-m))), \
|
||||
" GEN $@")
|
||||
|
||||
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
|
||||
@@ -435,7 +432,7 @@ endif
|
||||
install-doc: $(DOCS)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) $(SRC_PATH)/docs/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
ifdef CONFIG_POSIX
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1"
|
||||
@@ -558,6 +555,9 @@ qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool
|
||||
qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
|
||||
|
||||
qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -q < $< > $@," GEN $@")
|
||||
|
||||
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
|
||||
|
||||
@@ -669,40 +669,3 @@ endif
|
||||
-include $(wildcard *.d tests/*.d)
|
||||
|
||||
include $(SRC_PATH)/tests/docker/Makefile.include
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo 'Generic targets:'
|
||||
@echo ' all - Build all'
|
||||
@echo ' dir/file.o - Build specified target only'
|
||||
@echo ' install - Install QEMU, documentation and tools'
|
||||
@echo ' ctags/TAGS - Generate tags file for editors'
|
||||
@echo ' cscope - Generate cscope index'
|
||||
@echo ''
|
||||
@$(if $(TARGET_DIRS), \
|
||||
echo 'Architecture specific targets:'; \
|
||||
$(foreach t, $(TARGET_DIRS), \
|
||||
printf " %-30s - Build for %s\\n" $(patsubst %,subdir-%,$(t)) $(t);) \
|
||||
echo '')
|
||||
@echo 'Cleaning targets:'
|
||||
@echo ' clean - Remove most generated files but keep the config'
|
||||
@echo ' distclean - Remove all generated files'
|
||||
@echo ' dist - Build a distributable tarball'
|
||||
@echo ''
|
||||
@echo 'Test targets:'
|
||||
@echo ' check - Run all tests (check-help for details)'
|
||||
@echo ' docker - Help about targets running tests inside Docker containers'
|
||||
@echo ''
|
||||
@echo 'Documentation targets:'
|
||||
@echo ' dvi html info pdf'
|
||||
@echo ' - Build documentation in specified format'
|
||||
@echo ''
|
||||
ifdef CONFIG_WIN32
|
||||
@echo 'Windows targets:'
|
||||
@echo ' installer - Build NSIS-based installer for qemu-ga'
|
||||
ifdef QEMU_GA_MSI_ENABLED
|
||||
@echo ' msi - Build MSI-based installer for qemu-ga'
|
||||
endif
|
||||
@echo ''
|
||||
endif
|
||||
@echo ' make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build'
|
||||
|
@@ -15,7 +15,6 @@ block-obj-$(CONFIG_POSIX) += aio-posix.o
|
||||
block-obj-$(CONFIG_WIN32) += aio-win32.o
|
||||
block-obj-y += block/
|
||||
block-obj-y += qemu-io-cmds.o
|
||||
block-obj-$(CONFIG_REPLICATION) += replication.o
|
||||
|
||||
block-obj-m = block/
|
||||
|
||||
|
@@ -156,7 +156,7 @@ else
|
||||
obj-y += hw/$(TARGET_BASE_ARCH)/
|
||||
endif
|
||||
|
||||
GENERATED_HEADERS += hmp-commands.h hmp-commands-info.h
|
||||
GENERATED_HEADERS += hmp-commands.h hmp-commands-info.h qmp-commands-old.h
|
||||
|
||||
endif # CONFIG_SOFTMMU
|
||||
|
||||
@@ -209,10 +209,13 @@ hmp-commands.h: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool
|
||||
hmp-commands-info.h: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
|
||||
|
||||
clean: clean-target
|
||||
qmp-commands-old.h: $(SRC_PATH)/qmp-commands.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
|
||||
|
||||
clean:
|
||||
rm -f *.a *~ $(PROGS)
|
||||
rm -f $(shell find . -name '*.[od]')
|
||||
rm -f hmp-commands.h gdbstub-xml.c
|
||||
rm -f hmp-commands.h qmp-commands-old.h gdbstub-xml.c
|
||||
ifdef CONFIG_TRACE_SYSTEMTAP
|
||||
rm -f *.stp
|
||||
endif
|
||||
|
19
arch_init.c
19
arch_init.c
@@ -235,6 +235,25 @@ void audio_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
int qemu_uuid_parse(const char *str, uint8_t *uuid)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (strlen(str) != 36) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = sscanf(str, UUID_FMT, &uuid[0], &uuid[1], &uuid[2], &uuid[3],
|
||||
&uuid[4], &uuid[5], &uuid[6], &uuid[7], &uuid[8], &uuid[9],
|
||||
&uuid[10], &uuid[11], &uuid[12], &uuid[13], &uuid[14],
|
||||
&uuid[15]);
|
||||
|
||||
if (ret != 16) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void do_acpitable_option(const QemuOpts *opts)
|
||||
{
|
||||
#ifdef TARGET_I386
|
||||
|
@@ -41,9 +41,7 @@ static void rng_egd_request_entropy(RngBackend *b, RngRequest *req)
|
||||
header[0] = 0x02;
|
||||
header[1] = len;
|
||||
|
||||
/* XXX this blocks entire thread. Rewrite to use
|
||||
* qemu_chr_fe_write and background I/O callbacks */
|
||||
qemu_chr_fe_write_all(s->chr, header, sizeof(header));
|
||||
qemu_chr_fe_write(s->chr, header, sizeof(header));
|
||||
|
||||
size -= len;
|
||||
}
|
||||
|
170
block.c
170
block.c
@@ -25,9 +25,7 @@
|
||||
#include "trace.h"
|
||||
#include "block/block_int.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "block/nbd.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "module_block.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
@@ -243,40 +241,17 @@ BlockDriverState *bdrv_new(void)
|
||||
return bs;
|
||||
}
|
||||
|
||||
static BlockDriver *bdrv_do_find_format(const char *format_name)
|
||||
BlockDriver *bdrv_find_format(const char *format_name)
|
||||
{
|
||||
BlockDriver *drv1;
|
||||
|
||||
QLIST_FOREACH(drv1, &bdrv_drivers, list) {
|
||||
if (!strcmp(drv1->format_name, format_name)) {
|
||||
return drv1;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BlockDriver *bdrv_find_format(const char *format_name)
|
||||
{
|
||||
BlockDriver *drv1;
|
||||
int i;
|
||||
|
||||
drv1 = bdrv_do_find_format(format_name);
|
||||
if (drv1) {
|
||||
return drv1;
|
||||
}
|
||||
|
||||
/* The driver isn't registered, maybe we need to load a module */
|
||||
for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) {
|
||||
if (!strcmp(block_driver_modules[i].format_name, format_name)) {
|
||||
block_module_load_one(block_driver_modules[i].library_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bdrv_do_find_format(format_name);
|
||||
}
|
||||
|
||||
static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
|
||||
{
|
||||
static const char *whitelist_rw[] = {
|
||||
@@ -485,19 +460,6 @@ static BlockDriver *find_hdev_driver(const char *filename)
|
||||
return drv;
|
||||
}
|
||||
|
||||
static BlockDriver *bdrv_do_find_protocol(const char *protocol)
|
||||
{
|
||||
BlockDriver *drv1;
|
||||
|
||||
QLIST_FOREACH(drv1, &bdrv_drivers, list) {
|
||||
if (drv1->protocol_name && !strcmp(drv1->protocol_name, protocol)) {
|
||||
return drv1;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BlockDriver *bdrv_find_protocol(const char *filename,
|
||||
bool allow_protocol_prefix,
|
||||
Error **errp)
|
||||
@@ -506,7 +468,6 @@ BlockDriver *bdrv_find_protocol(const char *filename,
|
||||
char protocol[128];
|
||||
int len;
|
||||
const char *p;
|
||||
int i;
|
||||
|
||||
/* TODO Drivers without bdrv_file_open must be specified explicitly */
|
||||
|
||||
@@ -533,25 +494,15 @@ BlockDriver *bdrv_find_protocol(const char *filename,
|
||||
len = sizeof(protocol) - 1;
|
||||
memcpy(protocol, filename, len);
|
||||
protocol[len] = '\0';
|
||||
|
||||
drv1 = bdrv_do_find_protocol(protocol);
|
||||
if (drv1) {
|
||||
return drv1;
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) {
|
||||
if (block_driver_modules[i].protocol_name &&
|
||||
!strcmp(block_driver_modules[i].protocol_name, protocol)) {
|
||||
block_module_load_one(block_driver_modules[i].library_name);
|
||||
break;
|
||||
QLIST_FOREACH(drv1, &bdrv_drivers, list) {
|
||||
if (drv1->protocol_name &&
|
||||
!strcmp(drv1->protocol_name, protocol)) {
|
||||
return drv1;
|
||||
}
|
||||
}
|
||||
|
||||
drv1 = bdrv_do_find_protocol(protocol);
|
||||
if (!drv1) {
|
||||
error_setg(errp, "Unknown protocol '%s'", protocol);
|
||||
}
|
||||
return drv1;
|
||||
error_setg(errp, "Unknown protocol '%s'", protocol);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -733,9 +684,6 @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options,
|
||||
qdict_set_default_str(child_options, BDRV_OPT_CACHE_DIRECT, "off");
|
||||
qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
|
||||
|
||||
/* Copy the read-only option from the parent */
|
||||
qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
|
||||
|
||||
/* aio=native doesn't work for cache.direct=off, so disable it for the
|
||||
* temporary snapshot */
|
||||
*child_flags &= ~BDRV_O_NATIVE_AIO;
|
||||
@@ -758,9 +706,6 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,
|
||||
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
|
||||
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
|
||||
|
||||
/* Inherit the read-only option from the parent if it's not set */
|
||||
qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
|
||||
|
||||
/* Our block drivers take care to send flushes and respect unmap policy,
|
||||
* so we can default to enable both on lower layers regardless of the
|
||||
* corresponding parent options. */
|
||||
@@ -814,8 +759,7 @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
|
||||
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
|
||||
|
||||
/* backing files always opened read-only */
|
||||
qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on");
|
||||
flags &= ~BDRV_O_COPY_ON_READ;
|
||||
flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ);
|
||||
|
||||
/* snapshot=on is handled on the top layer */
|
||||
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
|
||||
@@ -862,14 +806,6 @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
|
||||
if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
|
||||
*flags |= BDRV_O_NOCACHE;
|
||||
}
|
||||
|
||||
*flags &= ~BDRV_O_RDWR;
|
||||
|
||||
assert(qemu_opt_find(opts, BDRV_OPT_READ_ONLY));
|
||||
if (!qemu_opt_get_bool(opts, BDRV_OPT_READ_ONLY, false)) {
|
||||
*flags |= BDRV_O_RDWR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void update_options_from_flags(QDict *options, int flags)
|
||||
@@ -882,10 +818,6 @@ static void update_options_from_flags(QDict *options, int flags)
|
||||
qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH,
|
||||
qbool_from_bool(flags & BDRV_O_NO_FLUSH));
|
||||
}
|
||||
if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) {
|
||||
qdict_put(options, BDRV_OPT_READ_ONLY,
|
||||
qbool_from_bool(!(flags & BDRV_O_RDWR)));
|
||||
}
|
||||
}
|
||||
|
||||
static void bdrv_assign_node_name(BlockDriverState *bs,
|
||||
@@ -949,11 +881,6 @@ static QemuOptsList bdrv_runtime_opts = {
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Ignore flush requests",
|
||||
},
|
||||
{
|
||||
.name = BDRV_OPT_READ_ONLY,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Node is opened in read-only mode",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@@ -985,8 +912,6 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
|
||||
goto fail_opts;
|
||||
}
|
||||
|
||||
update_flags_from_options(&bs->open_flags, opts);
|
||||
|
||||
driver_name = qemu_opt_get(opts, "driver");
|
||||
drv = bdrv_find_format(driver_name);
|
||||
assert(drv != NULL);
|
||||
@@ -1048,6 +973,9 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
|
||||
bs->drv = drv;
|
||||
bs->opaque = g_malloc0(drv->instance_size);
|
||||
|
||||
/* Apply cache mode options */
|
||||
update_flags_from_options(&bs->open_flags, opts);
|
||||
|
||||
/* Open the image, either directly or using a protocol */
|
||||
open_flags = bdrv_open_flags(bs, bs->open_flags);
|
||||
if (drv->bdrv_file_open) {
|
||||
@@ -1383,23 +1311,6 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
|
||||
/* Otherwise we won't be able to commit due to check in bdrv_commit */
|
||||
bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET,
|
||||
bs->backing_blocker);
|
||||
/*
|
||||
* We do backup in 3 ways:
|
||||
* 1. drive backup
|
||||
* The target bs is new opened, and the source is top BDS
|
||||
* 2. blockdev backup
|
||||
* Both the source and the target are top BDSes.
|
||||
* 3. internal backup(used for block replication)
|
||||
* Both the source and the target are backing file
|
||||
*
|
||||
* In case 1 and 2, neither the source nor the target is the backing file.
|
||||
* In case 3, we will block the top BDS, so there is only one block job
|
||||
* for the top BDS and its backing chain.
|
||||
*/
|
||||
bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_SOURCE,
|
||||
bs->backing_blocker);
|
||||
bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_TARGET,
|
||||
bs->backing_blocker);
|
||||
out:
|
||||
bdrv_refresh_limits(bs, NULL);
|
||||
}
|
||||
@@ -1698,25 +1609,6 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Set the BDRV_O_RDWR and BDRV_O_ALLOW_RDWR flags.
|
||||
* FIXME: we're parsing the QDict to avoid having to create a
|
||||
* QemuOpts just for this, but neither option is optimal. */
|
||||
if (g_strcmp0(qdict_get_try_str(options, BDRV_OPT_READ_ONLY), "on") &&
|
||||
!qdict_get_try_bool(options, BDRV_OPT_READ_ONLY, false)) {
|
||||
flags |= (BDRV_O_RDWR | BDRV_O_ALLOW_RDWR);
|
||||
} else {
|
||||
flags &= ~BDRV_O_RDWR;
|
||||
}
|
||||
|
||||
if (flags & BDRV_O_SNAPSHOT) {
|
||||
snapshot_options = qdict_new();
|
||||
bdrv_temp_snapshot_options(&snapshot_flags, snapshot_options,
|
||||
flags, options);
|
||||
/* Let bdrv_backing_options() override "read-only" */
|
||||
qdict_del(options, BDRV_OPT_READ_ONLY);
|
||||
bdrv_backing_options(&flags, options, flags, options);
|
||||
}
|
||||
|
||||
bs->open_flags = flags;
|
||||
bs->options = options;
|
||||
options = qdict_clone_shallow(options);
|
||||
@@ -1741,6 +1633,18 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
|
||||
|
||||
/* Open image file without format layer */
|
||||
if ((flags & BDRV_O_PROTOCOL) == 0) {
|
||||
if (flags & BDRV_O_RDWR) {
|
||||
flags |= BDRV_O_ALLOW_RDWR;
|
||||
}
|
||||
if (flags & BDRV_O_SNAPSHOT) {
|
||||
snapshot_options = qdict_new();
|
||||
bdrv_temp_snapshot_options(&snapshot_flags, snapshot_options,
|
||||
flags, options);
|
||||
bdrv_backing_options(&flags, options, flags, options);
|
||||
}
|
||||
|
||||
bs->open_flags = flags;
|
||||
|
||||
file = bdrv_open_child(filename, options, "file", bs,
|
||||
&child_file, true, &local_err);
|
||||
if (local_err) {
|
||||
@@ -1925,13 +1829,6 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
|
||||
options = qdict_new();
|
||||
}
|
||||
|
||||
/* Check if this BlockDriverState is already in the queue */
|
||||
QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
|
||||
if (bs == bs_entry->state.bs) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Precedence of options:
|
||||
* 1. Explicitly passed in options (highest)
|
||||
@@ -1952,11 +1849,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
|
||||
}
|
||||
|
||||
/* Old explicitly set values (don't overwrite by inherited value) */
|
||||
if (bs_entry) {
|
||||
old_options = qdict_clone_shallow(bs_entry->state.explicit_options);
|
||||
} else {
|
||||
old_options = qdict_clone_shallow(bs->explicit_options);
|
||||
}
|
||||
old_options = qdict_clone_shallow(bs->explicit_options);
|
||||
bdrv_join_options(bs, options, old_options);
|
||||
QDECREF(old_options);
|
||||
|
||||
@@ -1995,13 +1888,8 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
|
||||
child->role, options, flags);
|
||||
}
|
||||
|
||||
if (!bs_entry) {
|
||||
bs_entry = g_new0(BlockReopenQueueEntry, 1);
|
||||
QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry);
|
||||
} else {
|
||||
QDECREF(bs_entry->state.options);
|
||||
QDECREF(bs_entry->state.explicit_options);
|
||||
}
|
||||
bs_entry = g_new0(BlockReopenQueueEntry, 1);
|
||||
QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry);
|
||||
|
||||
bs_entry->state.bs = bs;
|
||||
bs_entry->state.options = options;
|
||||
@@ -2318,7 +2206,6 @@ static void bdrv_close(BlockDriverState *bs)
|
||||
void bdrv_close_all(void)
|
||||
{
|
||||
block_job_cancel_sync_all();
|
||||
nbd_export_close_all();
|
||||
|
||||
/* Drop references from requests still in flight, such as canceled block
|
||||
* jobs whose AIO context has not been polled yet */
|
||||
@@ -3059,6 +2946,11 @@ bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag)
|
||||
return false;
|
||||
}
|
||||
|
||||
int bdrv_is_snapshot(BlockDriverState *bs)
|
||||
{
|
||||
return !!(bs->open_flags & BDRV_O_SNAPSHOT);
|
||||
}
|
||||
|
||||
/* backing_file can either be relative, or absolute, or a protocol. If it is
|
||||
* relative, it must be relative to the chain. So, passing in bs->filename
|
||||
* from a BDS as backing_file should not be done, as that may be relative to
|
||||
|
@@ -1,8 +1,8 @@
|
||||
block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o
|
||||
block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o
|
||||
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
|
||||
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
|
||||
block-obj-y += qed-check.o
|
||||
block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
|
||||
block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o
|
||||
block-obj-y += quorum.o
|
||||
block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o
|
||||
block-obj-y += block-backend.o snapshot.o qapi.o
|
||||
@@ -22,14 +22,12 @@ block-obj-$(CONFIG_ARCHIPELAGO) += archipelago.o
|
||||
block-obj-$(CONFIG_LIBSSH2) += ssh.o
|
||||
block-obj-y += accounting.o dirty-bitmap.o
|
||||
block-obj-y += write-threshold.o
|
||||
block-obj-y += backup.o
|
||||
block-obj-$(CONFIG_REPLICATION) += replication.o
|
||||
|
||||
block-obj-y += crypto.o
|
||||
|
||||
common-obj-y += stream.o
|
||||
common-obj-y += backup.o
|
||||
|
||||
nfs.o-libs := $(LIBNFS_LIBS)
|
||||
iscsi.o-cflags := $(LIBISCSI_CFLAGS)
|
||||
iscsi.o-libs := $(LIBISCSI_LIBS)
|
||||
curl.o-cflags := $(CURL_CFLAGS)
|
||||
@@ -41,6 +39,7 @@ gluster.o-libs := $(GLUSTERFS_LIBS)
|
||||
ssh.o-cflags := $(LIBSSH2_CFLAGS)
|
||||
ssh.o-libs := $(LIBSSH2_LIBS)
|
||||
archipelago.o-libs := $(ARCHIPELAGO_LIBS)
|
||||
block-obj-m += dmg.o
|
||||
dmg.o-libs := $(BZIP2_LIBS)
|
||||
qcow.o-libs := -lz
|
||||
linux-aio.o-libs := -laio
|
||||
|
@@ -17,7 +17,6 @@
|
||||
#include "block/block.h"
|
||||
#include "block/block_int.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "block/block_backup.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/ratelimit.h"
|
||||
@@ -28,6 +27,13 @@
|
||||
#define BACKUP_CLUSTER_SIZE_DEFAULT (1 << 16)
|
||||
#define SLICE_TIME 100000000ULL /* ns */
|
||||
|
||||
typedef struct CowRequest {
|
||||
int64_t start;
|
||||
int64_t end;
|
||||
QLIST_ENTRY(CowRequest) list;
|
||||
CoQueue wait_queue; /* coroutines blocked on this request */
|
||||
} CowRequest;
|
||||
|
||||
typedef struct BackupBlockJob {
|
||||
BlockJob common;
|
||||
BlockBackend *target;
|
||||
@@ -41,7 +47,6 @@ typedef struct BackupBlockJob {
|
||||
uint64_t sectors_read;
|
||||
unsigned long *done_bitmap;
|
||||
int64_t cluster_size;
|
||||
bool compress;
|
||||
NotifierWithReturn before_write;
|
||||
QLIST_HEAD(, CowRequest) inflight_reqs;
|
||||
} BackupBlockJob;
|
||||
@@ -149,8 +154,7 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
|
||||
bounce_qiov.size, BDRV_REQ_MAY_UNMAP);
|
||||
} else {
|
||||
ret = blk_co_pwritev(job->target, start * job->cluster_size,
|
||||
bounce_qiov.size, &bounce_qiov,
|
||||
job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0);
|
||||
bounce_qiov.size, &bounce_qiov, 0);
|
||||
}
|
||||
if (ret < 0) {
|
||||
trace_backup_do_cow_write_fail(job, start, ret);
|
||||
@@ -249,57 +253,6 @@ static void backup_attached_aio_context(BlockJob *job, AioContext *aio_context)
|
||||
blk_set_aio_context(s->target, aio_context);
|
||||
}
|
||||
|
||||
void backup_do_checkpoint(BlockJob *job, Error **errp)
|
||||
{
|
||||
BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
|
||||
int64_t len;
|
||||
|
||||
assert(job->driver->job_type == BLOCK_JOB_TYPE_BACKUP);
|
||||
|
||||
if (backup_job->sync_mode != MIRROR_SYNC_MODE_NONE) {
|
||||
error_setg(errp, "The backup job only supports block checkpoint in"
|
||||
" sync=none mode");
|
||||
return;
|
||||
}
|
||||
|
||||
len = DIV_ROUND_UP(backup_job->common.len, backup_job->cluster_size);
|
||||
bitmap_zero(backup_job->done_bitmap, len);
|
||||
}
|
||||
|
||||
void backup_wait_for_overlapping_requests(BlockJob *job, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
|
||||
int64_t sectors_per_cluster = cluster_size_sectors(backup_job);
|
||||
int64_t start, end;
|
||||
|
||||
assert(job->driver->job_type == BLOCK_JOB_TYPE_BACKUP);
|
||||
|
||||
start = sector_num / sectors_per_cluster;
|
||||
end = DIV_ROUND_UP(sector_num + nb_sectors, sectors_per_cluster);
|
||||
wait_for_overlapping_requests(backup_job, start, end);
|
||||
}
|
||||
|
||||
void backup_cow_request_begin(CowRequest *req, BlockJob *job,
|
||||
int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
|
||||
int64_t sectors_per_cluster = cluster_size_sectors(backup_job);
|
||||
int64_t start, end;
|
||||
|
||||
assert(job->driver->job_type == BLOCK_JOB_TYPE_BACKUP);
|
||||
|
||||
start = sector_num / sectors_per_cluster;
|
||||
end = DIV_ROUND_UP(sector_num + nb_sectors, sectors_per_cluster);
|
||||
cow_request_begin(req, backup_job, start, end);
|
||||
}
|
||||
|
||||
void backup_cow_request_end(CowRequest *req)
|
||||
{
|
||||
cow_request_end(req);
|
||||
}
|
||||
|
||||
static const BlockJobDriver backup_job_driver = {
|
||||
.instance_size = sizeof(BackupBlockJob),
|
||||
.job_type = BLOCK_JOB_TYPE_BACKUP,
|
||||
@@ -524,7 +477,6 @@ static void coroutine_fn backup_run(void *opaque)
|
||||
void backup_start(const char *job_id, BlockDriverState *bs,
|
||||
BlockDriverState *target, int64_t speed,
|
||||
MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap,
|
||||
bool compress,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
BlockCompletionFunc *cb, void *opaque,
|
||||
@@ -555,12 +507,6 @@ void backup_start(const char *job_id, BlockDriverState *bs,
|
||||
return;
|
||||
}
|
||||
|
||||
if (compress && target->drv->bdrv_co_pwritev_compressed == NULL) {
|
||||
error_setg(errp, "Compression is not supported for this drive %s",
|
||||
bdrv_get_device_name(target));
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
|
||||
return;
|
||||
}
|
||||
@@ -609,7 +555,6 @@ void backup_start(const char *job_id, BlockDriverState *bs,
|
||||
job->sync_mode = sync_mode;
|
||||
job->sync_bitmap = sync_mode == MIRROR_SYNC_MODE_INCREMENTAL ?
|
||||
sync_bitmap : NULL;
|
||||
job->compress = compress;
|
||||
|
||||
/* If there is no backing file on the target, we cannot rely on COW if our
|
||||
* backup cluster size is smaller than the target cluster size. Even for
|
||||
|
@@ -409,22 +409,6 @@ bool bdrv_has_blk(BlockDriverState *bs)
|
||||
return bdrv_first_blk(bs) != NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if @bs has only BlockBackends as parents.
|
||||
*/
|
||||
bool bdrv_is_root_node(BlockDriverState *bs)
|
||||
{
|
||||
BdrvChild *c;
|
||||
|
||||
QLIST_FOREACH(c, &bs->parents, next_parent) {
|
||||
if (c->role != &child_root) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return @blk's DriveInfo if any, else null.
|
||||
*/
|
||||
@@ -559,25 +543,6 @@ void *blk_get_attached_dev(BlockBackend *blk)
|
||||
return blk->dev;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the BlockBackend which has the device model @dev attached if it
|
||||
* exists, else null.
|
||||
*
|
||||
* @dev must not be null.
|
||||
*/
|
||||
BlockBackend *blk_by_dev(void *dev)
|
||||
{
|
||||
BlockBackend *blk = NULL;
|
||||
|
||||
assert(dev != NULL);
|
||||
while ((blk = blk_all_next(blk)) != NULL) {
|
||||
if (blk->dev == dev) {
|
||||
return blk;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set @blk's device model callbacks to @ops.
|
||||
* @opaque is the opaque argument to pass to the callbacks.
|
||||
@@ -762,6 +727,21 @@ static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blk_check_request(BlockBackend *blk, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
if (sector_num < 0 || sector_num > INT64_MAX / BDRV_SECTOR_SIZE) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (nb_sectors < 0 || nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return blk_check_byte_request(blk, sector_num * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
|
||||
unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
@@ -1316,6 +1296,11 @@ void blk_eject(BlockBackend *blk, bool eject_flag)
|
||||
if (bs) {
|
||||
bdrv_eject(bs, eject_flag);
|
||||
}
|
||||
|
||||
/* Whether or not we ejected on the backend,
|
||||
* the frontend experienced a tray event. */
|
||||
qapi_event_send_device_tray_moved(blk_name(blk),
|
||||
eject_flag, &error_abort);
|
||||
}
|
||||
|
||||
int blk_get_flags(BlockBackend *blk)
|
||||
@@ -1504,11 +1489,15 @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
|
||||
flags | BDRV_REQ_ZERO_WRITE);
|
||||
}
|
||||
|
||||
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
|
||||
int count)
|
||||
int blk_write_compressed(BlockBackend *blk, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
return blk_prw(blk, offset, (void *) buf, count, blk_write_entry,
|
||||
BDRV_REQ_WRITE_COMPRESSED);
|
||||
int ret = blk_check_request(blk, sector_num, nb_sectors);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return bdrv_write_compressed(blk_bs(blk), sector_num, buf, nb_sectors);
|
||||
}
|
||||
|
||||
int blk_truncate(BlockBackend *blk, int64_t offset)
|
||||
@@ -1640,28 +1629,6 @@ int blk_commit_all(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blk_flush_all(void)
|
||||
{
|
||||
BlockBackend *blk = NULL;
|
||||
int result = 0;
|
||||
|
||||
while ((blk = blk_all_next(blk)) != NULL) {
|
||||
AioContext *aio_context = blk_get_aio_context(blk);
|
||||
int ret;
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
if (blk_is_inserted(blk)) {
|
||||
ret = blk_flush(blk);
|
||||
if (ret < 0 && !result) {
|
||||
result = ret;
|
||||
}
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* throttling disk I/O limits */
|
||||
void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg)
|
||||
|
@@ -83,7 +83,7 @@ static void commit_complete(BlockJob *job, void *opaque)
|
||||
BlockDriverState *active = s->active;
|
||||
BlockDriverState *top = blk_bs(s->top);
|
||||
BlockDriverState *base = blk_bs(s->base);
|
||||
BlockDriverState *overlay_bs = bdrv_find_overlay(active, top);
|
||||
BlockDriverState *overlay_bs;
|
||||
int ret = data->ret;
|
||||
|
||||
if (!block_job_is_cancelled(&s->common) && ret == 0) {
|
||||
@@ -97,6 +97,7 @@ static void commit_complete(BlockJob *job, void *opaque)
|
||||
if (s->base_flags != bdrv_get_flags(base)) {
|
||||
bdrv_reopen(base, s->base_flags, NULL);
|
||||
}
|
||||
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);
|
||||
}
|
||||
@@ -242,14 +243,14 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
orig_overlay_flags = bdrv_get_flags(overlay_bs);
|
||||
|
||||
/* convert base & overlay_bs to r/w, if necessary */
|
||||
if (!(orig_base_flags & BDRV_O_RDWR)) {
|
||||
reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
|
||||
orig_base_flags | BDRV_O_RDWR);
|
||||
}
|
||||
if (!(orig_overlay_flags & BDRV_O_RDWR)) {
|
||||
reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL,
|
||||
orig_overlay_flags | BDRV_O_RDWR);
|
||||
}
|
||||
if (!(orig_base_flags & BDRV_O_RDWR)) {
|
||||
reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
|
||||
orig_base_flags | BDRV_O_RDWR);
|
||||
}
|
||||
if (reopen_queue) {
|
||||
bdrv_reopen_multiple(reopen_queue, &local_err);
|
||||
if (local_err != NULL) {
|
||||
|
@@ -33,7 +33,6 @@
|
||||
#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG "ivgen-alg"
|
||||
#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg"
|
||||
#define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg"
|
||||
#define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time"
|
||||
|
||||
typedef struct BlockCrypto BlockCrypto;
|
||||
|
||||
@@ -184,11 +183,6 @@ static QemuOptsList block_crypto_create_opts_luks = {
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Name of encryption hash algorithm",
|
||||
},
|
||||
{
|
||||
.name = BLOCK_CRYPTO_OPT_LUKS_ITER_TIME,
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "Time to spend in PBKDF in milliseconds",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
124
block/curl.c
124
block/curl.c
@@ -73,7 +73,6 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
|
||||
|
||||
#define CURL_NUM_STATES 8
|
||||
#define CURL_NUM_ACB 8
|
||||
#define SECTOR_SIZE 512
|
||||
#define READ_AHEAD_DEFAULT (256 * 1024)
|
||||
#define CURL_TIMEOUT_DEFAULT 5
|
||||
#define CURL_TIMEOUT_MAX 10000
|
||||
@@ -106,12 +105,17 @@ typedef struct CURLAIOCB {
|
||||
size_t end;
|
||||
} CURLAIOCB;
|
||||
|
||||
typedef struct CURLSocket {
|
||||
int fd;
|
||||
QLIST_ENTRY(CURLSocket) next;
|
||||
} CURLSocket;
|
||||
|
||||
typedef struct CURLState
|
||||
{
|
||||
struct BDRVCURLState *s;
|
||||
CURLAIOCB *acb[CURL_NUM_ACB];
|
||||
CURL *curl;
|
||||
curl_socket_t sock_fd;
|
||||
QLIST_HEAD(, CURLSocket) sockets;
|
||||
char *orig_buf;
|
||||
size_t buf_start;
|
||||
size_t buf_off;
|
||||
@@ -165,10 +169,27 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
||||
{
|
||||
BDRVCURLState *s;
|
||||
CURLState *state = NULL;
|
||||
CURLSocket *socket;
|
||||
|
||||
curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
|
||||
state->sock_fd = fd;
|
||||
s = state->s;
|
||||
|
||||
QLIST_FOREACH(socket, &state->sockets, next) {
|
||||
if (socket->fd == fd) {
|
||||
if (action == CURL_POLL_REMOVE) {
|
||||
QLIST_REMOVE(socket, next);
|
||||
g_free(socket);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!socket) {
|
||||
socket = g_new0(CURLSocket, 1);
|
||||
socket->fd = fd;
|
||||
QLIST_INSERT_HEAD(&state->sockets, socket, next);
|
||||
}
|
||||
socket = NULL;
|
||||
|
||||
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, (int)fd);
|
||||
switch (action) {
|
||||
case CURL_POLL_IN:
|
||||
@@ -214,12 +235,13 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
||||
|
||||
DPRINTF("CURL: Just reading %zd bytes\n", realsize);
|
||||
|
||||
if (!s || !s->orig_buf)
|
||||
return 0;
|
||||
if (!s || !s->orig_buf) {
|
||||
goto read_end;
|
||||
}
|
||||
|
||||
if (s->buf_off >= s->buf_len) {
|
||||
/* buffer full, read nothing */
|
||||
return 0;
|
||||
goto read_end;
|
||||
}
|
||||
realsize = MIN(realsize, s->buf_len - s->buf_off);
|
||||
memcpy(s->orig_buf + s->buf_off, ptr, realsize);
|
||||
@@ -232,15 +254,26 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
||||
continue;
|
||||
|
||||
if ((s->buf_off >= acb->end)) {
|
||||
size_t request_length = acb->nb_sectors * BDRV_SECTOR_SIZE;
|
||||
|
||||
qemu_iovec_from_buf(acb->qiov, 0, s->orig_buf + acb->start,
|
||||
acb->end - acb->start);
|
||||
|
||||
if (acb->end - acb->start < request_length) {
|
||||
size_t offset = acb->end - acb->start;
|
||||
qemu_iovec_memset(acb->qiov, offset, 0,
|
||||
request_length - offset);
|
||||
}
|
||||
|
||||
acb->common.cb(acb->common.opaque, 0);
|
||||
qemu_aio_unref(acb);
|
||||
s->acb[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return realsize;
|
||||
read_end:
|
||||
/* curl will error out if we do not return this value */
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
||||
@@ -248,6 +281,8 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
||||
{
|
||||
int i;
|
||||
size_t end = start + len;
|
||||
size_t clamped_end = MIN(end, s->len);
|
||||
size_t clamped_len = clamped_end - start;
|
||||
|
||||
for (i=0; i<CURL_NUM_STATES; i++) {
|
||||
CURLState *state = &s->states[i];
|
||||
@@ -262,12 +297,15 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
||||
// Does the existing buffer cover our section?
|
||||
if ((start >= state->buf_start) &&
|
||||
(start <= buf_end) &&
|
||||
(end >= state->buf_start) &&
|
||||
(end <= buf_end))
|
||||
(clamped_end >= state->buf_start) &&
|
||||
(clamped_end <= buf_end))
|
||||
{
|
||||
char *buf = state->orig_buf + (start - state->buf_start);
|
||||
|
||||
qemu_iovec_from_buf(acb->qiov, 0, buf, len);
|
||||
qemu_iovec_from_buf(acb->qiov, 0, buf, clamped_len);
|
||||
if (clamped_len < len) {
|
||||
qemu_iovec_memset(acb->qiov, clamped_len, 0, len - clamped_len);
|
||||
}
|
||||
acb->common.cb(acb->common.opaque, 0);
|
||||
|
||||
return FIND_RET_OK;
|
||||
@@ -277,13 +315,13 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
||||
if (state->in_use &&
|
||||
(start >= state->buf_start) &&
|
||||
(start <= buf_fend) &&
|
||||
(end >= state->buf_start) &&
|
||||
(end <= buf_fend))
|
||||
(clamped_end >= state->buf_start) &&
|
||||
(clamped_end <= buf_fend))
|
||||
{
|
||||
int j;
|
||||
|
||||
acb->start = start - state->buf_start;
|
||||
acb->end = acb->start + len;
|
||||
acb->end = acb->start + clamped_len;
|
||||
|
||||
for (j=0; j<CURL_NUM_ACB; j++) {
|
||||
if (!state->acb[j]) {
|
||||
@@ -353,6 +391,7 @@ static void curl_multi_check_completion(BDRVCURLState *s)
|
||||
static void curl_multi_do(void *arg)
|
||||
{
|
||||
CURLState *s = (CURLState *)arg;
|
||||
CURLSocket *socket, *next_socket;
|
||||
int running;
|
||||
int r;
|
||||
|
||||
@@ -360,10 +399,13 @@ static void curl_multi_do(void *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
r = curl_multi_socket_action(s->s->multi, s->sock_fd, 0, &running);
|
||||
} while(r == CURLM_CALL_MULTI_PERFORM);
|
||||
|
||||
/* Need to use _SAFE because curl_multi_socket_action() may trigger
|
||||
* curl_sock_cb() which might modify this list */
|
||||
QLIST_FOREACH_SAFE(socket, &s->sockets, next, next_socket) {
|
||||
do {
|
||||
r = curl_multi_socket_action(s->s->multi, socket->fd, 0, &running);
|
||||
} while (r == CURLM_CALL_MULTI_PERFORM);
|
||||
}
|
||||
}
|
||||
|
||||
static void curl_multi_read(void *arg)
|
||||
@@ -467,6 +509,7 @@ static CURLState *curl_init_state(BlockDriverState *bs, BDRVCURLState *s)
|
||||
#endif
|
||||
}
|
||||
|
||||
QLIST_INIT(&state->sockets);
|
||||
state->s = s;
|
||||
|
||||
return state;
|
||||
@@ -476,6 +519,14 @@ static void curl_clean_state(CURLState *s)
|
||||
{
|
||||
if (s->s->multi)
|
||||
curl_multi_remove_handle(s->s->multi, s->curl);
|
||||
|
||||
while (!QLIST_EMPTY(&s->sockets)) {
|
||||
CURLSocket *socket = QLIST_FIRST(&s->sockets);
|
||||
|
||||
QLIST_REMOVE(socket, next);
|
||||
g_free(socket);
|
||||
}
|
||||
|
||||
s->in_use = 0;
|
||||
}
|
||||
|
||||
@@ -675,28 +726,11 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s);
|
||||
if (curl_easy_perform(state->curl))
|
||||
goto out;
|
||||
if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) {
|
||||
curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d);
|
||||
if (d)
|
||||
s->len = (size_t)d;
|
||||
else if(!s->len)
|
||||
goto out;
|
||||
}
|
||||
/* Prior CURL 7.19.4 return value of 0 could mean that the file size is not
|
||||
* know or the size is zero. From 7.19.4 CURL returns -1 if size is not
|
||||
* known and zero if it is realy zero-length file. */
|
||||
#if LIBCURL_VERSION_NUM >= 0x071304
|
||||
if (d < 0) {
|
||||
pstrcpy(state->errmsg, CURL_ERROR_SIZE,
|
||||
"Server didn't report file size.");
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
if (d <= 0) {
|
||||
pstrcpy(state->errmsg, CURL_ERROR_SIZE,
|
||||
"Unknown file size or zero-length file.");
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
s->len = (size_t)d;
|
||||
|
||||
if ((!strncasecmp(s->url, "http://", strlen("http://"))
|
||||
|| !strncasecmp(s->url, "https://", strlen("https://")))
|
||||
&& !s->accept_range) {
|
||||
@@ -742,12 +776,12 @@ static void curl_readv_bh_cb(void *p)
|
||||
qemu_bh_delete(acb->bh);
|
||||
acb->bh = NULL;
|
||||
|
||||
size_t start = acb->sector_num * SECTOR_SIZE;
|
||||
size_t start = acb->sector_num * BDRV_SECTOR_SIZE;
|
||||
size_t end;
|
||||
|
||||
// In case we have the requested data already (e.g. read-ahead),
|
||||
// we can just call the callback and be done.
|
||||
switch (curl_find_buf(s, start, acb->nb_sectors * SECTOR_SIZE, acb)) {
|
||||
switch (curl_find_buf(s, start, acb->nb_sectors * BDRV_SECTOR_SIZE, acb)) {
|
||||
case FIND_RET_OK:
|
||||
qemu_aio_unref(acb);
|
||||
// fall through
|
||||
@@ -766,13 +800,13 @@ static void curl_readv_bh_cb(void *p)
|
||||
}
|
||||
|
||||
acb->start = 0;
|
||||
acb->end = (acb->nb_sectors * SECTOR_SIZE);
|
||||
acb->end = MIN(acb->nb_sectors * BDRV_SECTOR_SIZE, s->len - start);
|
||||
|
||||
state->buf_off = 0;
|
||||
g_free(state->orig_buf);
|
||||
state->buf_start = start;
|
||||
state->buf_len = acb->end + s->readahead_size;
|
||||
end = MIN(start + state->buf_len, s->len) - 1;
|
||||
state->buf_len = MIN(acb->end + s->readahead_size, s->len - start);
|
||||
end = start + state->buf_len - 1;
|
||||
state->orig_buf = g_try_malloc(state->buf_len);
|
||||
if (state->buf_len && state->orig_buf == NULL) {
|
||||
curl_clean_state(state);
|
||||
@@ -783,8 +817,8 @@ static void curl_readv_bh_cb(void *p)
|
||||
state->acb[0] = acb;
|
||||
|
||||
snprintf(state->range, 127, "%zd-%zd", start, end);
|
||||
DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n",
|
||||
(acb->nb_sectors * SECTOR_SIZE), start, state->range);
|
||||
DPRINTF("CURL (AIO): Reading %llu at %zd (%s)\n",
|
||||
(acb->nb_sectors * BDRV_SECTOR_SIZE), start, state->range);
|
||||
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
|
||||
|
||||
curl_multi_add_handle(s->multi, state->curl);
|
||||
|
@@ -30,8 +30,6 @@
|
||||
#define GLUSTER_DEFAULT_PORT 24007
|
||||
#define GLUSTER_DEBUG_DEFAULT 4
|
||||
#define GLUSTER_DEBUG_MAX 9
|
||||
#define GLUSTER_OPT_LOGFILE "logfile"
|
||||
#define GLUSTER_LOGFILE_DEFAULT "-" /* handled in libgfapi as /dev/stderr */
|
||||
|
||||
#define GERR_INDEX_HINT "hint: check in 'server' array index '%d'\n"
|
||||
|
||||
@@ -46,7 +44,6 @@ typedef struct GlusterAIOCB {
|
||||
typedef struct BDRVGlusterState {
|
||||
struct glfs *glfs;
|
||||
struct glfs_fd *fd;
|
||||
char *logfile;
|
||||
bool supports_seek_data;
|
||||
int debug_level;
|
||||
} BDRVGlusterState;
|
||||
@@ -76,11 +73,6 @@ static QemuOptsList qemu_gluster_create_opts = {
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "Gluster log level, valid range is 0-9",
|
||||
},
|
||||
{
|
||||
.name = GLUSTER_OPT_LOGFILE,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Logfile path of libgfapi",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
}
|
||||
};
|
||||
@@ -99,11 +91,6 @@ static QemuOptsList runtime_opts = {
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "Gluster log level, valid range is 0-9",
|
||||
},
|
||||
{
|
||||
.name = GLUSTER_OPT_LOGFILE,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Logfile path of libgfapi",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@@ -354,7 +341,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
|
||||
}
|
||||
}
|
||||
|
||||
ret = glfs_set_logging(glfs, gconf->logfile, gconf->debug_level);
|
||||
ret = glfs_set_logging(glfs, "-", gconf->debug_level);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
@@ -589,9 +576,7 @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "invalid URI");
|
||||
error_append_hint(errp, "Usage: file=gluster[+transport]://"
|
||||
"[host[:port]]volume/path[?socket=...]"
|
||||
"[,file.debug=N]"
|
||||
"[,file.logfile=/path/filename.log]\n");
|
||||
"[host[:port]]/volume/path[?socket=...]\n");
|
||||
errno = -ret;
|
||||
return NULL;
|
||||
}
|
||||
@@ -601,9 +586,7 @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
|
||||
error_append_hint(errp, "Usage: "
|
||||
"-drive driver=qcow2,file.driver=gluster,"
|
||||
"file.volume=testvol,file.path=/path/a.qcow2"
|
||||
"[,file.debug=9]"
|
||||
"[,file.logfile=/path/filename.log],"
|
||||
"file.server.0.type=tcp,"
|
||||
"[,file.debug=9],file.server.0.type=tcp,"
|
||||
"file.server.0.host=1.2.3.4,"
|
||||
"file.server.0.port=24007,"
|
||||
"file.server.1.transport=unix,"
|
||||
@@ -694,7 +677,7 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
||||
BlockdevOptionsGluster *gconf = NULL;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
const char *filename, *logfile;
|
||||
const char *filename;
|
||||
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
@@ -717,13 +700,6 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
||||
gconf = g_new0(BlockdevOptionsGluster, 1);
|
||||
gconf->debug_level = s->debug_level;
|
||||
gconf->has_debug_level = true;
|
||||
|
||||
logfile = qemu_opt_get(opts, GLUSTER_OPT_LOGFILE);
|
||||
s->logfile = g_strdup(logfile ? logfile : GLUSTER_LOGFILE_DEFAULT);
|
||||
|
||||
gconf->logfile = g_strdup(s->logfile);
|
||||
gconf->has_logfile = true;
|
||||
|
||||
s->glfs = qemu_gluster_init(gconf, filename, options, errp);
|
||||
if (!s->glfs) {
|
||||
ret = -errno;
|
||||
@@ -762,7 +738,6 @@ out:
|
||||
if (!ret) {
|
||||
return ret;
|
||||
}
|
||||
g_free(s->logfile);
|
||||
if (s->fd) {
|
||||
glfs_close(s->fd);
|
||||
}
|
||||
@@ -794,8 +769,6 @@ static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
|
||||
gconf = g_new0(BlockdevOptionsGluster, 1);
|
||||
gconf->debug_level = s->debug_level;
|
||||
gconf->has_debug_level = true;
|
||||
gconf->logfile = g_strdup(s->logfile);
|
||||
gconf->has_logfile = true;
|
||||
reop_s->glfs = qemu_gluster_init(gconf, state->bs->filename, NULL, errp);
|
||||
if (reop_s->glfs == NULL) {
|
||||
ret = -errno;
|
||||
@@ -941,12 +914,6 @@ static int qemu_gluster_create(const char *filename,
|
||||
}
|
||||
gconf->has_debug_level = true;
|
||||
|
||||
gconf->logfile = qemu_opt_get_del(opts, GLUSTER_OPT_LOGFILE);
|
||||
if (!gconf->logfile) {
|
||||
gconf->logfile = g_strdup(GLUSTER_LOGFILE_DEFAULT);
|
||||
}
|
||||
gconf->has_logfile = true;
|
||||
|
||||
glfs = qemu_gluster_init(gconf, filename, NULL, errp);
|
||||
if (!glfs) {
|
||||
ret = -errno;
|
||||
@@ -1058,7 +1025,6 @@ static void qemu_gluster_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVGlusterState *s = bs->opaque;
|
||||
|
||||
g_free(s->logfile);
|
||||
if (s->fd) {
|
||||
glfs_close(s->fd);
|
||||
s->fd = NULL;
|
||||
|
135
block/io.c
135
block/io.c
@@ -540,6 +540,17 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return bdrv_check_byte_request(bs, sector_num * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
typedef struct RwCo {
|
||||
BdrvChild *child;
|
||||
int64_t offset;
|
||||
@@ -886,19 +897,6 @@ emulate_flags:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
bdrv_driver_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
|
||||
if (!drv->bdrv_co_pwritev_compressed) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return drv->bdrv_co_pwritev_compressed(bs, offset, bytes, qiov);
|
||||
}
|
||||
|
||||
static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
|
||||
int64_t offset, unsigned int bytes, QEMUIOVector *qiov)
|
||||
{
|
||||
@@ -1181,6 +1179,8 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
||||
int max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, INT_MAX);
|
||||
int alignment = MAX(bs->bl.pwrite_zeroes_alignment,
|
||||
bs->bl.request_alignment);
|
||||
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
|
||||
MAX_WRITE_ZEROES_BOUNCE_BUFFER);
|
||||
|
||||
assert(alignment % bs->bl.request_alignment == 0);
|
||||
head = offset % alignment;
|
||||
@@ -1196,9 +1196,12 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
||||
* boundaries.
|
||||
*/
|
||||
if (head) {
|
||||
/* Make a small request up to the first aligned sector. */
|
||||
num = MIN(count, alignment - head);
|
||||
head = 0;
|
||||
/* Make a small request up to the first aligned sector. For
|
||||
* convenience, limit this request to max_transfer even if
|
||||
* we don't need to fall back to writes. */
|
||||
num = MIN(MIN(count, max_transfer), alignment - head);
|
||||
head = (head + num) % alignment;
|
||||
assert(num < max_write_zeroes);
|
||||
} else if (tail && num > alignment) {
|
||||
/* Shorten the request to the last aligned sector. */
|
||||
num -= tail;
|
||||
@@ -1224,8 +1227,6 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
||||
|
||||
if (ret == -ENOTSUP) {
|
||||
/* Fall back to bounce buffer if write zeroes is unsupported */
|
||||
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
|
||||
MAX_WRITE_ZEROES_BOUNCE_BUFFER);
|
||||
BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE;
|
||||
|
||||
if ((flags & BDRV_REQ_FUA) &&
|
||||
@@ -1317,8 +1318,6 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
||||
} else if (flags & BDRV_REQ_ZERO_WRITE) {
|
||||
bdrv_debug_event(bs, BLKDBG_PWRITEV_ZERO);
|
||||
ret = bdrv_co_do_pwrite_zeroes(bs, offset, bytes, flags);
|
||||
} else if (flags & BDRV_REQ_WRITE_COMPRESSED) {
|
||||
ret = bdrv_driver_pwritev_compressed(bs, offset, bytes, qiov);
|
||||
} else if (bytes <= max_transfer) {
|
||||
bdrv_debug_event(bs, BLKDBG_PWRITEV);
|
||||
ret = bdrv_driver_pwritev(bs, offset, bytes, qiov, flags);
|
||||
@@ -1619,6 +1618,31 @@ int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
|
||||
BDRV_REQ_ZERO_WRITE | flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush ALL BDSes regardless of if they are reachable via a BlkBackend or not.
|
||||
*/
|
||||
int bdrv_flush_all(void)
|
||||
{
|
||||
BdrvNextIterator it;
|
||||
BlockDriverState *bs = NULL;
|
||||
int result = 0;
|
||||
|
||||
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
int ret;
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
ret = bdrv_flush(bs);
|
||||
if (ret < 0 && !result) {
|
||||
result = ret;
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
typedef struct BdrvCoGetBlockStatusData {
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *base;
|
||||
@@ -1883,6 +1907,28 @@ int bdrv_is_allocated_above(BlockDriverState *top,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
int ret;
|
||||
|
||||
if (!drv) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
if (!drv->bdrv_write_compressed) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
ret = bdrv_check_request(bs, sector_num, nb_sectors);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
assert(QLIST_EMPTY(&bs->dirty_bitmaps));
|
||||
|
||||
return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
|
||||
}
|
||||
|
||||
typedef struct BdrvVmstateCo {
|
||||
BlockDriverState *bs;
|
||||
QEMUIOVector *qiov;
|
||||
@@ -2338,7 +2384,9 @@ flush_parent:
|
||||
ret = bs->file ? bdrv_co_flush(bs->file->bs) : 0;
|
||||
out:
|
||||
/* Notify any pending flushes that we have completed */
|
||||
bs->flushed_gen = current_gen;
|
||||
if (ret == 0) {
|
||||
bs->flushed_gen = current_gen;
|
||||
}
|
||||
bs->active_flush_req = NULL;
|
||||
/* Return value is ignored - it's ok if wait queue is empty */
|
||||
qemu_co_queue_next(&bs->flush_queue);
|
||||
@@ -2389,7 +2437,7 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
||||
{
|
||||
BdrvTrackedRequest req;
|
||||
int max_pdiscard, ret;
|
||||
int head, align;
|
||||
int head, tail, align;
|
||||
|
||||
if (!bs->drv) {
|
||||
return -ENOMEDIUM;
|
||||
@@ -2412,19 +2460,15 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Discard is advisory, so ignore any unaligned head or tail */
|
||||
/* Discard is advisory, but some devices track and coalesce
|
||||
* unaligned requests, so we must pass everything down rather than
|
||||
* round here. Still, most devices will just silently ignore
|
||||
* unaligned requests (by returning -ENOTSUP), so we must fragment
|
||||
* the request accordingly. */
|
||||
align = MAX(bs->bl.pdiscard_alignment, bs->bl.request_alignment);
|
||||
assert(align % bs->bl.request_alignment == 0);
|
||||
head = offset % align;
|
||||
if (head) {
|
||||
head = MIN(count, align - head);
|
||||
count -= head;
|
||||
offset += head;
|
||||
}
|
||||
count = QEMU_ALIGN_DOWN(count, align);
|
||||
if (!count) {
|
||||
return 0;
|
||||
}
|
||||
tail = (offset + count) % align;
|
||||
|
||||
tracked_request_begin(&req, bs, offset, count, BDRV_TRACKED_DISCARD);
|
||||
|
||||
@@ -2435,11 +2479,34 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
||||
|
||||
max_pdiscard = QEMU_ALIGN_DOWN(MIN_NON_ZERO(bs->bl.max_pdiscard, INT_MAX),
|
||||
align);
|
||||
assert(max_pdiscard);
|
||||
assert(max_pdiscard >= bs->bl.request_alignment);
|
||||
|
||||
while (count > 0) {
|
||||
int ret;
|
||||
int num = MIN(count, max_pdiscard);
|
||||
int num = count;
|
||||
|
||||
if (head) {
|
||||
/* Make small requests to get to alignment boundaries. */
|
||||
num = MIN(count, align - head);
|
||||
if (!QEMU_IS_ALIGNED(num, bs->bl.request_alignment)) {
|
||||
num %= bs->bl.request_alignment;
|
||||
}
|
||||
head = (head + num) % align;
|
||||
assert(num < max_pdiscard);
|
||||
} else if (tail) {
|
||||
if (num > align) {
|
||||
/* Shorten the request to the last aligned cluster. */
|
||||
num -= tail;
|
||||
} else if (!QEMU_IS_ALIGNED(tail, bs->bl.request_alignment) &&
|
||||
tail > bs->bl.request_alignment) {
|
||||
tail %= bs->bl.request_alignment;
|
||||
num -= tail;
|
||||
}
|
||||
}
|
||||
/* limit request size */
|
||||
if (num > max_pdiscard) {
|
||||
num = max_pdiscard;
|
||||
}
|
||||
|
||||
if (bs->drv->bdrv_co_pdiscard) {
|
||||
ret = bs->drv->bdrv_co_pdiscard(bs, offset, num);
|
||||
|
@@ -36,7 +36,7 @@
|
||||
#include "block/block_int.h"
|
||||
#include "block/scsi.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "qemu/uuid.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "crypto/secret.h"
|
||||
@@ -1048,7 +1048,9 @@ coroutine_fn iscsi_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
|
||||
struct IscsiTask iTask;
|
||||
struct unmap_list list;
|
||||
|
||||
assert(is_byte_request_lun_aligned(offset, count, iscsilun));
|
||||
if (!is_byte_request_lun_aligned(offset, count, iscsilun)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (!iscsilun->lbp.lbpu) {
|
||||
/* UNMAP is not supported by the target */
|
||||
@@ -2013,9 +2015,45 @@ static BlockDriver bdrv_iscsi = {
|
||||
.bdrv_attach_aio_context = iscsi_attach_aio_context,
|
||||
};
|
||||
|
||||
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 = "password-secret",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "ID of the secret providing 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",
|
||||
},{
|
||||
.name = "timeout",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "Request timeout in seconds (default 0 = no timeout)",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static void iscsi_block_init(void)
|
||||
{
|
||||
bdrv_register(&bdrv_iscsi);
|
||||
qemu_add_opts(&qemu_iscsi_opts);
|
||||
}
|
||||
|
||||
block_init(iscsi_block_init);
|
||||
|
@@ -59,6 +59,7 @@ struct LinuxAioState {
|
||||
|
||||
/* I/O completion processing */
|
||||
QEMUBH *completion_bh;
|
||||
struct io_event events[MAX_EVENTS];
|
||||
int event_idx;
|
||||
int event_max;
|
||||
};
|
||||
@@ -94,153 +95,64 @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
|
||||
|
||||
laiocb->ret = ret;
|
||||
if (laiocb->co) {
|
||||
/* Jump and continue completion for foreign requests, don't do
|
||||
* anything for current request, it will be completed shortly. */
|
||||
if (laiocb->co != qemu_coroutine_self()) {
|
||||
qemu_coroutine_enter(laiocb->co);
|
||||
}
|
||||
qemu_coroutine_enter(laiocb->co);
|
||||
} else {
|
||||
laiocb->common.cb(laiocb->common.opaque, ret);
|
||||
qemu_aio_unref(laiocb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* aio_ring buffer which is shared between userspace and kernel.
|
||||
*
|
||||
* This copied from linux/fs/aio.c, common header does not exist
|
||||
* but AIO exists for ages so we assume ABI is stable.
|
||||
*/
|
||||
struct aio_ring {
|
||||
unsigned id; /* kernel internal index number */
|
||||
unsigned nr; /* number of io_events */
|
||||
unsigned head; /* Written to by userland or by kernel. */
|
||||
unsigned tail;
|
||||
|
||||
unsigned magic;
|
||||
unsigned compat_features;
|
||||
unsigned incompat_features;
|
||||
unsigned header_length; /* size of aio_ring */
|
||||
|
||||
struct io_event io_events[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* io_getevents_peek:
|
||||
* @ctx: AIO context
|
||||
* @events: pointer on events array, output value
|
||||
|
||||
* Returns the number of completed events and sets a pointer
|
||||
* on events array. This function does not update the internal
|
||||
* ring buffer, only reads head and tail. When @events has been
|
||||
* processed io_getevents_commit() must be called.
|
||||
*/
|
||||
static inline unsigned int io_getevents_peek(io_context_t ctx,
|
||||
struct io_event **events)
|
||||
{
|
||||
struct aio_ring *ring = (struct aio_ring *)ctx;
|
||||
unsigned int head = ring->head, tail = ring->tail;
|
||||
unsigned int nr;
|
||||
|
||||
nr = tail >= head ? tail - head : ring->nr - head;
|
||||
*events = ring->io_events + head;
|
||||
/* To avoid speculative loads of s->events[i] before observing tail.
|
||||
Paired with smp_wmb() inside linux/fs/aio.c: aio_complete(). */
|
||||
smp_rmb();
|
||||
|
||||
return nr;
|
||||
}
|
||||
|
||||
/**
|
||||
* io_getevents_commit:
|
||||
* @ctx: AIO context
|
||||
* @nr: the number of events on which head should be advanced
|
||||
*
|
||||
* Advances head of a ring buffer.
|
||||
*/
|
||||
static inline void io_getevents_commit(io_context_t ctx, unsigned int nr)
|
||||
{
|
||||
struct aio_ring *ring = (struct aio_ring *)ctx;
|
||||
|
||||
if (nr) {
|
||||
ring->head = (ring->head + nr) % ring->nr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* io_getevents_advance_and_peek:
|
||||
* @ctx: AIO context
|
||||
* @events: pointer on events array, output value
|
||||
* @nr: the number of events on which head should be advanced
|
||||
*
|
||||
* Advances head of a ring buffer and returns number of elements left.
|
||||
*/
|
||||
static inline unsigned int
|
||||
io_getevents_advance_and_peek(io_context_t ctx,
|
||||
struct io_event **events,
|
||||
unsigned int nr)
|
||||
{
|
||||
io_getevents_commit(ctx, nr);
|
||||
return io_getevents_peek(ctx, events);
|
||||
}
|
||||
|
||||
/**
|
||||
* qemu_laio_process_completions:
|
||||
* @s: AIO state
|
||||
*
|
||||
* Fetches completed I/O requests and invokes their callbacks.
|
||||
/* The completion BH fetches completed I/O requests and invokes their
|
||||
* callbacks.
|
||||
*
|
||||
* The function is somewhat tricky because it supports nested event loops, for
|
||||
* example when a request callback invokes aio_poll(). In order to do this,
|
||||
* indices are kept in LinuxAioState. Function schedules BH completion so it
|
||||
* can be called again in a nested event loop. When there are no events left
|
||||
* to complete the BH is being canceled.
|
||||
* the completion events array and index are kept in LinuxAioState. The BH
|
||||
* reschedules itself as long as there are completions pending so it will
|
||||
* either be called again in a nested event loop or will be called after all
|
||||
* events have been completed. When there are no events left to complete, the
|
||||
* BH returns without rescheduling.
|
||||
*/
|
||||
static void qemu_laio_process_completions(LinuxAioState *s)
|
||||
{
|
||||
struct io_event *events;
|
||||
|
||||
/* Reschedule so nested event loops see currently pending completions */
|
||||
qemu_bh_schedule(s->completion_bh);
|
||||
|
||||
while ((s->event_max = io_getevents_advance_and_peek(s->ctx, &events,
|
||||
s->event_idx))) {
|
||||
for (s->event_idx = 0; s->event_idx < s->event_max; ) {
|
||||
struct iocb *iocb = events[s->event_idx].obj;
|
||||
struct qemu_laiocb *laiocb =
|
||||
container_of(iocb, struct qemu_laiocb, iocb);
|
||||
|
||||
laiocb->ret = io_event_ret(&events[s->event_idx]);
|
||||
|
||||
/* Change counters one-by-one because we can be nested. */
|
||||
s->io_q.in_flight--;
|
||||
s->event_idx++;
|
||||
qemu_laio_process_completion(laiocb);
|
||||
}
|
||||
}
|
||||
|
||||
qemu_bh_cancel(s->completion_bh);
|
||||
|
||||
/* If we are nested we have to notify the level above that we are done
|
||||
* by setting event_max to zero, upper level will then jump out of it's
|
||||
* own `for` loop. If we are the last all counters droped to zero. */
|
||||
s->event_max = 0;
|
||||
s->event_idx = 0;
|
||||
}
|
||||
|
||||
static void qemu_laio_process_completions_and_submit(LinuxAioState *s)
|
||||
{
|
||||
qemu_laio_process_completions(s);
|
||||
if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
|
||||
ioq_submit(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_laio_completion_bh(void *opaque)
|
||||
{
|
||||
LinuxAioState *s = opaque;
|
||||
|
||||
qemu_laio_process_completions_and_submit(s);
|
||||
/* Fetch more completion events when empty */
|
||||
if (s->event_idx == s->event_max) {
|
||||
do {
|
||||
struct timespec ts = { 0 };
|
||||
s->event_max = io_getevents(s->ctx, MAX_EVENTS, MAX_EVENTS,
|
||||
s->events, &ts);
|
||||
} while (s->event_max == -EINTR);
|
||||
|
||||
s->event_idx = 0;
|
||||
if (s->event_max <= 0) {
|
||||
s->event_max = 0;
|
||||
return; /* no more events */
|
||||
}
|
||||
s->io_q.in_flight -= s->event_max;
|
||||
}
|
||||
|
||||
/* Reschedule so nested event loops see currently pending completions */
|
||||
qemu_bh_schedule(s->completion_bh);
|
||||
|
||||
/* Process completion events */
|
||||
while (s->event_idx < s->event_max) {
|
||||
struct iocb *iocb = s->events[s->event_idx].obj;
|
||||
struct qemu_laiocb *laiocb =
|
||||
container_of(iocb, struct qemu_laiocb, iocb);
|
||||
|
||||
laiocb->ret = io_event_ret(&s->events[s->event_idx]);
|
||||
s->event_idx++;
|
||||
|
||||
qemu_laio_process_completion(laiocb);
|
||||
}
|
||||
|
||||
if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
|
||||
ioq_submit(s);
|
||||
}
|
||||
|
||||
qemu_bh_cancel(s->completion_bh);
|
||||
}
|
||||
|
||||
static void qemu_laio_completion_cb(EventNotifier *e)
|
||||
@@ -248,7 +160,7 @@ static void qemu_laio_completion_cb(EventNotifier *e)
|
||||
LinuxAioState *s = container_of(e, LinuxAioState, e);
|
||||
|
||||
if (event_notifier_test_and_clear(&s->e)) {
|
||||
qemu_laio_process_completions_and_submit(s);
|
||||
qemu_laio_completion_bh(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,19 +236,6 @@ static void ioq_submit(LinuxAioState *s)
|
||||
QSIMPLEQ_SPLIT_AFTER(&s->io_q.pending, aiocb, next, &completed);
|
||||
} while (ret == len && !QSIMPLEQ_EMPTY(&s->io_q.pending));
|
||||
s->io_q.blocked = (s->io_q.in_queue > 0);
|
||||
|
||||
if (s->io_q.in_flight) {
|
||||
/* We can try to complete something just right away if there are
|
||||
* still requests in-flight. */
|
||||
qemu_laio_process_completions(s);
|
||||
/*
|
||||
* Even we have completed everything (in_flight == 0), the queue can
|
||||
* have still pended requests (in_queue > 0). We do not attempt to
|
||||
* repeat submission to avoid IO hang. The reason is simple: s->e is
|
||||
* still set and completion callback will be called shortly and all
|
||||
* pended requests will be submitted from there.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
void laio_io_plug(BlockDriverState *bs, LinuxAioState *s)
|
||||
@@ -394,7 +293,6 @@ int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
|
||||
.co = qemu_coroutine_self(),
|
||||
.nbytes = qiov->size,
|
||||
.ctx = s,
|
||||
.ret = -EINPROGRESS,
|
||||
.is_read = (type == QEMU_AIO_READ),
|
||||
.qiov = qiov,
|
||||
};
|
||||
@@ -404,9 +302,7 @@ int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (laiocb.ret == -EINPROGRESS) {
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
qemu_coroutine_yield();
|
||||
return laiocb.ret;
|
||||
}
|
||||
|
||||
|
@@ -916,8 +916,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp,
|
||||
const BlockJobDriver *driver,
|
||||
bool is_none_mode, BlockDriverState *base,
|
||||
bool auto_complete)
|
||||
bool is_none_mode, BlockDriverState *base)
|
||||
{
|
||||
MirrorBlockJob *s;
|
||||
|
||||
@@ -953,9 +952,6 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
|
||||
s->granularity = granularity;
|
||||
s->buf_size = ROUND_UP(buf_size, granularity);
|
||||
s->unmap = unmap;
|
||||
if (auto_complete) {
|
||||
s->should_complete = true;
|
||||
}
|
||||
|
||||
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
|
||||
if (!s->dirty_bitmap) {
|
||||
@@ -994,15 +990,14 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
|
||||
mirror_start_job(job_id, bs, target, replaces,
|
||||
speed, granularity, buf_size, backing_mode,
|
||||
on_source_error, on_target_error, unmap, cb, opaque, errp,
|
||||
&mirror_job_driver, is_none_mode, base, false);
|
||||
&mirror_job_driver, is_none_mode, base);
|
||||
}
|
||||
|
||||
void commit_active_start(const char *job_id, BlockDriverState *bs,
|
||||
BlockDriverState *base, int64_t speed,
|
||||
BlockdevOnError on_error,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp,
|
||||
bool auto_complete)
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
int64_t length, base_length;
|
||||
int orig_base_flags;
|
||||
@@ -1043,7 +1038,7 @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
|
||||
mirror_start_job(job_id, bs, base, NULL, speed, 0, 0,
|
||||
MIRROR_LEAVE_BACKING_CHAIN,
|
||||
on_error, on_error, false, cb, opaque, &local_err,
|
||||
&commit_active_job_driver, false, base, auto_complete);
|
||||
&commit_active_job_driver, false, base);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto error_restore_flags;
|
||||
|
113
block/qcow.c
113
block/qcow.c
@@ -913,32 +913,75 @@ static int qcow_make_empty(BlockDriverState *bs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct QcowWriteCo {
|
||||
BlockDriverState *bs;
|
||||
int64_t sector_num;
|
||||
const uint8_t *buf;
|
||||
int nb_sectors;
|
||||
int ret;
|
||||
} QcowWriteCo;
|
||||
|
||||
static void qcow_write_co_entry(void *opaque)
|
||||
{
|
||||
QcowWriteCo *co = opaque;
|
||||
QEMUIOVector qiov;
|
||||
|
||||
struct iovec iov = (struct iovec) {
|
||||
.iov_base = (uint8_t*) co->buf,
|
||||
.iov_len = co->nb_sectors * BDRV_SECTOR_SIZE,
|
||||
};
|
||||
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||
|
||||
co->ret = qcow_co_writev(co->bs, co->sector_num, co->nb_sectors, &qiov);
|
||||
}
|
||||
|
||||
/* Wrapper for non-coroutine contexts */
|
||||
static int qcow_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
Coroutine *co;
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
QcowWriteCo data = {
|
||||
.bs = bs,
|
||||
.sector_num = sector_num,
|
||||
.buf = buf,
|
||||
.nb_sectors = nb_sectors,
|
||||
.ret = -EINPROGRESS,
|
||||
};
|
||||
co = qemu_coroutine_create(qcow_write_co_entry, &data);
|
||||
qemu_coroutine_enter(co);
|
||||
while (data.ret == -EINPROGRESS) {
|
||||
aio_poll(aio_context, true);
|
||||
}
|
||||
return data.ret;
|
||||
}
|
||||
|
||||
/* XXX: put compressed sectors first, then all the cluster aligned
|
||||
tables to avoid losing bytes in alignment */
|
||||
static coroutine_fn int
|
||||
qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov)
|
||||
static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
QEMUIOVector hd_qiov;
|
||||
struct iovec iov;
|
||||
z_stream strm;
|
||||
int ret, out_len;
|
||||
uint8_t *buf, *out_buf;
|
||||
uint8_t *out_buf;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
buf = qemu_blockalign(bs, s->cluster_size);
|
||||
if (bytes != s->cluster_size) {
|
||||
if (bytes > s->cluster_size ||
|
||||
offset + bytes != bs->total_sectors << BDRV_SECTOR_BITS)
|
||||
{
|
||||
qemu_vfree(buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (nb_sectors != s->cluster_sectors) {
|
||||
ret = -EINVAL;
|
||||
|
||||
/* Zero-pad last write if image size is not cluster aligned */
|
||||
memset(buf + bytes, 0, s->cluster_size - bytes);
|
||||
if (sector_num + nb_sectors == bs->total_sectors &&
|
||||
nb_sectors < s->cluster_sectors) {
|
||||
uint8_t *pad_buf = qemu_blockalign(bs, s->cluster_size);
|
||||
memset(pad_buf, 0, s->cluster_size);
|
||||
memcpy(pad_buf, buf, nb_sectors * BDRV_SECTOR_SIZE);
|
||||
ret = qcow_write_compressed(bs, sector_num,
|
||||
pad_buf, s->cluster_sectors);
|
||||
qemu_vfree(pad_buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
qemu_iovec_to_buf(qiov, 0, buf, qiov->size);
|
||||
|
||||
out_buf = g_malloc(s->cluster_size);
|
||||
|
||||
@@ -969,35 +1012,27 @@ qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||
|
||||
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
|
||||
/* could not compress: write normal cluster */
|
||||
ret = qcow_co_writev(bs, offset >> BDRV_SECTOR_BITS,
|
||||
bytes >> BDRV_SECTOR_BITS, qiov);
|
||||
ret = qcow_write(bs, sector_num, buf, s->cluster_sectors);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
goto success;
|
||||
}
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
cluster_offset = get_cluster_offset(bs, offset, 2, out_len, 0, 0);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
if (cluster_offset == 0) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
cluster_offset &= s->cluster_offset_mask;
|
||||
} else {
|
||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
|
||||
out_len, 0, 0);
|
||||
if (cluster_offset == 0) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
iov = (struct iovec) {
|
||||
.iov_base = out_buf,
|
||||
.iov_len = out_len,
|
||||
};
|
||||
qemu_iovec_init_external(&hd_qiov, &iov, 1);
|
||||
ret = bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
cluster_offset &= s->cluster_offset_mask;
|
||||
ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
success:
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
qemu_vfree(buf);
|
||||
g_free(out_buf);
|
||||
return ret;
|
||||
}
|
||||
@@ -1050,7 +1085,7 @@ static BlockDriver bdrv_qcow = {
|
||||
|
||||
.bdrv_set_key = qcow_set_key,
|
||||
.bdrv_make_empty = qcow_make_empty,
|
||||
.bdrv_co_pwritev_compressed = qcow_co_pwritev_compressed,
|
||||
.bdrv_write_compressed = qcow_write_compressed,
|
||||
.bdrv_get_info = qcow_get_info,
|
||||
|
||||
.create_opts = &qcow_create_opts,
|
||||
|
@@ -83,9 +83,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
||||
}
|
||||
memset(new_l1_table, 0, align_offset(new_l1_size2, 512));
|
||||
|
||||
if (s->l1_size) {
|
||||
memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
|
||||
}
|
||||
memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
|
||||
|
||||
/* write new table (align to cluster) */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ALLOC_TABLE);
|
||||
|
143
block/qcow2.c
143
block/qcow2.c
@@ -1204,6 +1204,7 @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
bs->bl.request_alignment = BDRV_SECTOR_SIZE;
|
||||
}
|
||||
bs->bl.pwrite_zeroes_alignment = s->cluster_size;
|
||||
bs->bl.pdiscard_alignment = s->cluster_size;
|
||||
}
|
||||
|
||||
static int qcow2_set_key(BlockDriverState *bs, const char *key)
|
||||
@@ -1804,10 +1805,7 @@ static size_t header_ext_add(char *buf, uint32_t magic, const void *s,
|
||||
.magic = cpu_to_be32(magic),
|
||||
.len = cpu_to_be32(len),
|
||||
};
|
||||
|
||||
if (len) {
|
||||
memcpy(buf + sizeof(QCowExtension), s, len);
|
||||
}
|
||||
memcpy(buf + sizeof(QCowExtension), s, len);
|
||||
|
||||
return ext_len;
|
||||
}
|
||||
@@ -2488,6 +2486,11 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
|
||||
int ret;
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
|
||||
if (!QEMU_IS_ALIGNED(offset | count, s->cluster_size)) {
|
||||
assert(count < s->cluster_size);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
ret = qcow2_discard_clusters(bs, offset, count >> BDRV_SECTOR_BITS,
|
||||
QCOW2_DISCARD_REQUEST, false);
|
||||
@@ -2536,39 +2539,84 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct Qcow2WriteCo {
|
||||
BlockDriverState *bs;
|
||||
int64_t sector_num;
|
||||
const uint8_t *buf;
|
||||
int nb_sectors;
|
||||
int ret;
|
||||
} Qcow2WriteCo;
|
||||
|
||||
static void qcow2_write_co_entry(void *opaque)
|
||||
{
|
||||
Qcow2WriteCo *co = opaque;
|
||||
QEMUIOVector qiov;
|
||||
uint64_t offset = co->sector_num * BDRV_SECTOR_SIZE;
|
||||
uint64_t bytes = co->nb_sectors * BDRV_SECTOR_SIZE;
|
||||
|
||||
struct iovec iov = (struct iovec) {
|
||||
.iov_base = (uint8_t*) co->buf,
|
||||
.iov_len = bytes,
|
||||
};
|
||||
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||
|
||||
co->ret = qcow2_co_pwritev(co->bs, offset, bytes, &qiov, 0);
|
||||
}
|
||||
|
||||
/* Wrapper for non-coroutine contexts */
|
||||
static int qcow2_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
Coroutine *co;
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
Qcow2WriteCo data = {
|
||||
.bs = bs,
|
||||
.sector_num = sector_num,
|
||||
.buf = buf,
|
||||
.nb_sectors = nb_sectors,
|
||||
.ret = -EINPROGRESS,
|
||||
};
|
||||
co = qemu_coroutine_create(qcow2_write_co_entry, &data);
|
||||
qemu_coroutine_enter(co);
|
||||
while (data.ret == -EINPROGRESS) {
|
||||
aio_poll(aio_context, true);
|
||||
}
|
||||
return data.ret;
|
||||
}
|
||||
|
||||
/* XXX: put compressed sectors first, then all the cluster aligned
|
||||
tables to avoid losing bytes in alignment */
|
||||
static coroutine_fn int
|
||||
qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov)
|
||||
static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
QEMUIOVector hd_qiov;
|
||||
struct iovec iov;
|
||||
z_stream strm;
|
||||
int ret, out_len;
|
||||
uint8_t *buf, *out_buf;
|
||||
uint8_t *out_buf;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
if (bytes == 0) {
|
||||
if (nb_sectors == 0) {
|
||||
/* align end of file to a sector boundary to ease reading with
|
||||
sector based I/Os */
|
||||
cluster_offset = bdrv_getlength(bs->file->bs);
|
||||
return bdrv_truncate(bs->file->bs, cluster_offset);
|
||||
}
|
||||
|
||||
buf = qemu_blockalign(bs, s->cluster_size);
|
||||
if (bytes != s->cluster_size) {
|
||||
if (bytes > s->cluster_size ||
|
||||
offset + bytes != bs->total_sectors << BDRV_SECTOR_BITS)
|
||||
{
|
||||
qemu_vfree(buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (nb_sectors != s->cluster_sectors) {
|
||||
ret = -EINVAL;
|
||||
|
||||
/* Zero-pad last write if image size is not cluster aligned */
|
||||
memset(buf + bytes, 0, s->cluster_size - bytes);
|
||||
if (sector_num + nb_sectors == bs->total_sectors &&
|
||||
nb_sectors < s->cluster_sectors) {
|
||||
uint8_t *pad_buf = qemu_blockalign(bs, s->cluster_size);
|
||||
memset(pad_buf, 0, s->cluster_size);
|
||||
memcpy(pad_buf, buf, nb_sectors * BDRV_SECTOR_SIZE);
|
||||
ret = qcow2_write_compressed(bs, sector_num,
|
||||
pad_buf, s->cluster_sectors);
|
||||
qemu_vfree(pad_buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
qemu_iovec_to_buf(qiov, 0, buf, bytes);
|
||||
|
||||
out_buf = g_malloc(s->cluster_size);
|
||||
|
||||
@@ -2599,44 +2647,33 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||
|
||||
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
|
||||
/* could not compress: write normal cluster */
|
||||
ret = qcow2_co_pwritev(bs, offset, bytes, qiov, 0);
|
||||
ret = qcow2_write(bs, sector_num, buf, s->cluster_sectors);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
cluster_offset = qcow2_alloc_compressed_cluster_offset(bs,
|
||||
sector_num << 9, out_len);
|
||||
if (!cluster_offset) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
cluster_offset &= s->cluster_offset_mask;
|
||||
|
||||
ret = qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
|
||||
ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
goto success;
|
||||
}
|
||||
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
cluster_offset =
|
||||
qcow2_alloc_compressed_cluster_offset(bs, offset, out_len);
|
||||
if (!cluster_offset) {
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
cluster_offset &= s->cluster_offset_mask;
|
||||
|
||||
ret = qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
iov = (struct iovec) {
|
||||
.iov_base = out_buf,
|
||||
.iov_len = out_len,
|
||||
};
|
||||
qemu_iovec_init_external(&hd_qiov, &iov, 1);
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
|
||||
ret = bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
success:
|
||||
ret = 0;
|
||||
fail:
|
||||
qemu_vfree(buf);
|
||||
g_free(out_buf);
|
||||
return ret;
|
||||
}
|
||||
@@ -3381,7 +3418,7 @@ BlockDriver bdrv_qcow2 = {
|
||||
.bdrv_co_pwrite_zeroes = qcow2_co_pwrite_zeroes,
|
||||
.bdrv_co_pdiscard = qcow2_co_pdiscard,
|
||||
.bdrv_truncate = qcow2_truncate,
|
||||
.bdrv_co_pwritev_compressed = qcow2_co_pwritev_compressed,
|
||||
.bdrv_write_compressed = qcow2_write_compressed,
|
||||
.bdrv_make_empty = qcow2_make_empty,
|
||||
|
||||
.bdrv_snapshot_create = qcow2_snapshot_create,
|
||||
|
@@ -530,6 +530,7 @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
|
||||
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
||||
bool exact_size);
|
||||
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
|
||||
void qcow2_l2_cache_reset(BlockDriverState *bs);
|
||||
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
|
||||
int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
|
||||
uint8_t *out_buf, const uint8_t *in_buf,
|
||||
|
@@ -737,7 +737,7 @@ static BlockAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
|
||||
void *opaque)
|
||||
{
|
||||
return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov,
|
||||
nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
|
||||
(int64_t) nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
|
||||
RBD_AIO_READ);
|
||||
}
|
||||
|
||||
@@ -749,7 +749,7 @@ static BlockAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
|
||||
void *opaque)
|
||||
{
|
||||
return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov,
|
||||
nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
|
||||
(int64_t) nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
|
||||
RBD_AIO_WRITE);
|
||||
}
|
||||
|
||||
|
@@ -1,659 +0,0 @@
|
||||
/*
|
||||
* Replication Block filter
|
||||
*
|
||||
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
* Copyright (c) 2016 FUJITSU LIMITED
|
||||
*
|
||||
* Author:
|
||||
* Wen Congyang <wency@cn.fujitsu.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "block/nbd.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "block/block_int.h"
|
||||
#include "block/block_backup.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qapi/error.h"
|
||||
#include "replication.h"
|
||||
|
||||
typedef struct BDRVReplicationState {
|
||||
ReplicationMode mode;
|
||||
int replication_state;
|
||||
BdrvChild *active_disk;
|
||||
BdrvChild *hidden_disk;
|
||||
BdrvChild *secondary_disk;
|
||||
char *top_id;
|
||||
ReplicationState *rs;
|
||||
Error *blocker;
|
||||
int orig_hidden_flags;
|
||||
int orig_secondary_flags;
|
||||
int error;
|
||||
} BDRVReplicationState;
|
||||
|
||||
enum {
|
||||
BLOCK_REPLICATION_NONE, /* block replication is not started */
|
||||
BLOCK_REPLICATION_RUNNING, /* block replication is running */
|
||||
BLOCK_REPLICATION_FAILOVER, /* failover is running in background */
|
||||
BLOCK_REPLICATION_FAILOVER_FAILED, /* failover failed */
|
||||
BLOCK_REPLICATION_DONE, /* block replication is done */
|
||||
};
|
||||
|
||||
static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
||||
Error **errp);
|
||||
static void replication_do_checkpoint(ReplicationState *rs, Error **errp);
|
||||
static void replication_get_error(ReplicationState *rs, Error **errp);
|
||||
static void replication_stop(ReplicationState *rs, bool failover,
|
||||
Error **errp);
|
||||
|
||||
#define REPLICATION_MODE "mode"
|
||||
#define REPLICATION_TOP_ID "top-id"
|
||||
static QemuOptsList replication_runtime_opts = {
|
||||
.name = "replication",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(replication_runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = REPLICATION_MODE,
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{
|
||||
.name = REPLICATION_TOP_ID,
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static ReplicationOps replication_ops = {
|
||||
.start = replication_start,
|
||||
.checkpoint = replication_do_checkpoint,
|
||||
.get_error = replication_get_error,
|
||||
.stop = replication_stop,
|
||||
};
|
||||
|
||||
static int replication_open(BlockDriverState *bs, QDict *options,
|
||||
int flags, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
BDRVReplicationState *s = bs->opaque;
|
||||
Error *local_err = NULL;
|
||||
QemuOpts *opts = NULL;
|
||||
const char *mode;
|
||||
const char *top_id;
|
||||
|
||||
ret = -EINVAL;
|
||||
opts = qemu_opts_create(&replication_runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mode = qemu_opt_get(opts, REPLICATION_MODE);
|
||||
if (!mode) {
|
||||
error_setg(&local_err, "Missing the option mode");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!strcmp(mode, "primary")) {
|
||||
s->mode = REPLICATION_MODE_PRIMARY;
|
||||
} else if (!strcmp(mode, "secondary")) {
|
||||
s->mode = REPLICATION_MODE_SECONDARY;
|
||||
top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
|
||||
s->top_id = g_strdup(top_id);
|
||||
if (!s->top_id) {
|
||||
error_setg(&local_err, "Missing the option top-id");
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
error_setg(&local_err,
|
||||
"The option mode's value should be primary or secondary");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->rs = replication_new(bs, &replication_ops);
|
||||
|
||||
ret = 0;
|
||||
|
||||
fail:
|
||||
qemu_opts_del(opts);
|
||||
error_propagate(errp, local_err);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void replication_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVReplicationState *s = bs->opaque;
|
||||
|
||||
if (s->replication_state == BLOCK_REPLICATION_RUNNING) {
|
||||
replication_stop(s->rs, false, NULL);
|
||||
}
|
||||
|
||||
if (s->mode == REPLICATION_MODE_SECONDARY) {
|
||||
g_free(s->top_id);
|
||||
}
|
||||
|
||||
replication_remove(s->rs);
|
||||
}
|
||||
|
||||
static int64_t replication_getlength(BlockDriverState *bs)
|
||||
{
|
||||
return bdrv_getlength(bs->file->bs);
|
||||
}
|
||||
|
||||
static int replication_get_io_status(BDRVReplicationState *s)
|
||||
{
|
||||
switch (s->replication_state) {
|
||||
case BLOCK_REPLICATION_NONE:
|
||||
return -EIO;
|
||||
case BLOCK_REPLICATION_RUNNING:
|
||||
return 0;
|
||||
case BLOCK_REPLICATION_FAILOVER:
|
||||
return s->mode == REPLICATION_MODE_PRIMARY ? -EIO : 0;
|
||||
case BLOCK_REPLICATION_FAILOVER_FAILED:
|
||||
return s->mode == REPLICATION_MODE_PRIMARY ? -EIO : 1;
|
||||
case BLOCK_REPLICATION_DONE:
|
||||
/*
|
||||
* active commit job completes, and active disk and secondary_disk
|
||||
* is swapped, so we can operate bs->file directly
|
||||
*/
|
||||
return s->mode == REPLICATION_MODE_PRIMARY ? -EIO : 0;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static int replication_return_value(BDRVReplicationState *s, int ret)
|
||||
{
|
||||
if (s->mode == REPLICATION_MODE_SECONDARY) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
s->error = ret;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static coroutine_fn int replication_co_readv(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int remaining_sectors,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
BDRVReplicationState *s = bs->opaque;
|
||||
BdrvChild *child = s->secondary_disk;
|
||||
BlockJob *job = NULL;
|
||||
CowRequest req;
|
||||
int ret;
|
||||
|
||||
if (s->mode == REPLICATION_MODE_PRIMARY) {
|
||||
/* We only use it to forward primary write requests */
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = replication_get_io_status(s);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (child && child->bs) {
|
||||
job = child->bs->job;
|
||||
}
|
||||
|
||||
if (job) {
|
||||
backup_wait_for_overlapping_requests(child->bs->job, sector_num,
|
||||
remaining_sectors);
|
||||
backup_cow_request_begin(&req, child->bs->job, sector_num,
|
||||
remaining_sectors);
|
||||
ret = bdrv_co_readv(bs->file, sector_num, remaining_sectors,
|
||||
qiov);
|
||||
backup_cow_request_end(&req);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = bdrv_co_readv(bs->file, sector_num, remaining_sectors, qiov);
|
||||
out:
|
||||
return replication_return_value(s, ret);
|
||||
}
|
||||
|
||||
static coroutine_fn int replication_co_writev(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int remaining_sectors,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
BDRVReplicationState *s = bs->opaque;
|
||||
QEMUIOVector hd_qiov;
|
||||
uint64_t bytes_done = 0;
|
||||
BdrvChild *top = bs->file;
|
||||
BdrvChild *base = s->secondary_disk;
|
||||
BdrvChild *target;
|
||||
int ret, n;
|
||||
|
||||
ret = replication_get_io_status(s);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ret = bdrv_co_writev(top, sector_num,
|
||||
remaining_sectors, qiov);
|
||||
return replication_return_value(s, ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Failover failed, only write to active disk if the sectors
|
||||
* have already been allocated in active disk/hidden disk.
|
||||
*/
|
||||
qemu_iovec_init(&hd_qiov, qiov->niov);
|
||||
while (remaining_sectors > 0) {
|
||||
ret = bdrv_is_allocated_above(top->bs, base->bs, sector_num,
|
||||
remaining_sectors, &n);
|
||||
if (ret < 0) {
|
||||
goto out1;
|
||||
}
|
||||
|
||||
qemu_iovec_reset(&hd_qiov);
|
||||
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, n * BDRV_SECTOR_SIZE);
|
||||
|
||||
target = ret ? top : base;
|
||||
ret = bdrv_co_writev(target, sector_num, n, &hd_qiov);
|
||||
if (ret < 0) {
|
||||
goto out1;
|
||||
}
|
||||
|
||||
remaining_sectors -= n;
|
||||
sector_num += n;
|
||||
bytes_done += n * BDRV_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
out1:
|
||||
qemu_iovec_destroy(&hd_qiov);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool replication_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate)
|
||||
{
|
||||
return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
|
||||
}
|
||||
|
||||
static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
if (!s->secondary_disk->bs->job) {
|
||||
error_setg(errp, "Backup job was cancelled unexpectedly");
|
||||
return;
|
||||
}
|
||||
|
||||
backup_do_checkpoint(s->secondary_disk->bs->job, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = s->active_disk->bs->drv->bdrv_make_empty(s->active_disk->bs);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot make active disk empty");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = s->hidden_disk->bs->drv->bdrv_make_empty(s->hidden_disk->bs);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot make hidden disk empty");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void reopen_backing_file(BDRVReplicationState *s, bool writable,
|
||||
Error **errp)
|
||||
{
|
||||
BlockReopenQueue *reopen_queue = NULL;
|
||||
int orig_hidden_flags, orig_secondary_flags;
|
||||
int new_hidden_flags, new_secondary_flags;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (writable) {
|
||||
orig_hidden_flags = s->orig_hidden_flags =
|
||||
bdrv_get_flags(s->hidden_disk->bs);
|
||||
new_hidden_flags = (orig_hidden_flags | BDRV_O_RDWR) &
|
||||
~BDRV_O_INACTIVE;
|
||||
orig_secondary_flags = s->orig_secondary_flags =
|
||||
bdrv_get_flags(s->secondary_disk->bs);
|
||||
new_secondary_flags = (orig_secondary_flags | BDRV_O_RDWR) &
|
||||
~BDRV_O_INACTIVE;
|
||||
} else {
|
||||
orig_hidden_flags = (s->orig_hidden_flags | BDRV_O_RDWR) &
|
||||
~BDRV_O_INACTIVE;
|
||||
new_hidden_flags = s->orig_hidden_flags;
|
||||
orig_secondary_flags = (s->orig_secondary_flags | BDRV_O_RDWR) &
|
||||
~BDRV_O_INACTIVE;
|
||||
new_secondary_flags = s->orig_secondary_flags;
|
||||
}
|
||||
|
||||
if (orig_hidden_flags != new_hidden_flags) {
|
||||
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL,
|
||||
new_hidden_flags);
|
||||
}
|
||||
|
||||
if (!(orig_secondary_flags & BDRV_O_RDWR)) {
|
||||
reopen_queue = bdrv_reopen_queue(reopen_queue, s->secondary_disk->bs,
|
||||
NULL, new_secondary_flags);
|
||||
}
|
||||
|
||||
if (reopen_queue) {
|
||||
bdrv_reopen_multiple(reopen_queue, &local_err);
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
}
|
||||
|
||||
static void backup_job_cleanup(BDRVReplicationState *s)
|
||||
{
|
||||
BlockDriverState *top_bs;
|
||||
|
||||
top_bs = bdrv_lookup_bs(s->top_id, s->top_id, NULL);
|
||||
if (!top_bs) {
|
||||
return;
|
||||
}
|
||||
bdrv_op_unblock_all(top_bs, s->blocker);
|
||||
error_free(s->blocker);
|
||||
reopen_backing_file(s, false, NULL);
|
||||
}
|
||||
|
||||
static void backup_job_completed(void *opaque, int ret)
|
||||
{
|
||||
BDRVReplicationState *s = opaque;
|
||||
|
||||
if (s->replication_state != BLOCK_REPLICATION_FAILOVER) {
|
||||
/* The backup job is cancelled unexpectedly */
|
||||
s->error = -EIO;
|
||||
}
|
||||
|
||||
backup_job_cleanup(s);
|
||||
}
|
||||
|
||||
static bool check_top_bs(BlockDriverState *top_bs, BlockDriverState *bs)
|
||||
{
|
||||
BdrvChild *child;
|
||||
|
||||
/* The bs itself is the top_bs */
|
||||
if (top_bs == bs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Iterate over top_bs's children */
|
||||
QLIST_FOREACH(child, &top_bs->children, next) {
|
||||
if (child->bs == bs || check_top_bs(child->bs, bs)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = rs->opaque;
|
||||
BDRVReplicationState *s;
|
||||
BlockDriverState *top_bs;
|
||||
int64_t active_length, hidden_length, disk_length;
|
||||
AioContext *aio_context;
|
||||
Error *local_err = NULL;
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
s = bs->opaque;
|
||||
|
||||
if (s->replication_state != BLOCK_REPLICATION_NONE) {
|
||||
error_setg(errp, "Block replication is running or done");
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->mode != mode) {
|
||||
error_setg(errp, "The parameter mode's value is invalid, needs %d,"
|
||||
" but got %d", s->mode, mode);
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (s->mode) {
|
||||
case REPLICATION_MODE_PRIMARY:
|
||||
break;
|
||||
case REPLICATION_MODE_SECONDARY:
|
||||
s->active_disk = bs->file;
|
||||
if (!s->active_disk || !s->active_disk->bs ||
|
||||
!s->active_disk->bs->backing) {
|
||||
error_setg(errp, "Active disk doesn't have backing file");
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
s->hidden_disk = s->active_disk->bs->backing;
|
||||
if (!s->hidden_disk->bs || !s->hidden_disk->bs->backing) {
|
||||
error_setg(errp, "Hidden disk doesn't have backing file");
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
s->secondary_disk = s->hidden_disk->bs->backing;
|
||||
if (!s->secondary_disk->bs || !bdrv_has_blk(s->secondary_disk->bs)) {
|
||||
error_setg(errp, "The secondary disk doesn't have block backend");
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
/* verify the length */
|
||||
active_length = bdrv_getlength(s->active_disk->bs);
|
||||
hidden_length = bdrv_getlength(s->hidden_disk->bs);
|
||||
disk_length = bdrv_getlength(s->secondary_disk->bs);
|
||||
if (active_length < 0 || hidden_length < 0 || disk_length < 0 ||
|
||||
active_length != hidden_length || hidden_length != disk_length) {
|
||||
error_setg(errp, "Active disk, hidden disk, secondary disk's length"
|
||||
" are not the same");
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->active_disk->bs->drv->bdrv_make_empty ||
|
||||
!s->hidden_disk->bs->drv->bdrv_make_empty) {
|
||||
error_setg(errp,
|
||||
"Active disk or hidden disk doesn't support make_empty");
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
/* reopen the backing file in r/w mode */
|
||||
reopen_backing_file(s, true, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
/* start backup job now */
|
||||
error_setg(&s->blocker,
|
||||
"Block device is in use by internal backup job");
|
||||
|
||||
top_bs = bdrv_lookup_bs(s->top_id, s->top_id, NULL);
|
||||
if (!top_bs || !bdrv_is_root_node(top_bs) ||
|
||||
!check_top_bs(top_bs, bs)) {
|
||||
error_setg(errp, "No top_bs or it is invalid");
|
||||
reopen_backing_file(s, false, NULL);
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
bdrv_op_block_all(top_bs, s->blocker);
|
||||
bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker);
|
||||
|
||||
backup_start("replication-backup", s->secondary_disk->bs,
|
||||
s->hidden_disk->bs, 0, MIRROR_SYNC_MODE_NONE, NULL, false,
|
||||
BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
|
||||
backup_job_completed, s, NULL, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
backup_job_cleanup(s);
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
aio_context_release(aio_context);
|
||||
abort();
|
||||
}
|
||||
|
||||
s->replication_state = BLOCK_REPLICATION_RUNNING;
|
||||
|
||||
if (s->mode == REPLICATION_MODE_SECONDARY) {
|
||||
secondary_do_checkpoint(s, errp);
|
||||
}
|
||||
|
||||
s->error = 0;
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static void replication_do_checkpoint(ReplicationState *rs, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = rs->opaque;
|
||||
BDRVReplicationState *s;
|
||||
AioContext *aio_context;
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
s = bs->opaque;
|
||||
|
||||
if (s->mode == REPLICATION_MODE_SECONDARY) {
|
||||
secondary_do_checkpoint(s, errp);
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static void replication_get_error(ReplicationState *rs, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = rs->opaque;
|
||||
BDRVReplicationState *s;
|
||||
AioContext *aio_context;
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
s = bs->opaque;
|
||||
|
||||
if (s->replication_state != BLOCK_REPLICATION_RUNNING) {
|
||||
error_setg(errp, "Block replication is not running");
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->error) {
|
||||
error_setg(errp, "I/O error occurred");
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static void replication_done(void *opaque, int ret)
|
||||
{
|
||||
BlockDriverState *bs = opaque;
|
||||
BDRVReplicationState *s = bs->opaque;
|
||||
|
||||
if (ret == 0) {
|
||||
s->replication_state = BLOCK_REPLICATION_DONE;
|
||||
|
||||
/* refresh top bs's filename */
|
||||
bdrv_refresh_filename(bs);
|
||||
s->active_disk = NULL;
|
||||
s->secondary_disk = NULL;
|
||||
s->hidden_disk = NULL;
|
||||
s->error = 0;
|
||||
} else {
|
||||
s->replication_state = BLOCK_REPLICATION_FAILOVER_FAILED;
|
||||
s->error = -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = rs->opaque;
|
||||
BDRVReplicationState *s;
|
||||
AioContext *aio_context;
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
s = bs->opaque;
|
||||
|
||||
if (s->replication_state != BLOCK_REPLICATION_RUNNING) {
|
||||
error_setg(errp, "Block replication is not running");
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (s->mode) {
|
||||
case REPLICATION_MODE_PRIMARY:
|
||||
s->replication_state = BLOCK_REPLICATION_DONE;
|
||||
s->error = 0;
|
||||
break;
|
||||
case REPLICATION_MODE_SECONDARY:
|
||||
/*
|
||||
* This BDS will be closed, and the job should be completed
|
||||
* before the BDS is closed, because we will access hidden
|
||||
* disk, secondary disk in backup_job_completed().
|
||||
*/
|
||||
if (s->secondary_disk->bs->job) {
|
||||
block_job_cancel_sync(s->secondary_disk->bs->job);
|
||||
}
|
||||
|
||||
if (!failover) {
|
||||
secondary_do_checkpoint(s, errp);
|
||||
s->replication_state = BLOCK_REPLICATION_DONE;
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
s->replication_state = BLOCK_REPLICATION_FAILOVER;
|
||||
commit_active_start("replication-commit", s->active_disk->bs,
|
||||
s->secondary_disk->bs, 0, BLOCKDEV_ON_ERROR_REPORT,
|
||||
replication_done,
|
||||
bs, errp, true);
|
||||
break;
|
||||
default:
|
||||
aio_context_release(aio_context);
|
||||
abort();
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
BlockDriver bdrv_replication = {
|
||||
.format_name = "replication",
|
||||
.protocol_name = "replication",
|
||||
.instance_size = sizeof(BDRVReplicationState),
|
||||
|
||||
.bdrv_open = replication_open,
|
||||
.bdrv_close = replication_close,
|
||||
|
||||
.bdrv_getlength = replication_getlength,
|
||||
.bdrv_co_readv = replication_co_readv,
|
||||
.bdrv_co_writev = replication_co_writev,
|
||||
|
||||
.is_filter = true,
|
||||
.bdrv_recurse_is_first_non_filter = replication_recurse_is_first_non_filter,
|
||||
|
||||
.has_variable_length = true,
|
||||
};
|
||||
|
||||
static void bdrv_replication_init(void)
|
||||
{
|
||||
bdrv_register(&bdrv_replication);
|
||||
}
|
||||
|
||||
block_init(bdrv_replication_init);
|
@@ -1049,7 +1049,7 @@ static int parse_vdiname(BDRVSheepdogState *s, const char *filename,
|
||||
const char *host_spec, *vdi_spec;
|
||||
int nr_sep, ret;
|
||||
|
||||
strstart(filename, "sheepdog:", &filename);
|
||||
strstart(filename, "sheepdog:", (const char **)&filename);
|
||||
p = q = g_strdup(filename);
|
||||
|
||||
/* count the number of separators */
|
||||
@@ -2652,7 +2652,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
req.opcode = SD_OP_READ_VDIS;
|
||||
req.data_length = max;
|
||||
|
||||
ret = do_req(fd, s->aio_context, &req,
|
||||
ret = do_req(fd, s->aio_context, (SheepdogReq *)&req,
|
||||
vdi_inuse, &wlen, &rlen);
|
||||
|
||||
closesocket(fd);
|
||||
@@ -2820,8 +2820,9 @@ static coroutine_fn int sd_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
||||
iov.iov_len = sizeof(zero);
|
||||
discard_iov.iov = &iov;
|
||||
discard_iov.niov = 1;
|
||||
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||
assert((count & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||
if (!QEMU_IS_ALIGNED(offset | count, BDRV_SECTOR_SIZE)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
acb = sd_aio_setup(bs, &discard_iov, offset >> BDRV_SECTOR_BITS,
|
||||
count >> BDRV_SECTOR_BITS);
|
||||
acb->aiocb_type = AIOCB_DISCARD_OBJ;
|
||||
|
@@ -168,6 +168,22 @@ static BlockBackend *throttle_group_next_blk(BlockBackend *blk)
|
||||
return blk_by_public(next);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return whether a BlockBackend has pending requests.
|
||||
*
|
||||
* This assumes that tg->lock is held.
|
||||
*
|
||||
* @blk: the BlockBackend
|
||||
* @is_write: the type of operation (read/write)
|
||||
* @ret: whether the BlockBackend has pending requests.
|
||||
*/
|
||||
static inline bool blk_has_pending_reqs(BlockBackend *blk,
|
||||
bool is_write)
|
||||
{
|
||||
const BlockBackendPublic *blkp = blk_get_public(blk);
|
||||
return blkp->pending_reqs[is_write];
|
||||
}
|
||||
|
||||
/* Return the next BlockBackend in the round-robin sequence with pending I/O
|
||||
* requests.
|
||||
*
|
||||
@@ -188,7 +204,7 @@ static BlockBackend *next_throttle_token(BlockBackend *blk, bool is_write)
|
||||
|
||||
/* get next bs round in round robin style */
|
||||
token = throttle_group_next_blk(token);
|
||||
while (token != start && !blkp->pending_reqs[is_write]) {
|
||||
while (token != start && !blk_has_pending_reqs(token, is_write)) {
|
||||
token = throttle_group_next_blk(token);
|
||||
}
|
||||
|
||||
@@ -196,10 +212,13 @@ static BlockBackend *next_throttle_token(BlockBackend *blk, bool is_write)
|
||||
* then decide the token is the current bs because chances are
|
||||
* the current bs get the current request queued.
|
||||
*/
|
||||
if (token == start && !blkp->pending_reqs[is_write]) {
|
||||
if (token == start && !blk_has_pending_reqs(token, is_write)) {
|
||||
token = blk;
|
||||
}
|
||||
|
||||
/* Either we return the original BB, or one with pending requests */
|
||||
assert(token == blk || blk_has_pending_reqs(token, is_write));
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
@@ -257,7 +276,7 @@ static void schedule_next_request(BlockBackend *blk, bool is_write)
|
||||
|
||||
/* Check if there's any pending request to schedule next */
|
||||
token = next_throttle_token(blk, is_write);
|
||||
if (!blkp->pending_reqs[is_write]) {
|
||||
if (!blk_has_pending_reqs(token, is_write)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -271,7 +290,7 @@ static void schedule_next_request(BlockBackend *blk, bool is_write)
|
||||
qemu_co_queue_next(&blkp->throttled_reqs[is_write])) {
|
||||
token = blk;
|
||||
} else {
|
||||
ThrottleTimers *tt = &blkp->throttle_timers;
|
||||
ThrottleTimers *tt = &blk_get_public(token)->throttle_timers;
|
||||
int64_t now = qemu_clock_get_ns(tt->clock_type);
|
||||
timer_mod(tt->timers[is_write], now + 1);
|
||||
tg->any_timer_armed[is_write] = true;
|
||||
|
73
block/vdi.c
73
block/vdi.c
@@ -58,7 +58,14 @@
|
||||
#include "migration/migration.h"
|
||||
#include "qemu/coroutine.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/uuid.h"
|
||||
|
||||
#if defined(CONFIG_UUID)
|
||||
#include <uuid/uuid.h>
|
||||
#else
|
||||
/* TODO: move uuid emulation to some central place in QEMU. */
|
||||
#include "sysemu/sysemu.h" /* UUID_FMT */
|
||||
typedef unsigned char uuid_t[16];
|
||||
#endif
|
||||
|
||||
/* Code configuration options. */
|
||||
|
||||
@@ -133,6 +140,28 @@
|
||||
#define VDI_DISK_SIZE_MAX ((uint64_t)VDI_BLOCKS_IN_IMAGE_MAX * \
|
||||
(uint64_t)DEFAULT_CLUSTER_SIZE)
|
||||
|
||||
#if !defined(CONFIG_UUID)
|
||||
static inline void uuid_generate(uuid_t out)
|
||||
{
|
||||
memset(out, 0, sizeof(uuid_t));
|
||||
}
|
||||
|
||||
static inline int uuid_is_null(const uuid_t uu)
|
||||
{
|
||||
uuid_t null_uuid = { 0 };
|
||||
return memcmp(uu, null_uuid, sizeof(uuid_t)) == 0;
|
||||
}
|
||||
|
||||
# if defined(CONFIG_VDI_DEBUG)
|
||||
static inline void uuid_unparse(const uuid_t uu, char *out)
|
||||
{
|
||||
snprintf(out, 37, UUID_FMT,
|
||||
uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7],
|
||||
uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
char text[0x40];
|
||||
uint32_t signature;
|
||||
@@ -153,10 +182,10 @@ typedef struct {
|
||||
uint32_t block_extra; /* unused here */
|
||||
uint32_t blocks_in_image;
|
||||
uint32_t blocks_allocated;
|
||||
QemuUUID uuid_image;
|
||||
QemuUUID uuid_last_snap;
|
||||
QemuUUID uuid_link;
|
||||
QemuUUID uuid_parent;
|
||||
uuid_t uuid_image;
|
||||
uuid_t uuid_last_snap;
|
||||
uuid_t uuid_link;
|
||||
uuid_t uuid_parent;
|
||||
uint64_t unused2[7];
|
||||
} QEMU_PACKED VdiHeader;
|
||||
|
||||
@@ -177,6 +206,16 @@ typedef struct {
|
||||
Error *migration_blocker;
|
||||
} BDRVVdiState;
|
||||
|
||||
/* Change UUID from little endian (IPRT = VirtualBox format) to big endian
|
||||
* format (network byte order, standard, see RFC 4122) and vice versa.
|
||||
*/
|
||||
static void uuid_convert(uuid_t uuid)
|
||||
{
|
||||
bswap32s((uint32_t *)&uuid[0]);
|
||||
bswap16s((uint16_t *)&uuid[4]);
|
||||
bswap16s((uint16_t *)&uuid[6]);
|
||||
}
|
||||
|
||||
static void vdi_header_to_cpu(VdiHeader *header)
|
||||
{
|
||||
le32_to_cpus(&header->signature);
|
||||
@@ -195,10 +234,10 @@ static void vdi_header_to_cpu(VdiHeader *header)
|
||||
le32_to_cpus(&header->block_extra);
|
||||
le32_to_cpus(&header->blocks_in_image);
|
||||
le32_to_cpus(&header->blocks_allocated);
|
||||
qemu_uuid_bswap(&header->uuid_image);
|
||||
qemu_uuid_bswap(&header->uuid_last_snap);
|
||||
qemu_uuid_bswap(&header->uuid_link);
|
||||
qemu_uuid_bswap(&header->uuid_parent);
|
||||
uuid_convert(header->uuid_image);
|
||||
uuid_convert(header->uuid_last_snap);
|
||||
uuid_convert(header->uuid_link);
|
||||
uuid_convert(header->uuid_parent);
|
||||
}
|
||||
|
||||
static void vdi_header_to_le(VdiHeader *header)
|
||||
@@ -219,10 +258,10 @@ static void vdi_header_to_le(VdiHeader *header)
|
||||
cpu_to_le32s(&header->block_extra);
|
||||
cpu_to_le32s(&header->blocks_in_image);
|
||||
cpu_to_le32s(&header->blocks_allocated);
|
||||
qemu_uuid_bswap(&header->uuid_image);
|
||||
qemu_uuid_bswap(&header->uuid_last_snap);
|
||||
qemu_uuid_bswap(&header->uuid_link);
|
||||
qemu_uuid_bswap(&header->uuid_parent);
|
||||
uuid_convert(header->uuid_image);
|
||||
uuid_convert(header->uuid_last_snap);
|
||||
uuid_convert(header->uuid_link);
|
||||
uuid_convert(header->uuid_parent);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_VDI_DEBUG)
|
||||
@@ -430,11 +469,11 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
(uint64_t)header.blocks_in_image * header.block_size);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (!qemu_uuid_is_null(&header.uuid_link)) {
|
||||
} else if (!uuid_is_null(header.uuid_link)) {
|
||||
error_setg(errp, "unsupported VDI image (non-NULL link UUID)");
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (!qemu_uuid_is_null(&header.uuid_parent)) {
|
||||
} else if (!uuid_is_null(header.uuid_parent)) {
|
||||
error_setg(errp, "unsupported VDI image (non-NULL parent UUID)");
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
@@ -782,8 +821,8 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
if (image_type == VDI_TYPE_STATIC) {
|
||||
header.blocks_allocated = blocks;
|
||||
}
|
||||
qemu_uuid_generate(&header.uuid_image);
|
||||
qemu_uuid_generate(&header.uuid_last_snap);
|
||||
uuid_generate(header.uuid_image);
|
||||
uuid_generate(header.uuid_last_snap);
|
||||
/* There is no need to set header.uuid_link or header.uuid_parent here. */
|
||||
#if defined(CONFIG_VDI_DEBUG)
|
||||
vdi_header_print(&header);
|
||||
|
@@ -21,6 +21,9 @@
|
||||
#include "qemu/bswap.h"
|
||||
#include "block/vhdx.h"
|
||||
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
|
||||
/*
|
||||
* All the VHDX formats on disk are little endian - the following
|
||||
* are helper import/export functions to correctly convert
|
||||
|
@@ -25,7 +25,8 @@
|
||||
#include "qemu/bswap.h"
|
||||
#include "block/vhdx.h"
|
||||
#include "migration/migration.h"
|
||||
#include "qemu/uuid.h"
|
||||
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
/* Options for VHDX creation */
|
||||
|
||||
@@ -212,11 +213,11 @@ bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset)
|
||||
*/
|
||||
void vhdx_guid_generate(MSGUID *guid)
|
||||
{
|
||||
QemuUUID uuid;
|
||||
uuid_t uuid;
|
||||
assert(guid != NULL);
|
||||
|
||||
qemu_uuid_generate(&uuid);
|
||||
memcpy(guid, &uuid, sizeof(MSGUID));
|
||||
uuid_generate(uuid);
|
||||
memcpy(guid, uuid, sizeof(MSGUID));
|
||||
}
|
||||
|
||||
/* Check for region overlaps inside the VHDX image */
|
||||
|
55
block/vmdk.c
55
block/vmdk.c
@@ -1645,11 +1645,56 @@ vmdk_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
vmdk_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov)
|
||||
typedef struct VmdkWriteCompressedCo {
|
||||
BlockDriverState *bs;
|
||||
int64_t sector_num;
|
||||
const uint8_t *buf;
|
||||
int nb_sectors;
|
||||
int ret;
|
||||
} VmdkWriteCompressedCo;
|
||||
|
||||
static void vmdk_co_write_compressed(void *opaque)
|
||||
{
|
||||
return vmdk_co_pwritev(bs, offset, bytes, qiov, 0);
|
||||
VmdkWriteCompressedCo *co = opaque;
|
||||
QEMUIOVector local_qiov;
|
||||
uint64_t offset = co->sector_num * BDRV_SECTOR_SIZE;
|
||||
uint64_t bytes = co->nb_sectors * BDRV_SECTOR_SIZE;
|
||||
|
||||
struct iovec iov = (struct iovec) {
|
||||
.iov_base = (uint8_t*) co->buf,
|
||||
.iov_len = bytes,
|
||||
};
|
||||
qemu_iovec_init_external(&local_qiov, &iov, 1);
|
||||
|
||||
co->ret = vmdk_pwritev(co->bs, offset, bytes, &local_qiov, false, false);
|
||||
}
|
||||
|
||||
static int vmdk_write_compressed(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
const uint8_t *buf,
|
||||
int nb_sectors)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
|
||||
if (s->num_extents == 1 && s->extents[0].compressed) {
|
||||
Coroutine *co;
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
VmdkWriteCompressedCo data = {
|
||||
.bs = bs,
|
||||
.sector_num = sector_num,
|
||||
.buf = buf,
|
||||
.nb_sectors = nb_sectors,
|
||||
.ret = -EINPROGRESS,
|
||||
};
|
||||
co = qemu_coroutine_create(vmdk_co_write_compressed, &data);
|
||||
qemu_coroutine_enter(co);
|
||||
while (data.ret == -EINPROGRESS) {
|
||||
aio_poll(aio_context, true);
|
||||
}
|
||||
return data.ret;
|
||||
} else {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static int coroutine_fn vmdk_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
@@ -2348,7 +2393,7 @@ static BlockDriver bdrv_vmdk = {
|
||||
.bdrv_reopen_prepare = vmdk_reopen_prepare,
|
||||
.bdrv_co_preadv = vmdk_co_preadv,
|
||||
.bdrv_co_pwritev = vmdk_co_pwritev,
|
||||
.bdrv_co_pwritev_compressed = vmdk_co_pwritev_compressed,
|
||||
.bdrv_write_compressed = vmdk_write_compressed,
|
||||
.bdrv_co_pwrite_zeroes = vmdk_co_pwrite_zeroes,
|
||||
.bdrv_close = vmdk_close,
|
||||
.bdrv_create = vmdk_create,
|
||||
|
10
block/vpc.c
10
block/vpc.c
@@ -30,7 +30,9 @@
|
||||
#include "qemu/module.h"
|
||||
#include "migration/migration.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "qemu/uuid.h"
|
||||
#if defined(CONFIG_UUID)
|
||||
#include <uuid/uuid.h>
|
||||
#endif
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
@@ -87,7 +89,7 @@ typedef struct vhd_footer {
|
||||
uint32_t checksum;
|
||||
|
||||
/* UUID used to identify a parent hard disk (backing file) */
|
||||
QemuUUID uuid;
|
||||
uint8_t uuid[16];
|
||||
|
||||
uint8_t in_saved_state;
|
||||
} QEMU_PACKED VHDFooter;
|
||||
@@ -978,7 +980,9 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
|
||||
footer->type = cpu_to_be32(disk_type);
|
||||
|
||||
qemu_uuid_generate(&footer->uuid);
|
||||
#if defined(CONFIG_UUID)
|
||||
uuid_generate(footer->uuid);
|
||||
#endif
|
||||
|
||||
footer->checksum = cpu_to_be32(vpc_checksum(buf, HEADER_SIZE));
|
||||
|
||||
|
@@ -2971,8 +2971,7 @@ static BlockDriver vvfat_write_target = {
|
||||
static void vvfat_qcow_options(int *child_flags, QDict *child_options,
|
||||
int parent_flags, QDict *parent_options)
|
||||
{
|
||||
qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
|
||||
*child_flags = BDRV_O_NO_FLUSH;
|
||||
*child_flags = BDRV_O_RDWR | BDRV_O_NO_FLUSH;
|
||||
}
|
||||
|
||||
static const BdrvChildRole child_vvfat_qcow = {
|
||||
|
@@ -145,8 +145,7 @@ void qmp_nbd_server_start(SocketAddress *addr,
|
||||
void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = NULL;
|
||||
BlockBackend *on_eject_blk;
|
||||
BlockBackend *blk;
|
||||
NBDExport *exp;
|
||||
|
||||
if (!nbd_server) {
|
||||
@@ -159,22 +158,26 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
||||
return;
|
||||
}
|
||||
|
||||
on_eject_blk = blk_by_name(device);
|
||||
|
||||
bs = bdrv_lookup_bs(device, device, errp);
|
||||
if (!bs) {
|
||||
blk = blk_by_name(device);
|
||||
if (!blk) {
|
||||
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
||||
"Device '%s' not found", device);
|
||||
return;
|
||||
}
|
||||
if (!blk_is_inserted(blk)) {
|
||||
error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!has_writable) {
|
||||
writable = false;
|
||||
}
|
||||
if (bdrv_is_read_only(bs)) {
|
||||
if (blk_is_read_only(blk)) {
|
||||
writable = false;
|
||||
}
|
||||
|
||||
exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY,
|
||||
NULL, false, on_eject_blk, errp);
|
||||
exp = nbd_export_new(blk, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, NULL,
|
||||
errp);
|
||||
if (!exp) {
|
||||
return;
|
||||
}
|
||||
|
691
blockdev.c
691
blockdev.c
File diff suppressed because it is too large
Load Diff
@@ -132,10 +132,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
||||
|
||||
if (job_id == NULL) {
|
||||
job_id = bdrv_get_device_name(bs);
|
||||
if (!*job_id) {
|
||||
error_setg(errp, "An explicit job ID is required for this node");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!id_wellformed(job_id)) {
|
||||
|
148
configure
vendored
148
configure
vendored
@@ -212,6 +212,7 @@ sdlabi=""
|
||||
virtfs=""
|
||||
vnc="yes"
|
||||
sparse="no"
|
||||
uuid=""
|
||||
vde=""
|
||||
vnc_sasl=""
|
||||
vnc_jpeg=""
|
||||
@@ -228,7 +229,6 @@ xfs=""
|
||||
|
||||
vhost_net="no"
|
||||
vhost_scsi="no"
|
||||
vhost_vsock="no"
|
||||
kvm="no"
|
||||
rdma=""
|
||||
gprof="no"
|
||||
@@ -316,10 +316,10 @@ vte=""
|
||||
virglrenderer=""
|
||||
tpm="yes"
|
||||
libssh2=""
|
||||
vhdx=""
|
||||
numa=""
|
||||
tcmalloc="no"
|
||||
jemalloc="no"
|
||||
replication="yes"
|
||||
|
||||
# parse CC options first
|
||||
for opt do
|
||||
@@ -388,11 +388,7 @@ sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}"
|
||||
ARFLAGS="${ARFLAGS-rv}"
|
||||
|
||||
# default flags for all hosts
|
||||
# We use -fwrapv to tell the compiler that we require a C dialect where
|
||||
# left shift of signed integers is well defined and has the expected
|
||||
# 2s-complement style results. (Both clang and gcc agree that it
|
||||
# provides these semantics.)
|
||||
QEMU_CFLAGS="-fno-strict-aliasing -fno-common -fwrapv $QEMU_CFLAGS"
|
||||
QEMU_CFLAGS="-fno-strict-aliasing -fno-common $QEMU_CFLAGS"
|
||||
QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
|
||||
QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
|
||||
QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
|
||||
@@ -509,6 +505,8 @@ elif check_define __arm__ ; then
|
||||
cpu="arm"
|
||||
elif check_define __aarch64__ ; then
|
||||
cpu="aarch64"
|
||||
elif check_define __hppa__ ; then
|
||||
cpu="hppa"
|
||||
else
|
||||
cpu=$(uname -m)
|
||||
fi
|
||||
@@ -676,7 +674,6 @@ Haiku)
|
||||
kvm="yes"
|
||||
vhost_net="yes"
|
||||
vhost_scsi="yes"
|
||||
vhost_vsock="yes"
|
||||
QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers -I$(pwd)/linux-headers $QEMU_INCLUDES"
|
||||
;;
|
||||
esac
|
||||
@@ -885,6 +882,10 @@ for opt do
|
||||
;;
|
||||
--disable-slirp) slirp="no"
|
||||
;;
|
||||
--disable-uuid) uuid="no"
|
||||
;;
|
||||
--enable-uuid) uuid="yes"
|
||||
;;
|
||||
--disable-vde) vde="no"
|
||||
;;
|
||||
--enable-vde) vde="yes"
|
||||
@@ -1016,10 +1017,6 @@ for opt do
|
||||
;;
|
||||
--enable-vhost-scsi) vhost_scsi="yes"
|
||||
;;
|
||||
--disable-vhost-vsock) vhost_vsock="no"
|
||||
;;
|
||||
--enable-vhost-vsock) vhost_vsock="yes"
|
||||
;;
|
||||
--disable-opengl) opengl="no"
|
||||
;;
|
||||
--enable-opengl) opengl="yes"
|
||||
@@ -1097,12 +1094,6 @@ for opt do
|
||||
--disable-virtio-blk-data-plane|--enable-virtio-blk-data-plane)
|
||||
echo "$0: $opt is obsolete, virtio-blk data-plane is always on" >&2
|
||||
;;
|
||||
--enable-vhdx|--disable-vhdx)
|
||||
echo "$0: $opt is obsolete, VHDX driver is always built" >&2
|
||||
;;
|
||||
--enable-uuid|--disable-uuid)
|
||||
echo "$0: $opt is obsolete, UUID support is always built" >&2
|
||||
;;
|
||||
--disable-gtk) gtk="no"
|
||||
;;
|
||||
--enable-gtk) gtk="yes"
|
||||
@@ -1143,6 +1134,10 @@ for opt do
|
||||
;;
|
||||
--enable-libssh2) libssh2="yes"
|
||||
;;
|
||||
--enable-vhdx) vhdx="yes"
|
||||
;;
|
||||
--disable-vhdx) vhdx="no"
|
||||
;;
|
||||
--disable-numa) numa="no"
|
||||
;;
|
||||
--enable-numa) numa="yes"
|
||||
@@ -1155,10 +1150,6 @@ for opt do
|
||||
;;
|
||||
--enable-jemalloc) jemalloc="yes"
|
||||
;;
|
||||
--disable-replication) replication="no"
|
||||
;;
|
||||
--enable-replication) replication="yes"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: unknown option $opt"
|
||||
echo "Try '$0 --help' for more information"
|
||||
@@ -1361,6 +1352,7 @@ disabled with --disable-FEATURE, default is enabled if available:
|
||||
bluez bluez stack connectivity
|
||||
kvm KVM acceleration support
|
||||
rdma RDMA-based migration support
|
||||
uuid uuid support
|
||||
vde support for vde network
|
||||
netmap support for netmap network
|
||||
linux-aio Linux AIO support
|
||||
@@ -1384,10 +1376,10 @@ disabled with --disable-FEATURE, default is enabled if available:
|
||||
archipelago Archipelago backend
|
||||
tpm TPM support
|
||||
libssh2 ssh block device support
|
||||
vhdx support for the Microsoft VHDX image format
|
||||
numa libnuma support
|
||||
tcmalloc tcmalloc support
|
||||
jemalloc jemalloc support
|
||||
replication replication support
|
||||
|
||||
NOTE: The object files are built at the place where configure is launched
|
||||
EOF
|
||||
@@ -1796,19 +1788,28 @@ fi
|
||||
##########################################
|
||||
# avx2 optimization requirement check
|
||||
|
||||
cat > $TMPC << EOF
|
||||
|
||||
if test "$static" = "no" ; then
|
||||
cat > $TMPC << EOF
|
||||
#pragma GCC push_options
|
||||
#pragma GCC target("avx2")
|
||||
#include <cpuid.h>
|
||||
#include <immintrin.h>
|
||||
|
||||
static int bar(void *a) {
|
||||
__m256i x = *(__m256i *)a;
|
||||
return _mm256_testz_si256(x, x);
|
||||
return _mm256_movemask_epi8(_mm256_cmpeq_epi8(*(__m256i *)a, (__m256i){0}));
|
||||
}
|
||||
int main(int argc, char *argv[]) { return bar(argv[0]); }
|
||||
static void *bar_ifunc(void) {return (void*) bar;}
|
||||
int foo(void *a) __attribute__((ifunc("bar_ifunc")));
|
||||
int main(int argc, char *argv[]) { return foo(argv[0]);}
|
||||
EOF
|
||||
if compile_object "" ; then
|
||||
avx2_opt="yes"
|
||||
if compile_object "" ; then
|
||||
if has readelf; then
|
||||
if readelf --syms $TMPO 2>/dev/null |grep -q "IFUNC.*foo"; then
|
||||
avx2_opt="yes"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
#########################################
|
||||
@@ -2655,6 +2656,47 @@ if compile_prog "" "" ; then
|
||||
fnmatch="yes"
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# uuid_generate() probe, used for vdi block driver
|
||||
# Note that on some systems (notably MacOSX) no extra library
|
||||
# need be linked to get the uuid functions.
|
||||
if test "$uuid" != "no" ; then
|
||||
uuid_libs="-luuid"
|
||||
cat > $TMPC << EOF
|
||||
#include <uuid/uuid.h>
|
||||
int main(void)
|
||||
{
|
||||
uuid_t my_uuid;
|
||||
uuid_generate(my_uuid);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
uuid="yes"
|
||||
elif compile_prog "" "$uuid_libs" ; then
|
||||
uuid="yes"
|
||||
libs_softmmu="$uuid_libs $libs_softmmu"
|
||||
libs_tools="$uuid_libs $libs_tools"
|
||||
else
|
||||
if test "$uuid" = "yes" ; then
|
||||
feature_not_found "uuid" "Install libuuid devel"
|
||||
fi
|
||||
uuid=no
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$vhdx" = "yes" ; then
|
||||
if test "$uuid" = "no" ; then
|
||||
error_exit "uuid required for VHDX support"
|
||||
fi
|
||||
elif test "$vhdx" != "no" ; then
|
||||
if test "$uuid" = "yes" ; then
|
||||
vhdx=yes
|
||||
else
|
||||
vhdx=no
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# xfsctl() probe, used for raw-posix
|
||||
if test "$xfs" != "no" ; then
|
||||
@@ -2967,7 +3009,7 @@ fi
|
||||
|
||||
# g_test_trap_subprocess added in 2.38. Used by some tests.
|
||||
glib_subprocess=yes
|
||||
if test "$mingw32" = "yes" || ! $pkg_config --atleast-version=2.38 glib-2.0; then
|
||||
if ! $pkg_config --atleast-version=2.38 glib-2.0; then
|
||||
glib_subprocess=no
|
||||
fi
|
||||
|
||||
@@ -4028,7 +4070,7 @@ EOF
|
||||
if compile_prog "$vss_win32_include" "" ; then
|
||||
guest_agent_with_vss="yes"
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $vss_win32_include"
|
||||
libs_qga="-lole32 -loleaut32 -lshlwapi -lstdc++ -Wl,--enable-stdcall-fixup $libs_qga"
|
||||
libs_qga="-lole32 -loleaut32 -lshlwapi -luuid -lstdc++ -Wl,--enable-stdcall-fixup $libs_qga"
|
||||
qga_vss_provider="qga/vss-win32/qga-vss.dll qga/vss-win32/qga-vss.tlb"
|
||||
else
|
||||
if test "$vss_win32_sdk" != "" ; then
|
||||
@@ -4149,18 +4191,6 @@ if compile_prog "" "" ; then
|
||||
posix_madvise=yes
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# check if we have posix_syslog
|
||||
|
||||
posix_syslog=no
|
||||
cat > $TMPC << EOF
|
||||
#include <syslog.h>
|
||||
int main(void) { openlog("qemu", LOG_PID, LOG_DAEMON); syslog(LOG_INFO, "configure"); return 0; }
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
posix_syslog=yes
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# check if trace backend exists
|
||||
|
||||
@@ -4531,6 +4561,7 @@ if test "$libnfs" != "no" ; then
|
||||
if $pkg_config --atleast-version=1.9.3 libnfs; then
|
||||
libnfs="yes"
|
||||
libnfs_libs=$($pkg_config --libs libnfs)
|
||||
LIBS="$LIBS $libnfs_libs"
|
||||
else
|
||||
if test "$libnfs" = "yes" ; then
|
||||
feature_not_found "libnfs" "Install libnfs devel >= 1.9.3"
|
||||
@@ -4836,10 +4867,10 @@ echo "preadv support $preadv"
|
||||
echo "fdatasync $fdatasync"
|
||||
echo "madvise $madvise"
|
||||
echo "posix_madvise $posix_madvise"
|
||||
echo "uuid support $uuid"
|
||||
echo "libcap-ng support $cap_ng"
|
||||
echo "vhost-net support $vhost_net"
|
||||
echo "vhost-scsi support $vhost_scsi"
|
||||
echo "vhost-vsock support $vhost_vsock"
|
||||
echo "Trace backends $trace_backends"
|
||||
if have_backend "simple"; then
|
||||
echo "Trace output file $trace_file-<pid>"
|
||||
@@ -4869,6 +4900,7 @@ echo "TPM support $tpm"
|
||||
echo "libssh2 support $libssh2"
|
||||
echo "TPM passthrough $tpm_passthrough"
|
||||
echo "QOM debugging $qom_cast_debug"
|
||||
echo "vhdx $vhdx"
|
||||
echo "lzo support $lzo"
|
||||
echo "snappy support $snappy"
|
||||
echo "bzip2 support $bzip2"
|
||||
@@ -4876,7 +4908,6 @@ echo "NUMA host support $numa"
|
||||
echo "tcmalloc support $tcmalloc"
|
||||
echo "jemalloc support $jemalloc"
|
||||
echo "avx2 optimization $avx2_opt"
|
||||
echo "replication support $replication"
|
||||
|
||||
if test "$sdl_too_old" = "yes"; then
|
||||
echo "-> Your SDL version is too old - please upgrade to have SDL support"
|
||||
@@ -5025,6 +5056,9 @@ fi
|
||||
if test "$fnmatch" = "yes" ; then
|
||||
echo "CONFIG_FNMATCH=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$uuid" = "yes" ; then
|
||||
echo "CONFIG_UUID=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$xfs" = "yes" ; then
|
||||
echo "CONFIG_XFS=y" >> $config_host_mak
|
||||
fi
|
||||
@@ -5218,9 +5252,6 @@ fi
|
||||
if test "$vhost_net" = "yes" ; then
|
||||
echo "CONFIG_VHOST_NET_USED=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$vhost_vsock" = "yes" ; then
|
||||
echo "CONFIG_VHOST_VSOCK=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$blobs" = "yes" ; then
|
||||
echo "INSTALL_BLOBS=yes" >> $config_host_mak
|
||||
fi
|
||||
@@ -5298,8 +5329,7 @@ if test "$libiscsi" = "yes" ; then
|
||||
fi
|
||||
|
||||
if test "$libnfs" = "yes" ; then
|
||||
echo "CONFIG_LIBNFS=m" >> $config_host_mak
|
||||
echo "LIBNFS_LIBS=$libnfs_libs" >> $config_host_mak
|
||||
echo "CONFIG_LIBNFS=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$seccomp" = "yes"; then
|
||||
@@ -5391,6 +5421,10 @@ if test "$libssh2" = "yes" ; then
|
||||
echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$vhdx" = "yes" ; then
|
||||
echo "CONFIG_VHDX=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
# USB host support
|
||||
if test "$libusb" = "yes"; then
|
||||
echo "HOST_USB=libusb legacy" >> $config_host_mak
|
||||
@@ -5434,13 +5468,6 @@ if have_backend "ftrace"; then
|
||||
feature_not_found "ftrace(trace backend)" "ftrace requires Linux"
|
||||
fi
|
||||
fi
|
||||
if have_backend "syslog"; then
|
||||
if test "$posix_syslog" = "yes" ; then
|
||||
echo "CONFIG_TRACE_SYSLOG=y" >> $config_host_mak
|
||||
else
|
||||
feature_not_found "syslog(trace backend)" "syslog not available"
|
||||
fi
|
||||
fi
|
||||
echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
|
||||
|
||||
if test "$rdma" = "yes" ; then
|
||||
@@ -5451,10 +5478,6 @@ if test "$have_rtnetlink" = "yes" ; then
|
||||
echo "CONFIG_RTNETLINK=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$replication" = "yes" ; then
|
||||
echo "CONFIG_REPLICATION=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
# Hold two types of flag:
|
||||
# CONFIG_THREAD_SETNAME_BYTHREAD - we've got a way of setting the name on
|
||||
# a thread we have a handle to
|
||||
@@ -5841,6 +5864,9 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
|
||||
cris)
|
||||
disas_config "CRIS"
|
||||
;;
|
||||
hppa)
|
||||
disas_config "HPPA"
|
||||
;;
|
||||
i386|x86_64|x32)
|
||||
disas_config "I386"
|
||||
;;
|
||||
|
118
cpu-exec.c
118
cpu-exec.c
@@ -147,8 +147,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
||||
itb->tc_ptr, itb->pc, lookup_symbol(itb->pc));
|
||||
|
||||
#if defined(DEBUG_DISAS)
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)
|
||||
&& qemu_log_in_addr_range(itb->pc)) {
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
|
||||
#if defined(TARGET_I386)
|
||||
log_cpu_state(cpu, CPU_DUMP_CCOP);
|
||||
#elif defined(TARGET_M68K)
|
||||
@@ -242,8 +241,7 @@ static bool tb_cmp(const void *p, const void *d)
|
||||
if (tb->pc == desc->pc &&
|
||||
tb->page_addr[0] == desc->phys_page1 &&
|
||||
tb->cs_base == desc->cs_base &&
|
||||
tb->flags == desc->flags &&
|
||||
!atomic_read(&tb->invalid)) {
|
||||
tb->flags == desc->flags) {
|
||||
/* check next page if needed */
|
||||
if (tb->page_addr[1] == -1) {
|
||||
return true;
|
||||
@@ -261,7 +259,7 @@ static bool tb_cmp(const void *p, const void *d)
|
||||
return false;
|
||||
}
|
||||
|
||||
static TranslationBlock *tb_htable_lookup(CPUState *cpu,
|
||||
static TranslationBlock *tb_find_physical(CPUState *cpu,
|
||||
target_ulong pc,
|
||||
target_ulong cs_base,
|
||||
uint32_t flags)
|
||||
@@ -280,48 +278,72 @@ static TranslationBlock *tb_htable_lookup(CPUState *cpu,
|
||||
return qht_lookup(&tcg_ctx.tb_ctx.htable, tb_cmp, &desc, h);
|
||||
}
|
||||
|
||||
static inline TranslationBlock *tb_find(CPUState *cpu,
|
||||
TranslationBlock *last_tb,
|
||||
int tb_exit)
|
||||
static TranslationBlock *tb_find_slow(CPUState *cpu,
|
||||
target_ulong pc,
|
||||
target_ulong cs_base,
|
||||
uint32_t flags)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
|
||||
tb = tb_find_physical(cpu, pc, cs_base, flags);
|
||||
if (tb) {
|
||||
goto found;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* mmap_lock is needed by tb_gen_code, and mmap_lock must be
|
||||
* taken outside tb_lock. Since we're momentarily dropping
|
||||
* tb_lock, there's a chance that our desired tb has been
|
||||
* translated.
|
||||
*/
|
||||
tb_unlock();
|
||||
mmap_lock();
|
||||
tb_lock();
|
||||
tb = tb_find_physical(cpu, pc, cs_base, flags);
|
||||
if (tb) {
|
||||
mmap_unlock();
|
||||
goto found;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* if no translated code available, then translate it now */
|
||||
tb = tb_gen_code(cpu, pc, cs_base, flags, 0);
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
mmap_unlock();
|
||||
#endif
|
||||
|
||||
found:
|
||||
/* we add the TB in the virtual pc hash table */
|
||||
cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
|
||||
return tb;
|
||||
}
|
||||
|
||||
static inline TranslationBlock *tb_find_fast(CPUState *cpu,
|
||||
TranslationBlock **last_tb,
|
||||
int tb_exit)
|
||||
{
|
||||
CPUArchState *env = (CPUArchState *)cpu->env_ptr;
|
||||
TranslationBlock *tb;
|
||||
target_ulong cs_base, pc;
|
||||
uint32_t flags;
|
||||
bool have_tb_lock = false;
|
||||
|
||||
/* we record a subset of the CPU state. It will
|
||||
always be the same before a given translated block
|
||||
is executed. */
|
||||
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||
tb = atomic_rcu_read(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]);
|
||||
tb_lock();
|
||||
tb = cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
|
||||
if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
|
||||
tb->flags != flags)) {
|
||||
tb = tb_htable_lookup(cpu, pc, cs_base, flags);
|
||||
if (!tb) {
|
||||
|
||||
/* mmap_lock is needed by tb_gen_code, and mmap_lock must be
|
||||
* taken outside tb_lock. As system emulation is currently
|
||||
* single threaded the locks are NOPs.
|
||||
*/
|
||||
mmap_lock();
|
||||
tb_lock();
|
||||
have_tb_lock = true;
|
||||
|
||||
/* There's a chance that our desired tb has been translated while
|
||||
* taking the locks so we check again inside the lock.
|
||||
*/
|
||||
tb = tb_htable_lookup(cpu, pc, cs_base, flags);
|
||||
if (!tb) {
|
||||
/* if no translated code available, then translate it now */
|
||||
tb = tb_gen_code(cpu, pc, cs_base, flags, 0);
|
||||
}
|
||||
|
||||
mmap_unlock();
|
||||
}
|
||||
|
||||
/* We add the TB in the virtual pc hash table for the fast lookup */
|
||||
atomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb);
|
||||
tb = tb_find_slow(cpu, pc, cs_base, flags);
|
||||
}
|
||||
if (cpu->tb_flushed) {
|
||||
/* Ensure that no TB jump will be modified as the
|
||||
* translation buffer has been flushed.
|
||||
*/
|
||||
*last_tb = NULL;
|
||||
cpu->tb_flushed = false;
|
||||
}
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* We don't take care of direct jumps when address mapping changes in
|
||||
@@ -329,25 +351,14 @@ static inline TranslationBlock *tb_find(CPUState *cpu,
|
||||
* spanning two pages because the mapping for the second page can change.
|
||||
*/
|
||||
if (tb->page_addr[1] != -1) {
|
||||
last_tb = NULL;
|
||||
*last_tb = NULL;
|
||||
}
|
||||
#endif
|
||||
/* See if we can patch the calling TB. */
|
||||
if (last_tb && !qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) {
|
||||
if (!have_tb_lock) {
|
||||
tb_lock();
|
||||
have_tb_lock = true;
|
||||
}
|
||||
/* Check if translation buffer has been flushed */
|
||||
if (cpu->tb_flushed) {
|
||||
cpu->tb_flushed = false;
|
||||
} else if (!tb->invalid) {
|
||||
tb_add_jump(last_tb, tb_exit, tb);
|
||||
}
|
||||
}
|
||||
if (have_tb_lock) {
|
||||
tb_unlock();
|
||||
if (*last_tb && !qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) {
|
||||
tb_add_jump(*last_tb, tb_exit, tb);
|
||||
}
|
||||
tb_unlock();
|
||||
return tb;
|
||||
}
|
||||
|
||||
@@ -426,7 +437,8 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
||||
} else if (replay_has_exception()
|
||||
&& cpu->icount_decr.u16.low + cpu->icount_extra == 0) {
|
||||
/* try to cause an exception pending in the log */
|
||||
cpu_exec_nocache(cpu, 1, tb_find(cpu, NULL, 0), true);
|
||||
TranslationBlock *last_tb = NULL; /* Avoid chaining TBs */
|
||||
cpu_exec_nocache(cpu, 1, tb_find_fast(cpu, &last_tb, 0), true);
|
||||
*ret = -1;
|
||||
return true;
|
||||
#endif
|
||||
@@ -606,10 +618,10 @@ int cpu_exec(CPUState *cpu)
|
||||
break;
|
||||
}
|
||||
|
||||
atomic_mb_set(&cpu->tb_flushed, false); /* reset before first TB lookup */
|
||||
cpu->tb_flushed = false; /* reset before first TB lookup */
|
||||
for(;;) {
|
||||
cpu_handle_interrupt(cpu, &last_tb);
|
||||
tb = tb_find(cpu, last_tb, tb_exit);
|
||||
tb = tb_find_fast(cpu, &last_tb, tb_exit);
|
||||
cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit, &sc);
|
||||
/* Try to align the host and virtual clocks
|
||||
if the guest is in advance */
|
||||
|
28
cpus.c
28
cpus.c
@@ -191,12 +191,8 @@ int64_t cpu_icount_to_ns(int64_t icount)
|
||||
return icount << icount_time_shift;
|
||||
}
|
||||
|
||||
/* return the time elapsed in VM between vm_start and vm_stop. Unless
|
||||
* icount is active, cpu_get_ticks() uses units of the host CPU cycle
|
||||
* counter.
|
||||
*
|
||||
* Caller must hold the BQL
|
||||
*/
|
||||
/* return the host CPU cycle counter and handle stop/restart */
|
||||
/* Caller must hold the BQL */
|
||||
int64_t cpu_get_ticks(void)
|
||||
{
|
||||
int64_t ticks;
|
||||
@@ -223,19 +219,17 @@ int64_t cpu_get_ticks(void)
|
||||
|
||||
static int64_t cpu_get_clock_locked(void)
|
||||
{
|
||||
int64_t time;
|
||||
int64_t ticks;
|
||||
|
||||
time = timers_state.cpu_clock_offset;
|
||||
ticks = timers_state.cpu_clock_offset;
|
||||
if (timers_state.cpu_ticks_enabled) {
|
||||
time += get_clock();
|
||||
ticks += get_clock();
|
||||
}
|
||||
|
||||
return time;
|
||||
return ticks;
|
||||
}
|
||||
|
||||
/* Return the monotonic time elapsed in VM, i.e.,
|
||||
* the time between vm_start and vm_stop
|
||||
*/
|
||||
/* return the host CPU monotonic timer and handle stop/restart */
|
||||
int64_t cpu_get_clock(void)
|
||||
{
|
||||
int64_t ti;
|
||||
@@ -250,7 +244,7 @@ int64_t cpu_get_clock(void)
|
||||
}
|
||||
|
||||
/* enable cpu_get_ticks()
|
||||
* Caller must hold BQL which serves as mutex for vm_clock_seqlock.
|
||||
* Caller must hold BQL which server as mutex for vm_clock_seqlock.
|
||||
*/
|
||||
void cpu_enable_ticks(void)
|
||||
{
|
||||
@@ -266,7 +260,7 @@ void cpu_enable_ticks(void)
|
||||
|
||||
/* disable cpu_get_ticks() : the clock is stopped. You must not call
|
||||
* cpu_get_ticks() after that.
|
||||
* Caller must hold BQL which serves as mutex for vm_clock_seqlock.
|
||||
* Caller must hold BQL which server as mutex for vm_clock_seqlock.
|
||||
*/
|
||||
void cpu_disable_ticks(void)
|
||||
{
|
||||
@@ -751,7 +745,7 @@ static int do_vm_stop(RunState state)
|
||||
}
|
||||
|
||||
bdrv_drain_all();
|
||||
ret = blk_flush_all();
|
||||
ret = bdrv_flush_all();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1494,7 +1488,7 @@ int vm_stop_force_state(RunState state)
|
||||
bdrv_drain_all();
|
||||
/* Make sure to return an error if the flush in a previous vm_stop()
|
||||
* failed. */
|
||||
return blk_flush_all();
|
||||
return bdrv_flush_all();
|
||||
}
|
||||
}
|
||||
|
||||
|
6
cputlb.c
6
cputlb.c
@@ -543,8 +543,10 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index,
|
||||
#undef MMUSUFFIX
|
||||
|
||||
#define MMUSUFFIX _cmmu
|
||||
#undef GETPC
|
||||
#define GETPC() ((uintptr_t)0)
|
||||
#undef GETPC_ADJ
|
||||
#define GETPC_ADJ 0
|
||||
#undef GETRA
|
||||
#define GETRA() ((uintptr_t)0)
|
||||
#define SOFTMMU_CODE_ACCESS
|
||||
|
||||
#define SHIFT 0
|
||||
|
@@ -29,7 +29,10 @@
|
||||
#include "crypto/pbkdf.h"
|
||||
#include "crypto/secret.h"
|
||||
#include "crypto/random.h"
|
||||
#include "qemu/uuid.h"
|
||||
|
||||
#ifdef CONFIG_UUID
|
||||
#include <uuid/uuid.h>
|
||||
#endif
|
||||
|
||||
#include "qemu/coroutine.h"
|
||||
|
||||
@@ -874,12 +877,18 @@ qcrypto_block_luks_open(QCryptoBlock *block,
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_block_luks_uuid_gen(uint8_t *uuidstr)
|
||||
static int
|
||||
qcrypto_block_luks_uuid_gen(uint8_t *uuidstr, Error **errp)
|
||||
{
|
||||
QemuUUID uuid;
|
||||
qemu_uuid_generate(&uuid);
|
||||
qemu_uuid_unparse(&uuid, (char *)uuidstr);
|
||||
#ifdef CONFIG_UUID
|
||||
uuid_t uuid;
|
||||
uuid_generate(uuid);
|
||||
uuid_unparse(uuid, (char *)uuidstr);
|
||||
return 0;
|
||||
#else
|
||||
error_setg(errp, "Unable to generate uuids on this platform");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -908,12 +917,8 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
||||
const char *hash_alg;
|
||||
char *cipher_mode_spec = NULL;
|
||||
QCryptoCipherAlgorithm ivcipheralg = 0;
|
||||
uint64_t iters;
|
||||
|
||||
memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts));
|
||||
if (!luks_opts.has_iter_time) {
|
||||
luks_opts.iter_time = 2000;
|
||||
}
|
||||
if (!luks_opts.has_cipher_alg) {
|
||||
luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256;
|
||||
}
|
||||
@@ -956,7 +961,10 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
||||
* it out to disk
|
||||
*/
|
||||
luks->header.version = QCRYPTO_BLOCK_LUKS_VERSION;
|
||||
qcrypto_block_luks_uuid_gen(luks->header.uuid);
|
||||
if (qcrypto_block_luks_uuid_gen(luks->header.uuid,
|
||||
errp) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
cipher_alg = qcrypto_block_luks_cipher_alg_lookup(luks_opts.cipher_alg,
|
||||
errp);
|
||||
@@ -1056,40 +1064,26 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
||||
/* Determine how many iterations we need to hash the master
|
||||
* key, in order to have 1 second of compute time used
|
||||
*/
|
||||
iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
|
||||
masterkey, luks->header.key_bytes,
|
||||
luks->header.master_key_salt,
|
||||
QCRYPTO_BLOCK_LUKS_SALT_LEN,
|
||||
QCRYPTO_BLOCK_LUKS_DIGEST_LEN,
|
||||
&local_err);
|
||||
luks->header.master_key_iterations =
|
||||
qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
|
||||
masterkey, luks->header.key_bytes,
|
||||
luks->header.master_key_salt,
|
||||
QCRYPTO_BLOCK_LUKS_SALT_LEN,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (iters > (ULLONG_MAX / luks_opts.iter_time)) {
|
||||
error_setg_errno(errp, ERANGE,
|
||||
"PBKDF iterations %llu too large to scale",
|
||||
(unsigned long long)iters);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* iter_time was in millis, but count_iters reported for secs */
|
||||
iters = iters * luks_opts.iter_time / 1000;
|
||||
|
||||
/* Why /= 8 ? That matches cryptsetup, but there's no
|
||||
* explanation why they chose /= 8... Probably so that
|
||||
* if all 8 keyslots are active we only spend 1 second
|
||||
* in total time to check all keys */
|
||||
iters /= 8;
|
||||
if (iters > UINT32_MAX) {
|
||||
error_setg_errno(errp, ERANGE,
|
||||
"PBKDF iterations %llu larger than %u",
|
||||
(unsigned long long)iters, UINT32_MAX);
|
||||
goto error;
|
||||
}
|
||||
iters = MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS);
|
||||
luks->header.master_key_iterations = iters;
|
||||
luks->header.master_key_iterations /= 8;
|
||||
luks->header.master_key_iterations = MAX(
|
||||
luks->header.master_key_iterations,
|
||||
QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS);
|
||||
|
||||
|
||||
/* Hash the master key, saving the result in the LUKS
|
||||
* header. This hash is used when opening the encrypted
|
||||
@@ -1137,36 +1131,22 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
||||
/* Again we determine how many iterations are required to
|
||||
* hash the user password while consuming 1 second of compute
|
||||
* time */
|
||||
iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
|
||||
(uint8_t *)password, strlen(password),
|
||||
luks->header.key_slots[0].salt,
|
||||
QCRYPTO_BLOCK_LUKS_SALT_LEN,
|
||||
luks->header.key_bytes,
|
||||
&local_err);
|
||||
luks->header.key_slots[0].iterations =
|
||||
qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
|
||||
(uint8_t *)password, strlen(password),
|
||||
luks->header.key_slots[0].salt,
|
||||
QCRYPTO_BLOCK_LUKS_SALT_LEN,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (iters > (ULLONG_MAX / luks_opts.iter_time)) {
|
||||
error_setg_errno(errp, ERANGE,
|
||||
"PBKDF iterations %llu too large to scale",
|
||||
(unsigned long long)iters);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* iter_time was in millis, but count_iters reported for secs */
|
||||
iters = iters * luks_opts.iter_time / 1000;
|
||||
|
||||
if (iters > UINT32_MAX) {
|
||||
error_setg_errno(errp, ERANGE,
|
||||
"PBKDF iterations %llu larger than %u",
|
||||
(unsigned long long)iters, UINT32_MAX);
|
||||
goto error;
|
||||
}
|
||||
|
||||
luks->header.key_slots[0].iterations =
|
||||
MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS);
|
||||
/* Why /= 2 ? That matches cryptsetup, but there's no
|
||||
* explanation why they chose /= 2... */
|
||||
luks->header.key_slots[0].iterations /= 2;
|
||||
luks->header.key_slots[0].iterations = MAX(
|
||||
luks->header.key_slots[0].iterations,
|
||||
QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS);
|
||||
|
||||
|
||||
/* Generate a key that we'll use to encrypt the master
|
||||
|
@@ -59,8 +59,7 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
|
||||
|
||||
if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
|
||||
!qcrypto_block_drivers[options->format]) {
|
||||
error_setg(errp, "Unsupported block driver %s",
|
||||
QCryptoBlockFormat_lookup[options->format]);
|
||||
error_setg(errp, "Unsupported block driver %d", options->format);
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
@@ -89,8 +88,7 @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
|
||||
|
||||
if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
|
||||
!qcrypto_block_drivers[options->format]) {
|
||||
error_setg(errp, "Unsupported block driver %s",
|
||||
QCryptoBlockFormat_lookup[options->format]);
|
||||
error_setg(errp, "Unsupported block driver %d", options->format);
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -244,8 +244,7 @@ static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,
|
||||
if (cipher->mode != QCRYPTO_CIPHER_MODE_CBC &&
|
||||
cipher->mode != QCRYPTO_CIPHER_MODE_ECB &&
|
||||
cipher->mode != QCRYPTO_CIPHER_MODE_XTS) {
|
||||
error_setg(errp, "Unsupported cipher mode %s",
|
||||
QCryptoCipherMode_lookup[cipher->mode]);
|
||||
error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -377,8 +376,7 @@ static int qcrypto_cipher_init_des_rfb(QCryptoCipher *cipher,
|
||||
QCryptoCipherBuiltin *ctxt;
|
||||
|
||||
if (cipher->mode != QCRYPTO_CIPHER_MODE_ECB) {
|
||||
error_setg(errp, "Unsupported cipher mode %s",
|
||||
QCryptoCipherMode_lookup[cipher->mode]);
|
||||
error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -444,8 +442,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
break;
|
||||
default:
|
||||
error_setg(errp,
|
||||
"Unsupported cipher algorithm %s",
|
||||
QCryptoCipherAlgorithm_lookup[cipher->alg]);
|
||||
"Unsupported cipher algorithm %d", cipher->alg);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@@ -70,8 +70,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
gcrymode = GCRY_CIPHER_MODE_CBC;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher mode %s",
|
||||
QCryptoCipherMode_lookup[mode]);
|
||||
error_setg(errp, "Unsupported cipher mode %d", mode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -121,8 +120,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %s",
|
||||
QCryptoCipherAlgorithm_lookup[alg]);
|
||||
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@@ -227,8 +227,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher mode %s",
|
||||
QCryptoCipherMode_lookup[mode]);
|
||||
error_setg(errp, "Unsupported cipher mode %d", mode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -358,8 +357,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %s",
|
||||
QCryptoCipherAlgorithm_lookup[alg]);
|
||||
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -431,8 +429,8 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher mode %s",
|
||||
QCryptoCipherMode_lookup[cipher->mode]);
|
||||
error_setg(errp, "Unsupported cipher algorithm %d",
|
||||
cipher->alg);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -471,8 +469,8 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher mode %s",
|
||||
QCryptoCipherMode_lookup[cipher->mode]);
|
||||
error_setg(errp, "Unsupported cipher algorithm %d",
|
||||
cipher->alg);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@@ -59,7 +59,8 @@
|
||||
|
||||
#if (defined(CONFIG_GCRYPT) && \
|
||||
(!defined(CONFIG_GNUTLS) || \
|
||||
(LIBGNUTLS_VERSION_NUMBER < 0x020c00)) && \
|
||||
!defined(GNUTLS_VERSION_NUMBER) || \
|
||||
(GNUTLS_VERSION_NUMBER < 0x020c00)) && \
|
||||
(!defined(GCRYPT_VERSION_NUMBER) || \
|
||||
(GCRYPT_VERSION_NUMBER < 0x010600)))
|
||||
#define QCRYPTO_INIT_GCRYPT_THREADS
|
||||
|
@@ -28,11 +28,7 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
|
||||
switch (hash) {
|
||||
case QCRYPTO_HASH_ALG_MD5:
|
||||
case QCRYPTO_HASH_ALG_SHA1:
|
||||
case QCRYPTO_HASH_ALG_SHA224:
|
||||
case QCRYPTO_HASH_ALG_SHA256:
|
||||
case QCRYPTO_HASH_ALG_SHA384:
|
||||
case QCRYPTO_HASH_ALG_SHA512:
|
||||
case QCRYPTO_HASH_ALG_RIPEMD160:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -42,33 +38,20 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
|
||||
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
uint64_t iterations,
|
||||
unsigned int iterations,
|
||||
uint8_t *out, size_t nout,
|
||||
Error **errp)
|
||||
{
|
||||
static const int hash_map[QCRYPTO_HASH_ALG__MAX] = {
|
||||
[QCRYPTO_HASH_ALG_MD5] = GCRY_MD_MD5,
|
||||
[QCRYPTO_HASH_ALG_SHA1] = GCRY_MD_SHA1,
|
||||
[QCRYPTO_HASH_ALG_SHA224] = GCRY_MD_SHA224,
|
||||
[QCRYPTO_HASH_ALG_SHA256] = GCRY_MD_SHA256,
|
||||
[QCRYPTO_HASH_ALG_SHA384] = GCRY_MD_SHA384,
|
||||
[QCRYPTO_HASH_ALG_SHA512] = GCRY_MD_SHA512,
|
||||
[QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MD_RMD160,
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (iterations > ULONG_MAX) {
|
||||
error_setg_errno(errp, ERANGE,
|
||||
"PBKDF iterations %llu must be less than %lu",
|
||||
(long long unsigned)iterations, ULONG_MAX);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hash >= G_N_ELEMENTS(hash_map) ||
|
||||
hash_map[hash] == GCRY_MD_NONE) {
|
||||
error_setg_errno(errp, ENOSYS,
|
||||
"PBKDF does not support hash algorithm %s",
|
||||
QCryptoHashAlgorithm_lookup[hash]);
|
||||
error_setg(errp, "Unexpected hash algorithm %d", hash);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <nettle/pbkdf2.h>
|
||||
#include <nettle/hmac.h>
|
||||
#include "qapi/error.h"
|
||||
#include "crypto/pbkdf.h"
|
||||
|
||||
@@ -29,11 +28,7 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
|
||||
{
|
||||
switch (hash) {
|
||||
case QCRYPTO_HASH_ALG_SHA1:
|
||||
case QCRYPTO_HASH_ALG_SHA224:
|
||||
case QCRYPTO_HASH_ALG_SHA256:
|
||||
case QCRYPTO_HASH_ALG_SHA384:
|
||||
case QCRYPTO_HASH_ALG_SHA512:
|
||||
case QCRYPTO_HASH_ALG_RIPEMD160:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -43,74 +38,28 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
|
||||
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
uint64_t iterations,
|
||||
unsigned int iterations,
|
||||
uint8_t *out, size_t nout,
|
||||
Error **errp)
|
||||
{
|
||||
union {
|
||||
struct hmac_md5_ctx md5;
|
||||
struct hmac_sha1_ctx sha1;
|
||||
struct hmac_sha224_ctx sha224;
|
||||
struct hmac_sha256_ctx sha256;
|
||||
struct hmac_sha384_ctx sha384;
|
||||
struct hmac_sha512_ctx sha512;
|
||||
struct hmac_ripemd160_ctx ripemd160;
|
||||
} ctx;
|
||||
|
||||
if (iterations > UINT_MAX) {
|
||||
error_setg_errno(errp, ERANGE,
|
||||
"PBKDF iterations %llu must be less than %u",
|
||||
(long long unsigned)iterations, UINT_MAX);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (hash) {
|
||||
case QCRYPTO_HASH_ALG_MD5:
|
||||
hmac_md5_set_key(&ctx.md5, nkey, key);
|
||||
PBKDF2(&ctx.md5, hmac_md5_update, hmac_md5_digest,
|
||||
MD5_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
|
||||
break;
|
||||
|
||||
case QCRYPTO_HASH_ALG_SHA1:
|
||||
hmac_sha1_set_key(&ctx.sha1, nkey, key);
|
||||
PBKDF2(&ctx.sha1, hmac_sha1_update, hmac_sha1_digest,
|
||||
SHA1_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
|
||||
break;
|
||||
|
||||
case QCRYPTO_HASH_ALG_SHA224:
|
||||
hmac_sha224_set_key(&ctx.sha224, nkey, key);
|
||||
PBKDF2(&ctx.sha224, hmac_sha224_update, hmac_sha224_digest,
|
||||
SHA224_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
|
||||
pbkdf2_hmac_sha1(nkey, key,
|
||||
iterations,
|
||||
nsalt, salt,
|
||||
nout, out);
|
||||
break;
|
||||
|
||||
case QCRYPTO_HASH_ALG_SHA256:
|
||||
hmac_sha256_set_key(&ctx.sha256, nkey, key);
|
||||
PBKDF2(&ctx.sha256, hmac_sha256_update, hmac_sha256_digest,
|
||||
SHA256_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
|
||||
break;
|
||||
|
||||
case QCRYPTO_HASH_ALG_SHA384:
|
||||
hmac_sha384_set_key(&ctx.sha384, nkey, key);
|
||||
PBKDF2(&ctx.sha384, hmac_sha384_update, hmac_sha384_digest,
|
||||
SHA384_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
|
||||
break;
|
||||
|
||||
case QCRYPTO_HASH_ALG_SHA512:
|
||||
hmac_sha512_set_key(&ctx.sha512, nkey, key);
|
||||
PBKDF2(&ctx.sha512, hmac_sha512_update, hmac_sha512_digest,
|
||||
SHA512_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
|
||||
break;
|
||||
|
||||
case QCRYPTO_HASH_ALG_RIPEMD160:
|
||||
hmac_ripemd160_set_key(&ctx.ripemd160, nkey, key);
|
||||
PBKDF2(&ctx.ripemd160, hmac_ripemd160_update, hmac_ripemd160_digest,
|
||||
RIPEMD160_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
|
||||
pbkdf2_hmac_sha256(nkey, key,
|
||||
iterations,
|
||||
nsalt, salt,
|
||||
nout, out);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg_errno(errp, ENOSYS,
|
||||
"PBKDF does not support hash algorithm %s",
|
||||
QCryptoHashAlgorithm_lookup[hash]);
|
||||
"PBKDF does not support hash algorithm %d", hash);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@@ -32,7 +32,7 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash G_GNUC_UNUSED,
|
||||
size_t nkey G_GNUC_UNUSED,
|
||||
const uint8_t *salt G_GNUC_UNUSED,
|
||||
size_t nsalt G_GNUC_UNUSED,
|
||||
uint64_t iterations G_GNUC_UNUSED,
|
||||
unsigned int iterations G_GNUC_UNUSED,
|
||||
uint8_t *out G_GNUC_UNUSED,
|
||||
size_t nout G_GNUC_UNUSED,
|
||||
Error **errp)
|
||||
|
@@ -62,33 +62,29 @@ static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms,
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
size_t nout,
|
||||
Error **errp)
|
||||
int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
Error **errp)
|
||||
{
|
||||
uint64_t ret = -1;
|
||||
uint8_t *out;
|
||||
uint64_t iterations = (1 << 15);
|
||||
uint8_t out[32];
|
||||
long long int iterations = (1 << 15);
|
||||
unsigned long long delta_ms, start_ms, end_ms;
|
||||
|
||||
out = g_new(uint8_t, nout);
|
||||
|
||||
while (1) {
|
||||
if (qcrypto_pbkdf2_get_thread_cpu(&start_ms, errp) < 0) {
|
||||
goto cleanup;
|
||||
return -1;
|
||||
}
|
||||
if (qcrypto_pbkdf2(hash,
|
||||
key, nkey,
|
||||
salt, nsalt,
|
||||
iterations,
|
||||
out, nout,
|
||||
out, sizeof(out),
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
return -1;
|
||||
}
|
||||
if (qcrypto_pbkdf2_get_thread_cpu(&end_ms, errp) < 0) {
|
||||
goto cleanup;
|
||||
return -1;
|
||||
}
|
||||
|
||||
delta_ms = end_ms - start_ms;
|
||||
@@ -104,10 +100,11 @@ uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
|
||||
|
||||
iterations = iterations * 1000 / delta_ms;
|
||||
|
||||
ret = iterations;
|
||||
if (iterations > INT32_MAX) {
|
||||
error_setg(errp, "Iterations %lld too large for a 32-bit int",
|
||||
iterations);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
memset(out, 0, nout);
|
||||
g_free(out);
|
||||
return ret;
|
||||
return iterations;
|
||||
}
|
||||
|
@@ -615,7 +615,7 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
|
||||
}
|
||||
|
||||
if (cert != NULL && key != NULL) {
|
||||
#if LIBGNUTLS_VERSION_NUMBER >= 0x030111
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030111
|
||||
char *password = NULL;
|
||||
if (creds->passwordid) {
|
||||
password = qcrypto_secret_lookup_as_utf8(creds->passwordid,
|
||||
@@ -630,7 +630,7 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
|
||||
password,
|
||||
0);
|
||||
g_free(password);
|
||||
#else /* LIBGNUTLS_VERSION_NUMBER < 0x030111 */
|
||||
#else /* GNUTLS_VERSION_NUMBER < 0x030111 */
|
||||
if (creds->passwordid) {
|
||||
error_setg(errp, "PKCS8 decryption requires GNUTLS >= 3.1.11");
|
||||
goto cleanup;
|
||||
@@ -638,7 +638,7 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
|
||||
ret = gnutls_certificate_set_x509_key_file(creds->data,
|
||||
cert, key,
|
||||
GNUTLS_X509_FMT_PEM);
|
||||
#endif
|
||||
#endif /* GNUTLS_VERSION_NUMBER < 0x030111 */
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot load certificate '%s' & key '%s': %s",
|
||||
cert, key, gnutls_strerror(ret));
|
||||
|
@@ -351,22 +351,16 @@ qcrypto_tls_session_check_credentials(QCryptoTLSSession *session,
|
||||
{
|
||||
if (object_dynamic_cast(OBJECT(session->creds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_ANON)) {
|
||||
trace_qcrypto_tls_session_check_creds(session, "nop");
|
||||
return 0;
|
||||
} else if (object_dynamic_cast(OBJECT(session->creds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_X509)) {
|
||||
if (session->creds->verifyPeer) {
|
||||
int ret = qcrypto_tls_session_check_certificate(session,
|
||||
errp);
|
||||
trace_qcrypto_tls_session_check_creds(session,
|
||||
ret == 0 ? "pass" : "fail");
|
||||
return ret;
|
||||
return qcrypto_tls_session_check_certificate(session,
|
||||
errp);
|
||||
} else {
|
||||
trace_qcrypto_tls_session_check_creds(session, "skip");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
trace_qcrypto_tls_session_check_creds(session, "error");
|
||||
error_setg(errp, "Unexpected credential type %s",
|
||||
object_get_typename(OBJECT(session->creds)));
|
||||
return -1;
|
||||
|
@@ -17,4 +17,3 @@ qcrypto_tls_creds_x509_load_cert_list(void *creds, const char *file) "TLS creds
|
||||
|
||||
# crypto/tlssession.c
|
||||
qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *aclname, int endpoint) "TLS session new session=%p creds=%p hostname=%s aclname=%s endpoint=%d"
|
||||
qcrypto_tls_session_check_creds(void *session, const char *status) "TLS session check creds session=%p status=%s"
|
||||
|
@@ -3,6 +3,7 @@
|
||||
include pci.mak
|
||||
include usb.mak
|
||||
CONFIG_VGA=y
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_NAND=y
|
||||
CONFIG_ECC=y
|
||||
CONFIG_SERIAL=y
|
||||
|
@@ -30,12 +30,14 @@ CONFIG_I8257=y
|
||||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_PIIX=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_PIIX_PCI=y
|
||||
CONFIG_HPET=y
|
||||
CONFIG_APPLESMC=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_TPM_TIS=$(CONFIG_TPM)
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_PAM=y
|
||||
CONFIG_PCI_PIIX=y
|
||||
CONFIG_WDT_IB700=y
|
||||
CONFIG_XEN_I386=$(CONFIG_XEN)
|
||||
|
@@ -3,6 +3,7 @@
|
||||
include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_ESCC=y
|
||||
CONFIG_M48T59=y
|
||||
CONFIG_SERIAL=y
|
||||
|
@@ -4,6 +4,7 @@ include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_VIRTIO_VGA=y
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_ESCC=y
|
||||
CONFIG_M48T59=y
|
||||
CONFIG_SERIAL=y
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
include pci.mak
|
||||
include usb.mak
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_M48T59=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_SERIAL=y
|
||||
|
@@ -30,12 +30,14 @@ CONFIG_I8257=y
|
||||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_PIIX=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_PIIX_PCI=y
|
||||
CONFIG_HPET=y
|
||||
CONFIG_APPLESMC=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_TPM_TIS=$(CONFIG_TPM)
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_PAM=y
|
||||
CONFIG_PCI_PIIX=y
|
||||
CONFIG_WDT_IB700=y
|
||||
CONFIG_XEN_I386=$(CONFIG_XEN)
|
||||
|
2
disas.c
2
disas.c
@@ -310,6 +310,8 @@ void disas(FILE *out, void *code, unsigned long size)
|
||||
print_insn = print_insn_m68k;
|
||||
#elif defined(__s390__)
|
||||
print_insn = print_insn_s390;
|
||||
#elif defined(__hppa__)
|
||||
print_insn = print_insn_hppa;
|
||||
#elif defined(__ia64__)
|
||||
print_insn = print_insn_ia64;
|
||||
#endif
|
||||
|
@@ -9,6 +9,7 @@ libvixldir = $(SRC_PATH)/disas/libvixl
|
||||
# versions do not.
|
||||
arm-a64.o-cflags := -I$(libvixldir) -Wno-sign-compare
|
||||
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
|
||||
|
11
disas/arm.c
11
disas/arm.c
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "disas/bfd.h"
|
||||
#define ISSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n')
|
||||
|
||||
#define ARM_EXT_V1 0
|
||||
#define ARM_EXT_V2 0
|
||||
@@ -72,6 +73,15 @@ static void floatformat_to_double (unsigned char *data, double *dest)
|
||||
|
||||
/* End of qemu specific additions. */
|
||||
|
||||
/* FIXME: Belongs in global header. */
|
||||
#ifndef strneq
|
||||
#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
|
||||
#endif
|
||||
|
||||
#ifndef NUM_ELEM
|
||||
#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0])
|
||||
#endif
|
||||
|
||||
struct opcode32
|
||||
{
|
||||
unsigned long arch; /* Architecture defining this insn. */
|
||||
@@ -1518,6 +1528,7 @@ static const char *const iwmmxt_cregnames[] =
|
||||
/* Default to GCC register name set. */
|
||||
static unsigned int regname_selected = 1;
|
||||
|
||||
#define NUM_ARM_REGNAMES NUM_ELEM (regnames)
|
||||
#define arm_regnames regnames[regname_selected].reg_names
|
||||
|
||||
static bfd_boolean force_thumb = false;
|
||||
|
2832
disas/hppa.c
Normal file
2832
disas/hppa.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -264,6 +264,12 @@ sh_dsp_reg_nums;
|
||||
be some confusion between DSP and FPU etc. */
|
||||
#define SH_ARCH_UNKNOWN_ARCH 0xffffffff
|
||||
|
||||
/* These are defined in bfd/cpu-sh.c . */
|
||||
unsigned int sh_get_arch_from_bfd_mach (unsigned long mach);
|
||||
unsigned int sh_get_arch_up_from_bfd_mach (unsigned long mach);
|
||||
unsigned long sh_get_bfd_mach_from_arch_set (unsigned int arch_set);
|
||||
/* bfd_boolean sh_merge_bfd_arch (bfd *ibfd, bfd *obfd); */
|
||||
|
||||
/* Below are the 'architecture sets'.
|
||||
They describe the following inheritance graph:
|
||||
|
||||
|
@@ -73,6 +73,7 @@ typedef struct {
|
||||
AioContext *ctx;
|
||||
BlockAIOCB *acb;
|
||||
QEMUSGList *sg;
|
||||
uint32_t align;
|
||||
uint64_t offset;
|
||||
DMADirection dir;
|
||||
int sg_cur_index;
|
||||
@@ -160,8 +161,9 @@ static void dma_blk_cb(void *opaque, int ret)
|
||||
return;
|
||||
}
|
||||
|
||||
if (dbs->iov.size & ~BDRV_SECTOR_MASK) {
|
||||
qemu_iovec_discard_back(&dbs->iov, dbs->iov.size & ~BDRV_SECTOR_MASK);
|
||||
if (!QEMU_IS_ALIGNED(dbs->iov.size, dbs->align)) {
|
||||
qemu_iovec_discard_back(&dbs->iov,
|
||||
QEMU_ALIGN_DOWN(dbs->iov.size, dbs->align));
|
||||
}
|
||||
|
||||
dbs->acb = dbs->io_func(dbs->offset, &dbs->iov,
|
||||
@@ -199,7 +201,7 @@ static const AIOCBInfo dma_aiocb_info = {
|
||||
};
|
||||
|
||||
BlockAIOCB *dma_blk_io(AioContext *ctx,
|
||||
QEMUSGList *sg, uint64_t offset,
|
||||
QEMUSGList *sg, uint64_t offset, uint32_t align,
|
||||
DMAIOFunc *io_func, void *io_func_opaque,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, DMADirection dir)
|
||||
@@ -212,6 +214,7 @@ BlockAIOCB *dma_blk_io(AioContext *ctx,
|
||||
dbs->sg = sg;
|
||||
dbs->ctx = ctx;
|
||||
dbs->offset = offset;
|
||||
dbs->align = align;
|
||||
dbs->sg_cur_index = 0;
|
||||
dbs->sg_cur_byte = 0;
|
||||
dbs->dir = dir;
|
||||
@@ -234,11 +237,11 @@ BlockAIOCB *dma_blk_read_io_func(int64_t offset, QEMUIOVector *iov,
|
||||
}
|
||||
|
||||
BlockAIOCB *dma_blk_read(BlockBackend *blk,
|
||||
QEMUSGList *sg, uint64_t offset,
|
||||
QEMUSGList *sg, uint64_t offset, uint32_t align,
|
||||
void (*cb)(void *opaque, int ret), void *opaque)
|
||||
{
|
||||
return dma_blk_io(blk_get_aio_context(blk),
|
||||
sg, offset, dma_blk_read_io_func, blk, cb, opaque,
|
||||
return dma_blk_io(blk_get_aio_context(blk), sg, offset, align,
|
||||
dma_blk_read_io_func, blk, cb, opaque,
|
||||
DMA_DIRECTION_FROM_DEVICE);
|
||||
}
|
||||
|
||||
@@ -252,11 +255,11 @@ BlockAIOCB *dma_blk_write_io_func(int64_t offset, QEMUIOVector *iov,
|
||||
}
|
||||
|
||||
BlockAIOCB *dma_blk_write(BlockBackend *blk,
|
||||
QEMUSGList *sg, uint64_t offset,
|
||||
QEMUSGList *sg, uint64_t offset, uint32_t align,
|
||||
void (*cb)(void *opaque, int ret), void *opaque)
|
||||
{
|
||||
return dma_blk_io(blk_get_aio_context(blk),
|
||||
sg, offset, dma_blk_write_io_func, blk, cb, opaque,
|
||||
return dma_blk_io(blk_get_aio_context(blk), sg, offset, align,
|
||||
dma_blk_write_io_func, blk, cb, opaque,
|
||||
DMA_DIRECTION_TO_DEVICE);
|
||||
}
|
||||
|
||||
|
@@ -1,239 +0,0 @@
|
||||
Block replication
|
||||
----------------------------------------
|
||||
Copyright Fujitsu, Corp. 2016
|
||||
Copyright (c) 2016 Intel Corporation
|
||||
Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
|
||||
|
||||
This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
See the COPYING file in the top-level directory.
|
||||
|
||||
Block replication is used for continuous checkpoints. It is designed
|
||||
for COLO (COarse-grain LOck-stepping) where the Secondary VM is running.
|
||||
It can also be applied for FT/HA (Fault-tolerance/High Assurance) scenario,
|
||||
where the Secondary VM is not running.
|
||||
|
||||
This document gives an overview of block replication's design.
|
||||
|
||||
== Background ==
|
||||
High availability solutions such as micro checkpoint and COLO will do
|
||||
consecutive checkpoints. The VM state of the Primary and Secondary VM is
|
||||
identical right after a VM checkpoint, but becomes different as the VM
|
||||
executes till the next checkpoint. To support disk contents checkpoint,
|
||||
the modified disk contents in the Secondary VM must be buffered, and are
|
||||
only dropped at next checkpoint time. To reduce the network transportation
|
||||
effort during a vmstate checkpoint, the disk modification operations of
|
||||
the Primary disk are asynchronously forwarded to the Secondary node.
|
||||
|
||||
== Workflow ==
|
||||
The following is the image of block replication workflow:
|
||||
|
||||
+----------------------+ +------------------------+
|
||||
|Primary Write Requests| |Secondary Write Requests|
|
||||
+----------------------+ +------------------------+
|
||||
| |
|
||||
| (4)
|
||||
| V
|
||||
| /-------------\
|
||||
| Copy and Forward | |
|
||||
|---------(1)----------+ | Disk Buffer |
|
||||
| | | |
|
||||
| (3) \-------------/
|
||||
| speculative ^
|
||||
| write through (2)
|
||||
| | |
|
||||
V V |
|
||||
+--------------+ +----------------+
|
||||
| Primary Disk | | Secondary Disk |
|
||||
+--------------+ +----------------+
|
||||
|
||||
1) Primary write requests will be copied and forwarded to Secondary
|
||||
QEMU.
|
||||
2) Before Primary write requests are written to Secondary disk, the
|
||||
original sector content will be read from Secondary disk and
|
||||
buffered in the Disk buffer, but it will not overwrite the existing
|
||||
sector content (it could be from either "Secondary Write Requests" or
|
||||
previous COW of "Primary Write Requests") in the Disk buffer.
|
||||
3) Primary write requests will be written to Secondary disk.
|
||||
4) Secondary write requests will be buffered in the Disk buffer and it
|
||||
will overwrite the existing sector content in the buffer.
|
||||
|
||||
== Architecture ==
|
||||
We are going to implement block replication from many basic
|
||||
blocks that are already in QEMU.
|
||||
|
||||
virtio-blk ||
|
||||
^ || .----------
|
||||
| || | Secondary
|
||||
1 Quorum || '----------
|
||||
/ \ ||
|
||||
/ \ ||
|
||||
Primary 2 filter
|
||||
disk ^ virtio-blk
|
||||
| ^
|
||||
3 NBD -------> 3 NBD |
|
||||
client || server 2 filter
|
||||
|| ^ ^
|
||||
--------. || | |
|
||||
Primary | || Secondary disk <--------- hidden-disk 5 <--------- active-disk 4
|
||||
--------' || | backing ^ backing
|
||||
|| | |
|
||||
|| | |
|
||||
|| '-------------------------'
|
||||
|| drive-backup sync=none 6
|
||||
|
||||
1) The disk on the primary is represented by a block device with two
|
||||
children, providing replication between a primary disk and the host that
|
||||
runs the secondary VM. The read pattern (fifo) for quorum can be extended
|
||||
to make the primary always read from the local disk instead of going through
|
||||
NBD.
|
||||
|
||||
2) The new block filter (the name is replication) will control the block
|
||||
replication.
|
||||
|
||||
3) The secondary disk receives writes from the primary VM through QEMU's
|
||||
embedded NBD server (speculative write-through).
|
||||
|
||||
4) The disk on the secondary is represented by a custom block device
|
||||
(called active-disk). It should start as an empty disk, and the format
|
||||
should support bdrv_make_empty() and backing file.
|
||||
|
||||
5) The hidden-disk is created automatically. It buffers the original content
|
||||
that is modified by the primary VM. It should also start as an empty disk,
|
||||
and the driver supports bdrv_make_empty() and backing file.
|
||||
|
||||
6) The drive-backup job (sync=none) is run to allow hidden-disk to buffer
|
||||
any state that would otherwise be lost by the speculative write-through
|
||||
of the NBD server into the secondary disk. So before block replication,
|
||||
the primary disk and secondary disk should contain the same data.
|
||||
|
||||
== Failure Handling ==
|
||||
There are 7 internal errors when block replication is running:
|
||||
1. I/O error on primary disk
|
||||
2. Forwarding primary write requests failed
|
||||
3. Backup failed
|
||||
4. I/O error on secondary disk
|
||||
5. I/O error on active disk
|
||||
6. Making active disk or hidden disk empty failed
|
||||
7. Doing failover failed
|
||||
In case 1 and 5, we just report the error to the disk layer. In case 2, 3,
|
||||
4 and 6, we just report block replication's error to FT/HA manager (which
|
||||
decides when to do a new checkpoint, when to do failover).
|
||||
In case 7, if active commit failed, we use replication failover failed state
|
||||
in Secondary's write operation (what decides which target to write).
|
||||
|
||||
== New block driver interface ==
|
||||
We add four block driver interfaces to control block replication:
|
||||
a. replication_start_all()
|
||||
Start block replication, called in migration/checkpoint thread.
|
||||
We must call block_replication_start_all() in secondary QEMU before
|
||||
calling block_replication_start_all() in primary QEMU. The caller
|
||||
must hold the I/O mutex lock if it is in migration/checkpoint
|
||||
thread.
|
||||
b. replication_do_checkpoint_all()
|
||||
This interface is called after all VM state is transferred to
|
||||
Secondary QEMU. The Disk buffer will be dropped in this interface.
|
||||
The caller must hold the I/O mutex lock if it is in migration/checkpoint
|
||||
thread.
|
||||
c. replication_get_error_all()
|
||||
This interface is called to check if error happened in replication.
|
||||
The caller must hold the I/O mutex lock if it is in migration/checkpoint
|
||||
thread.
|
||||
d. replication_stop_all()
|
||||
It is called on failover. We will flush the Disk buffer into
|
||||
Secondary Disk and stop block replication. The vm should be stopped
|
||||
before calling it if you use this API to shutdown the guest, or other
|
||||
things except failover. The caller must hold the I/O mutex lock if it is
|
||||
in migration/checkpoint thread.
|
||||
|
||||
== Usage ==
|
||||
Primary:
|
||||
-drive if=xxx,driver=quorum,read-pattern=fifo,id=colo1,vote-threshold=1,\
|
||||
children.0.file.filename=1.raw,\
|
||||
children.0.driver=raw
|
||||
|
||||
Run qmp command in primary qemu:
|
||||
{ 'execute': 'human-monitor-command',
|
||||
'arguments': {
|
||||
'command-line': 'drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=xxxx,file.port=xxxx,file.export=colo1,node-name=nbd_client1'
|
||||
}
|
||||
}
|
||||
{ 'execute': 'x-blockdev-change',
|
||||
'arguments': {
|
||||
'parent': 'colo1',
|
||||
'node': 'nbd_client1'
|
||||
}
|
||||
}
|
||||
Note:
|
||||
1. There should be only one NBD Client for each primary disk.
|
||||
2. host is the secondary physical machine's hostname or IP
|
||||
3. Each disk must have its own export name.
|
||||
4. It is all a single argument to -drive and you should ignore the
|
||||
leading whitespace.
|
||||
5. The qmp command line must be run after running qmp command line in
|
||||
secondary qemu.
|
||||
6. After failover we need remove children.1 (replication driver).
|
||||
|
||||
Secondary:
|
||||
-drive if=none,driver=raw,file.filename=1.raw,id=colo1 \
|
||||
-drive if=xxx,id=topxxx,driver=replication,mode=secondary,top-id=topxxx\
|
||||
file.file.filename=active_disk.qcow2,\
|
||||
file.driver=qcow2,\
|
||||
file.backing.file.filename=hidden_disk.qcow2,\
|
||||
file.backing.driver=qcow2,\
|
||||
file.backing.backing=colo1
|
||||
|
||||
Then run qmp command in secondary qemu:
|
||||
{ 'execute': 'nbd-server-start',
|
||||
'arguments': {
|
||||
'addr': {
|
||||
'type': 'inet',
|
||||
'data': {
|
||||
'host': 'xxx',
|
||||
'port': 'xxx'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{ 'execute': 'nbd-server-add',
|
||||
'arguments': {
|
||||
'device': 'colo1',
|
||||
'writable': true
|
||||
}
|
||||
}
|
||||
|
||||
Note:
|
||||
1. The export name in secondary QEMU command line is the secondary
|
||||
disk's id.
|
||||
2. The export name for the same disk must be the same
|
||||
3. The qmp command nbd-server-start and nbd-server-add must be run
|
||||
before running the qmp command migrate on primary QEMU
|
||||
4. Active disk, hidden disk and nbd target's length should be the
|
||||
same.
|
||||
5. It is better to put active disk and hidden disk in ramdisk.
|
||||
6. It is all a single argument to -drive, and you should ignore
|
||||
the leading whitespace.
|
||||
|
||||
After Failover:
|
||||
Primary:
|
||||
The secondary host is down, so we should run the following qmp command
|
||||
to remove the nbd child from the quorum:
|
||||
{ 'execute': 'x-blockdev-change',
|
||||
'arguments': {
|
||||
'parent': 'colo1',
|
||||
'child': 'children.1'
|
||||
}
|
||||
}
|
||||
{ 'execute': 'human-monitor-command',
|
||||
'arguments': {
|
||||
'command-line': 'drive_del xxxx'
|
||||
}
|
||||
}
|
||||
Note: there is no qmp command to remove the blockdev now
|
||||
|
||||
Secondary:
|
||||
The primary host is down, so we should do the following thing:
|
||||
{ 'execute': 'nbd-server-stop' }
|
||||
|
||||
TODO:
|
||||
1. Continuous block replication
|
||||
2. Shared disk
|
@@ -964,9 +964,9 @@ Example:
|
||||
|
||||
Used to generate the marshaling/dispatch functions for the commands
|
||||
defined in the schema. The generated code implements
|
||||
qmp_marshal_COMMAND() (registered automatically), and declares
|
||||
qmp_COMMAND() that the user must implement. The following files are
|
||||
generated:
|
||||
qmp_marshal_COMMAND() (mentioned in qmp-commands.hx, and registered
|
||||
automatically), and declares qmp_COMMAND() that the user must
|
||||
implement. The following files are generated:
|
||||
|
||||
$(prefix)qmp-marshal.c: command marshal/dispatch functions for each
|
||||
QMP command defined in the schema. Functions
|
||||
|
@@ -37,7 +37,7 @@ do not matter; as soon as all previous critical sections have finished,
|
||||
there cannot be any readers who hold references to the data structure,
|
||||
and these can now be safely reclaimed (e.g., freed or unref'ed).
|
||||
|
||||
Here is a picture:
|
||||
Here is a picutre:
|
||||
|
||||
thread 1 thread 2 thread 3
|
||||
------------------- ------------------------ -------------------
|
||||
|
@@ -235,10 +235,7 @@ consider the following values:
|
||||
- Water leaks from the bucket at a rate of 100 IOPS.
|
||||
- Water can be added to the bucket at a rate of 2000 IOPS.
|
||||
- The size of the bucket is 2000 x 60 = 120000
|
||||
- If 'iops-total-max-length' is unset then it defaults to 1 and the
|
||||
size of the bucket is 2000.
|
||||
- If 'iops-total-max' is unset then 'iops-total-max-length' must be
|
||||
unset as well. In this case the bucket size is 100.
|
||||
- If 'iops-total-max' is unset then the bucket size is 100 x 60.
|
||||
|
||||
The bucket is initially empty, therefore water can be added until it's
|
||||
full at a rate of 2000 IOPS (the burst rate). Once the bucket is full
|
||||
|
@@ -192,18 +192,6 @@ After running qemu by root user, you can get the trace:
|
||||
|
||||
Restriction: "ftrace" backend is restricted to Linux only.
|
||||
|
||||
=== Syslog ===
|
||||
|
||||
The "syslog" backend sends trace events using the POSIX syslog API. The log
|
||||
is opened specifying the LOG_DAEMON facility and LOG_PID option (so events
|
||||
are tagged with the pid of the particular QEMU process that generated
|
||||
them). All events are logged at LOG_INFO level.
|
||||
|
||||
NOTE: syslog may squash duplicate consecutive trace events and apply rate
|
||||
limiting.
|
||||
|
||||
Restriction: "syslog" backend is restricted to POSIX compliant OS.
|
||||
|
||||
==== Monitor commands ====
|
||||
|
||||
* trace-file on|off|flush|set <path>
|
||||
|
@@ -119,6 +119,17 @@ There are a few things to be noticed:
|
||||
5. Printing to the terminal is discouraged for QMP commands, we do it here
|
||||
because it's the easiest way to demonstrate a QMP command
|
||||
|
||||
Now a little hack is needed. As we're still using the old QMP server we need
|
||||
to add the new command to its internal dispatch table. This step won't be
|
||||
required in the near future. Open the qmp-commands.hx file and add the
|
||||
following at the bottom:
|
||||
|
||||
{
|
||||
.name = "hello-world",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_hello_world,
|
||||
},
|
||||
|
||||
You're done. Now build qemu, run it as suggested in the "Testing" section,
|
||||
and then type the following QMP command:
|
||||
|
||||
@@ -163,6 +174,21 @@ There are two important details to be noticed:
|
||||
2. The C implementation signature must follow the schema's argument ordering,
|
||||
which is defined by the "data" member
|
||||
|
||||
The last step is to update the qmp-commands.hx file:
|
||||
|
||||
{
|
||||
.name = "hello-world",
|
||||
.args_type = "message:s?",
|
||||
.mhandler.cmd_new = qmp_marshal_hello_world,
|
||||
},
|
||||
|
||||
Notice that the "args_type" member got our "message" argument. The character
|
||||
"s" stands for "string" and "?" means it's optional. This too must be ordered
|
||||
according to the C implementation and schema file. You can look for more
|
||||
examples in the qmp-commands.hx file if you need to define more arguments.
|
||||
|
||||
Again, this step won't be required in the future.
|
||||
|
||||
Time to test our new version of the "hello-world" command. Build qemu, run it as
|
||||
described in the "Testing" section and then send two commands:
|
||||
|
||||
@@ -311,7 +337,7 @@ we should add it to the hmp-commands.hx file:
|
||||
.args_type = "message:s?",
|
||||
.params = "hello-world [message]",
|
||||
.help = "Print message to the standard output",
|
||||
.cmd = hmp_hello_world,
|
||||
.mhandler.cmd = hmp_hello_world,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -428,6 +454,14 @@ There are a number of things to be noticed:
|
||||
6. You have to include the "qmp-commands.h" header file in qemu-timer.c,
|
||||
otherwise qemu won't build
|
||||
|
||||
The last step is to add the correspoding entry in the qmp-commands.hx file:
|
||||
|
||||
{
|
||||
.name = "query-alarm-clock",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_query_alarm_clock,
|
||||
},
|
||||
|
||||
Time to test the new command. Build qemu, run it as described in the "Testing"
|
||||
section and try this:
|
||||
|
||||
@@ -484,7 +518,7 @@ in the monitor.c file. The entry for the "info alarmclock" follows:
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show information about the alarm clock",
|
||||
.cmd = hmp_info_alarm_clock,
|
||||
.mhandler.info = hmp_info_alarm_clock,
|
||||
},
|
||||
|
||||
To test this, run qemu and type "info alarmclock" in the user monitor.
|
||||
@@ -566,6 +600,14 @@ iteration of the loop. That's because the alarm timer method in use is the
|
||||
first element of the alarm_timers array. Also notice that QAPI lists are handled
|
||||
by hand and we return the head of the list.
|
||||
|
||||
To test this you have to add the corresponding qmp-commands.hx entry:
|
||||
|
||||
{
|
||||
.name = "query-alarm-methods",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_query_alarm_methods,
|
||||
},
|
||||
|
||||
Now Build qemu, run it as explained in the "Testing" section and try our new
|
||||
command:
|
||||
|
||||
|
14
exec.c
14
exec.c
@@ -598,14 +598,11 @@ AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx)
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool cpu_index_auto_assigned;
|
||||
|
||||
static int cpu_get_free_index(void)
|
||||
{
|
||||
CPUState *some_cpu;
|
||||
int cpu_index = 0;
|
||||
|
||||
cpu_index_auto_assigned = true;
|
||||
CPU_FOREACH(some_cpu) {
|
||||
cpu_index++;
|
||||
}
|
||||
@@ -617,15 +614,14 @@ void cpu_exec_exit(CPUState *cpu)
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
cpu_list_lock();
|
||||
if (!QTAILQ_IN_USE(cpu, node)) {
|
||||
if (cpu->node.tqe_prev == NULL) {
|
||||
/* there is nothing to undo since cpu_exec_init() hasn't been called */
|
||||
cpu_list_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus, CPUTailQ)));
|
||||
|
||||
QTAILQ_REMOVE(&cpus, cpu, node);
|
||||
cpu->node.tqe_prev = NULL;
|
||||
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
|
||||
cpu_list_unlock();
|
||||
|
||||
@@ -667,8 +663,6 @@ void cpu_exec_init(CPUState *cpu, Error **errp)
|
||||
if (cpu->cpu_index == UNASSIGNED_CPU_INDEX) {
|
||||
cpu->cpu_index = cpu_get_free_index();
|
||||
assert(cpu->cpu_index != UNASSIGNED_CPU_INDEX);
|
||||
} else {
|
||||
assert(!cpu_index_auto_assigned);
|
||||
}
|
||||
QTAILQ_INSERT_TAIL(&cpus, cpu, node);
|
||||
cpu_list_unlock();
|
||||
@@ -1621,8 +1615,10 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
|
||||
if (new_block->host) {
|
||||
qemu_ram_setup_dump(new_block->host, new_block->max_length);
|
||||
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE);
|
||||
/* MADV_DONTFORK is also needed by KVM in absence of synchronous MMU */
|
||||
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK);
|
||||
if (kvm_enabled()) {
|
||||
kvm_setup_guest_memory(new_block->host, new_block->max_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
116
fpu/softfloat.c
116
fpu/softfloat.c
@@ -4814,10 +4814,6 @@ int32_t floatx80_to_int32(floatx80 a, float_status *status)
|
||||
int32_t aExp, shiftCount;
|
||||
uint64_t aSig;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1 << 31;
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@@ -4846,10 +4842,6 @@ int32_t floatx80_to_int32_round_to_zero(floatx80 a, float_status *status)
|
||||
uint64_t aSig, savedASig;
|
||||
int32_t z;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1 << 31;
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@@ -4896,10 +4888,6 @@ int64_t floatx80_to_int64(floatx80 a, float_status *status)
|
||||
int32_t aExp, shiftCount;
|
||||
uint64_t aSig, aSigExtra;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1ULL << 63;
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@@ -4941,10 +4929,6 @@ int64_t floatx80_to_int64_round_to_zero(floatx80 a, float_status *status)
|
||||
uint64_t aSig;
|
||||
int64_t z;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1ULL << 63;
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@@ -4987,10 +4971,6 @@ float32 floatx80_to_float32(floatx80 a, float_status *status)
|
||||
int32_t aExp;
|
||||
uint64_t aSig;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return float32_default_nan(status);
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@@ -5019,10 +4999,6 @@ float64 floatx80_to_float64(floatx80 a, float_status *status)
|
||||
int32_t aExp;
|
||||
uint64_t aSig, zSig;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return float64_default_nan(status);
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@@ -5051,10 +5027,6 @@ float128 floatx80_to_float128(floatx80 a, float_status *status)
|
||||
int aExp;
|
||||
uint64_t aSig, zSig0, zSig1;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return float128_default_nan(status);
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@@ -5080,10 +5052,6 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status)
|
||||
uint64_t lastBitMask, roundBitsMask;
|
||||
floatx80 z;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aExp = extractFloatx80Exp( a );
|
||||
if ( 0x403E <= aExp ) {
|
||||
if ( ( aExp == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) {
|
||||
@@ -5311,10 +5279,6 @@ floatx80 floatx80_add(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSign = extractFloatx80Sign( a );
|
||||
bSign = extractFloatx80Sign( b );
|
||||
if ( aSign == bSign ) {
|
||||
@@ -5336,10 +5300,6 @@ floatx80 floatx80_sub(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSign = extractFloatx80Sign( a );
|
||||
bSign = extractFloatx80Sign( b );
|
||||
if ( aSign == bSign ) {
|
||||
@@ -5363,10 +5323,6 @@ floatx80 floatx80_mul(floatx80 a, floatx80 b, float_status *status)
|
||||
int32_t aExp, bExp, zExp;
|
||||
uint64_t aSig, bSig, zSig0, zSig1;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@@ -5424,10 +5380,6 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status)
|
||||
uint64_t aSig, bSig, zSig0, zSig1;
|
||||
uint64_t rem0, rem1, rem2, term0, term1, term2;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@@ -5509,10 +5461,6 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status)
|
||||
uint64_t aSig0, aSig1, bSig;
|
||||
uint64_t q, term0, term1, alternateASig0, alternateASig1;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSig0 = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@@ -5608,10 +5556,6 @@ floatx80 floatx80_sqrt(floatx80 a, float_status *status)
|
||||
uint64_t aSig0, aSig1, zSig0, zSig1, doubleZSig0;
|
||||
uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSig0 = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@@ -5676,11 +5620,10 @@ floatx80 floatx80_sqrt(floatx80 a, float_status *status)
|
||||
int floatx80_eq(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)
|
||||
|| (extractFloatx80Exp(a) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(a) << 1))
|
||||
|| (extractFloatx80Exp(b) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(b) << 1))
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
||||
) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 0;
|
||||
@@ -5706,11 +5649,10 @@ int floatx80_le(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)
|
||||
|| (extractFloatx80Exp(a) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(a) << 1))
|
||||
|| (extractFloatx80Exp(b) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(b) << 1))
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
||||
) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 0;
|
||||
@@ -5740,11 +5682,10 @@ int floatx80_lt(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)
|
||||
|| (extractFloatx80Exp(a) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(a) << 1))
|
||||
|| (extractFloatx80Exp(b) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(b) << 1))
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
||||
) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 0;
|
||||
@@ -5771,11 +5712,10 @@ int floatx80_lt(floatx80 a, floatx80 b, float_status *status)
|
||||
*----------------------------------------------------------------------------*/
|
||||
int floatx80_unordered(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)
|
||||
|| (extractFloatx80Exp(a) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(a) << 1))
|
||||
|| (extractFloatx80Exp(b) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(b) << 1))
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
||||
) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1;
|
||||
@@ -5793,10 +5733,6 @@ int floatx80_unordered(floatx80 a, floatx80 b, float_status *status)
|
||||
int floatx80_eq_quiet(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 0;
|
||||
}
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
@@ -5828,10 +5764,6 @@ int floatx80_le_quiet(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 0;
|
||||
}
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
@@ -5868,10 +5800,6 @@ int floatx80_lt_quiet(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 0;
|
||||
}
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
@@ -5905,10 +5833,6 @@ int floatx80_lt_quiet(floatx80 a, floatx80 b, float_status *status)
|
||||
*----------------------------------------------------------------------------*/
|
||||
int floatx80_unordered_quiet(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1;
|
||||
}
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
@@ -7450,10 +7374,6 @@ static inline int floatx80_compare_internal(floatx80 a, floatx80 b,
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return float_relation_unordered;
|
||||
}
|
||||
if (( ( extractFloatx80Exp( a ) == 0x7fff ) &&
|
||||
( extractFloatx80Frac( a )<<1 ) ) ||
|
||||
( ( extractFloatx80Exp( b ) == 0x7fff ) &&
|
||||
@@ -7725,10 +7645,6 @@ floatx80 floatx80_scalbn(floatx80 a, int n, float_status *status)
|
||||
int32_t aExp;
|
||||
uint64_t aSig;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
|
@@ -25,6 +25,11 @@ void v9fs_string_free(V9fsString *str)
|
||||
str->size = 0;
|
||||
}
|
||||
|
||||
void v9fs_string_null(V9fsString *str)
|
||||
{
|
||||
v9fs_string_free(str);
|
||||
}
|
||||
|
||||
void GCC_FMT_ATTR(2, 3)
|
||||
v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
|
||||
{
|
||||
|
@@ -77,6 +77,7 @@ static inline void v9fs_string_init(V9fsString *str)
|
||||
str->size = 0;
|
||||
}
|
||||
extern void v9fs_string_free(V9fsString *str);
|
||||
extern void v9fs_string_null(V9fsString *str);
|
||||
extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...);
|
||||
extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs);
|
||||
|
||||
|
@@ -402,9 +402,7 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len)
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* XXX this blocks entire thread. Rewrite to use
|
||||
* qemu_chr_fe_write and background I/O callbacks */
|
||||
qemu_chr_fe_write_all(s->chr, buf, len);
|
||||
qemu_chr_fe_write(s->chr, buf, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -18,7 +18,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the version of QEMU",
|
||||
.cmd = hmp_info_version,
|
||||
.mhandler.cmd = hmp_info_version,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -32,7 +32,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the network state",
|
||||
.cmd = hmp_info_network,
|
||||
.mhandler.cmd = hmp_info_network,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -46,7 +46,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the character devices",
|
||||
.cmd = hmp_info_chardev,
|
||||
.mhandler.cmd = hmp_info_chardev,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -61,7 +61,7 @@ ETEXI
|
||||
.params = "[-n] [-v] [device]",
|
||||
.help = "show info of one block device or all block devices "
|
||||
"(-n: show named nodes; -v: show details)",
|
||||
.cmd = hmp_info_block,
|
||||
.mhandler.cmd = hmp_info_block,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -75,7 +75,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show block device statistics",
|
||||
.cmd = hmp_info_blockstats,
|
||||
.mhandler.cmd = hmp_info_blockstats,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -89,7 +89,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show progress of ongoing block device operations",
|
||||
.cmd = hmp_info_block_jobs,
|
||||
.mhandler.cmd = hmp_info_block_jobs,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -103,7 +103,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the cpu registers",
|
||||
.cmd = hmp_info_registers,
|
||||
.mhandler.cmd = hmp_info_registers,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -118,7 +118,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show local apic state",
|
||||
.cmd = hmp_info_local_apic,
|
||||
.mhandler.cmd = hmp_info_local_apic,
|
||||
},
|
||||
#endif
|
||||
|
||||
@@ -134,7 +134,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show io apic state",
|
||||
.cmd = hmp_info_io_apic,
|
||||
.mhandler.cmd = hmp_info_io_apic,
|
||||
},
|
||||
#endif
|
||||
|
||||
@@ -149,7 +149,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show infos for each CPU",
|
||||
.cmd = hmp_info_cpus,
|
||||
.mhandler.cmd = hmp_info_cpus,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -163,7 +163,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the command line history",
|
||||
.cmd = hmp_info_history,
|
||||
.mhandler.cmd = hmp_info_history,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -180,11 +180,11 @@ ETEXI
|
||||
.params = "",
|
||||
.help = "show the interrupts statistics (if available)",
|
||||
#ifdef TARGET_SPARC
|
||||
.cmd = sun4m_hmp_info_irq,
|
||||
.mhandler.cmd = sun4m_hmp_info_irq,
|
||||
#elif defined(TARGET_LM32)
|
||||
.cmd = lm32_hmp_info_irq,
|
||||
.mhandler.cmd = lm32_hmp_info_irq,
|
||||
#else
|
||||
.cmd = hmp_info_irq,
|
||||
.mhandler.cmd = hmp_info_irq,
|
||||
#endif
|
||||
},
|
||||
|
||||
@@ -200,11 +200,11 @@ ETEXI
|
||||
.params = "",
|
||||
.help = "show i8259 (PIC) state",
|
||||
#ifdef TARGET_SPARC
|
||||
.cmd = sun4m_hmp_info_pic,
|
||||
.mhandler.cmd = sun4m_hmp_info_pic,
|
||||
#elif defined(TARGET_LM32)
|
||||
.cmd = lm32_hmp_info_pic,
|
||||
.mhandler.cmd = lm32_hmp_info_pic,
|
||||
#else
|
||||
.cmd = hmp_info_pic,
|
||||
.mhandler.cmd = hmp_info_pic,
|
||||
#endif
|
||||
},
|
||||
#endif
|
||||
@@ -220,7 +220,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show PCI info",
|
||||
.cmd = hmp_info_pci,
|
||||
.mhandler.cmd = hmp_info_pci,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -236,7 +236,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show virtual to physical memory mappings",
|
||||
.cmd = hmp_info_tlb,
|
||||
.mhandler.cmd = hmp_info_tlb,
|
||||
},
|
||||
#endif
|
||||
|
||||
@@ -252,7 +252,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the active virtual memory mappings",
|
||||
.cmd = hmp_info_mem,
|
||||
.mhandler.cmd = hmp_info_mem,
|
||||
},
|
||||
#endif
|
||||
|
||||
@@ -267,7 +267,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show memory tree",
|
||||
.cmd = hmp_info_mtree,
|
||||
.mhandler.cmd = hmp_info_mtree,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -281,7 +281,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show dynamic compiler info",
|
||||
.cmd = hmp_info_jit,
|
||||
.mhandler.cmd = hmp_info_jit,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -295,7 +295,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show dynamic compiler opcode counters",
|
||||
.cmd = hmp_info_opcount,
|
||||
.mhandler.cmd = hmp_info_opcount,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -309,7 +309,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show KVM information",
|
||||
.cmd = hmp_info_kvm,
|
||||
.mhandler.cmd = hmp_info_kvm,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -323,7 +323,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show NUMA information",
|
||||
.cmd = hmp_info_numa,
|
||||
.mhandler.cmd = hmp_info_numa,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -337,7 +337,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show guest USB devices",
|
||||
.cmd = hmp_info_usb,
|
||||
.mhandler.cmd = hmp_info_usb,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -351,7 +351,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show host USB devices",
|
||||
.cmd = hmp_info_usbhost,
|
||||
.mhandler.cmd = hmp_info_usbhost,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -365,7 +365,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show profiling information",
|
||||
.cmd = hmp_info_profile,
|
||||
.mhandler.cmd = hmp_info_profile,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -379,7 +379,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show capture information",
|
||||
.cmd = hmp_info_capture,
|
||||
.mhandler.cmd = hmp_info_capture,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -393,7 +393,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the currently saved VM snapshots",
|
||||
.cmd = hmp_info_snapshots,
|
||||
.mhandler.cmd = hmp_info_snapshots,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -407,7 +407,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the current VM status (running|paused)",
|
||||
.cmd = hmp_info_status,
|
||||
.mhandler.cmd = hmp_info_status,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -421,7 +421,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show which guest mouse is receiving events",
|
||||
.cmd = hmp_info_mice,
|
||||
.mhandler.cmd = hmp_info_mice,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -435,7 +435,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the vnc server status",
|
||||
.cmd = hmp_info_vnc,
|
||||
.mhandler.cmd = hmp_info_vnc,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -450,7 +450,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the spice server status",
|
||||
.cmd = hmp_info_spice,
|
||||
.mhandler.cmd = hmp_info_spice,
|
||||
},
|
||||
#endif
|
||||
|
||||
@@ -465,7 +465,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the current VM name",
|
||||
.cmd = hmp_info_name,
|
||||
.mhandler.cmd = hmp_info_name,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -479,7 +479,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the current VM UUID",
|
||||
.cmd = hmp_info_uuid,
|
||||
.mhandler.cmd = hmp_info_uuid,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -493,7 +493,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show CPU statistics",
|
||||
.cmd = hmp_info_cpustats,
|
||||
.mhandler.cmd = hmp_info_cpustats,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -508,7 +508,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show user network stack connection states",
|
||||
.cmd = hmp_info_usernet,
|
||||
.mhandler.cmd = hmp_info_usernet,
|
||||
},
|
||||
#endif
|
||||
|
||||
@@ -523,7 +523,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show migration status",
|
||||
.cmd = hmp_info_migrate,
|
||||
.mhandler.cmd = hmp_info_migrate,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -537,7 +537,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show current migration capabilities",
|
||||
.cmd = hmp_info_migrate_capabilities,
|
||||
.mhandler.cmd = hmp_info_migrate_capabilities,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -551,7 +551,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show current migration parameters",
|
||||
.cmd = hmp_info_migrate_parameters,
|
||||
.mhandler.cmd = hmp_info_migrate_parameters,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -565,7 +565,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show current migration xbzrle cache size",
|
||||
.cmd = hmp_info_migrate_cache_size,
|
||||
.mhandler.cmd = hmp_info_migrate_cache_size,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -579,7 +579,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show balloon information",
|
||||
.cmd = hmp_info_balloon,
|
||||
.mhandler.cmd = hmp_info_balloon,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -593,7 +593,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show device tree",
|
||||
.cmd = hmp_info_qtree,
|
||||
.mhandler.cmd = hmp_info_qtree,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -607,7 +607,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show qdev device model list",
|
||||
.cmd = hmp_info_qdm,
|
||||
.mhandler.cmd = hmp_info_qdm,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -621,7 +621,7 @@ ETEXI
|
||||
.args_type = "path:s?",
|
||||
.params = "[path]",
|
||||
.help = "show QOM composition tree",
|
||||
.cmd = hmp_info_qom_tree,
|
||||
.mhandler.cmd = hmp_info_qom_tree,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -635,7 +635,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show roms",
|
||||
.cmd = hmp_info_roms,
|
||||
.mhandler.cmd = hmp_info_roms,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -650,7 +650,7 @@ ETEXI
|
||||
.params = "[name] [vcpu]",
|
||||
.help = "show available trace-events & their state "
|
||||
"(name: event name pattern; vcpu: vCPU to query, default is any)",
|
||||
.cmd = hmp_info_trace_events,
|
||||
.mhandler.cmd = hmp_info_trace_events,
|
||||
.command_completion = info_trace_events_completion,
|
||||
},
|
||||
|
||||
@@ -665,7 +665,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the TPM device",
|
||||
.cmd = hmp_info_tpm,
|
||||
.mhandler.cmd = hmp_info_tpm,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -679,7 +679,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show memory backends",
|
||||
.cmd = hmp_info_memdev,
|
||||
.mhandler.cmd = hmp_info_memdev,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -693,7 +693,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show memory devices",
|
||||
.cmd = hmp_info_memory_devices,
|
||||
.mhandler.cmd = hmp_info_memory_devices,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -707,7 +707,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show iothreads",
|
||||
.cmd = hmp_info_iothreads,
|
||||
.mhandler.cmd = hmp_info_iothreads,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -721,7 +721,7 @@ ETEXI
|
||||
.args_type = "name:s",
|
||||
.params = "name",
|
||||
.help = "Show rocker switch",
|
||||
.cmd = hmp_rocker,
|
||||
.mhandler.cmd = hmp_rocker,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -735,7 +735,7 @@ ETEXI
|
||||
.args_type = "name:s",
|
||||
.params = "name",
|
||||
.help = "Show rocker ports",
|
||||
.cmd = hmp_rocker_ports,
|
||||
.mhandler.cmd = hmp_rocker_ports,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -749,7 +749,7 @@ ETEXI
|
||||
.args_type = "name:s,tbl_id:i?",
|
||||
.params = "name [tbl_id]",
|
||||
.help = "Show rocker OF-DPA flow tables",
|
||||
.cmd = hmp_rocker_of_dpa_flows,
|
||||
.mhandler.cmd = hmp_rocker_of_dpa_flows,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -763,7 +763,7 @@ ETEXI
|
||||
.args_type = "name:s,type:i?",
|
||||
.params = "name [type]",
|
||||
.help = "Show rocker OF-DPA groups",
|
||||
.cmd = hmp_rocker_of_dpa_groups,
|
||||
.mhandler.cmd = hmp_rocker_of_dpa_groups,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -778,7 +778,7 @@ ETEXI
|
||||
.args_type = "addr:l",
|
||||
.params = "address",
|
||||
.help = "Display the value of a storage key",
|
||||
.cmd = hmp_info_skeys,
|
||||
.mhandler.cmd = hmp_info_skeys,
|
||||
},
|
||||
#endif
|
||||
|
||||
@@ -793,7 +793,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "Display the latest dump status",
|
||||
.cmd = hmp_info_dump,
|
||||
.mhandler.cmd = hmp_info_dump,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -807,7 +807,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "Show information about hotpluggable CPUs",
|
||||
.cmd = hmp_hotpluggable_cpus,
|
||||
.mhandler.cmd = hmp_hotpluggable_cpus,
|
||||
},
|
||||
|
||||
STEXI
|
||||
|
216
hmp-commands.hx
216
hmp-commands.hx
@@ -14,7 +14,7 @@ ETEXI
|
||||
.args_type = "name:S?",
|
||||
.params = "[cmd]",
|
||||
.help = "show the help",
|
||||
.cmd = do_help_cmd,
|
||||
.mhandler.cmd = do_help_cmd,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -28,7 +28,7 @@ ETEXI
|
||||
.args_type = "device:B",
|
||||
.params = "device|all",
|
||||
.help = "commit changes to the disk images (if -snapshot is used) or backing files",
|
||||
.cmd = hmp_commit,
|
||||
.mhandler.cmd = hmp_commit,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -47,7 +47,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "quit the emulator",
|
||||
.cmd = hmp_quit,
|
||||
.mhandler.cmd = hmp_quit,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -61,7 +61,7 @@ ETEXI
|
||||
.args_type = "device:B,size:o",
|
||||
.params = "device size",
|
||||
.help = "resize a block image",
|
||||
.cmd = hmp_block_resize,
|
||||
.mhandler.cmd = hmp_block_resize,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -78,7 +78,7 @@ ETEXI
|
||||
.args_type = "device:B,speed:o?,base:s?",
|
||||
.params = "device [speed [base]]",
|
||||
.help = "copy data from a backing file into a block device",
|
||||
.cmd = hmp_block_stream,
|
||||
.mhandler.cmd = hmp_block_stream,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -92,7 +92,7 @@ ETEXI
|
||||
.args_type = "device:B,speed:o",
|
||||
.params = "device speed",
|
||||
.help = "set maximum speed for a background block operation",
|
||||
.cmd = hmp_block_job_set_speed,
|
||||
.mhandler.cmd = hmp_block_job_set_speed,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -107,7 +107,7 @@ ETEXI
|
||||
.params = "[-f] device",
|
||||
.help = "stop an active background block operation (use -f"
|
||||
"\n\t\t\t if the operation is currently paused)",
|
||||
.cmd = hmp_block_job_cancel,
|
||||
.mhandler.cmd = hmp_block_job_cancel,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -121,7 +121,7 @@ ETEXI
|
||||
.args_type = "device:B",
|
||||
.params = "device",
|
||||
.help = "stop an active background block operation",
|
||||
.cmd = hmp_block_job_complete,
|
||||
.mhandler.cmd = hmp_block_job_complete,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -136,7 +136,7 @@ ETEXI
|
||||
.args_type = "device:B",
|
||||
.params = "device",
|
||||
.help = "pause an active background block operation",
|
||||
.cmd = hmp_block_job_pause,
|
||||
.mhandler.cmd = hmp_block_job_pause,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -150,7 +150,7 @@ ETEXI
|
||||
.args_type = "device:B",
|
||||
.params = "device",
|
||||
.help = "resume a paused background block operation",
|
||||
.cmd = hmp_block_job_resume,
|
||||
.mhandler.cmd = hmp_block_job_resume,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -164,7 +164,7 @@ ETEXI
|
||||
.args_type = "force:-f,device:B",
|
||||
.params = "[-f] device",
|
||||
.help = "eject a removable medium (use -f to force it)",
|
||||
.cmd = hmp_eject,
|
||||
.mhandler.cmd = hmp_eject,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -178,7 +178,7 @@ ETEXI
|
||||
.args_type = "id:B",
|
||||
.params = "device",
|
||||
.help = "remove host block device",
|
||||
.cmd = hmp_drive_del,
|
||||
.mhandler.cmd = hmp_drive_del,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -197,7 +197,7 @@ ETEXI
|
||||
.args_type = "device:B,target:F,arg:s?,read-only-mode:s?",
|
||||
.params = "device filename [format [read-only-mode]]",
|
||||
.help = "change a removable medium, optional format",
|
||||
.cmd = hmp_change,
|
||||
.mhandler.cmd = hmp_change,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -256,7 +256,7 @@ ETEXI
|
||||
.args_type = "filename:F",
|
||||
.params = "filename",
|
||||
.help = "save screen into PPM image 'filename'",
|
||||
.cmd = hmp_screendump,
|
||||
.mhandler.cmd = hmp_screendump,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -270,7 +270,7 @@ ETEXI
|
||||
.args_type = "filename:F",
|
||||
.params = "filename",
|
||||
.help = "output logs to 'filename'",
|
||||
.cmd = hmp_logfile,
|
||||
.mhandler.cmd = hmp_logfile,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -285,7 +285,7 @@ ETEXI
|
||||
.params = "name on|off [vcpu]",
|
||||
.help = "changes status of a specific trace event "
|
||||
"(vcpu: vCPU to set, default is all)",
|
||||
.cmd = hmp_trace_event,
|
||||
.mhandler.cmd = hmp_trace_event,
|
||||
.command_completion = trace_event_completion,
|
||||
},
|
||||
|
||||
@@ -301,7 +301,7 @@ ETEXI
|
||||
.args_type = "op:s?,arg:F?",
|
||||
.params = "on|off|flush|set [arg]",
|
||||
.help = "open, close, or flush trace file, or set a new file name",
|
||||
.cmd = hmp_trace_file,
|
||||
.mhandler.cmd = hmp_trace_file,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -316,7 +316,7 @@ ETEXI
|
||||
.args_type = "items:s",
|
||||
.params = "item1[,...]",
|
||||
.help = "activate logging of the specified items",
|
||||
.cmd = hmp_log,
|
||||
.mhandler.cmd = hmp_log,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -330,7 +330,7 @@ ETEXI
|
||||
.args_type = "name:s?",
|
||||
.params = "[tag|id]",
|
||||
.help = "save a VM snapshot. If no tag or id are provided, a new snapshot is created",
|
||||
.cmd = hmp_savevm,
|
||||
.mhandler.cmd = hmp_savevm,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -347,7 +347,7 @@ ETEXI
|
||||
.args_type = "name:s",
|
||||
.params = "tag|id",
|
||||
.help = "restore a VM snapshot from its tag or id",
|
||||
.cmd = hmp_loadvm,
|
||||
.mhandler.cmd = hmp_loadvm,
|
||||
.command_completion = loadvm_completion,
|
||||
},
|
||||
|
||||
@@ -363,7 +363,7 @@ ETEXI
|
||||
.args_type = "name:s",
|
||||
.params = "tag|id",
|
||||
.help = "delete a VM snapshot from its tag or id",
|
||||
.cmd = hmp_delvm,
|
||||
.mhandler.cmd = hmp_delvm,
|
||||
.command_completion = delvm_completion,
|
||||
},
|
||||
|
||||
@@ -378,7 +378,7 @@ ETEXI
|
||||
.args_type = "option:s?",
|
||||
.params = "[on|off]",
|
||||
.help = "run emulation in singlestep mode or switch to normal mode",
|
||||
.cmd = hmp_singlestep,
|
||||
.mhandler.cmd = hmp_singlestep,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -393,7 +393,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "stop emulation",
|
||||
.cmd = hmp_stop,
|
||||
.mhandler.cmd = hmp_stop,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -407,7 +407,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "resume emulation",
|
||||
.cmd = hmp_cont,
|
||||
.mhandler.cmd = hmp_cont,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -421,7 +421,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "wakeup guest from suspend",
|
||||
.cmd = hmp_system_wakeup,
|
||||
.mhandler.cmd = hmp_system_wakeup,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -435,7 +435,7 @@ ETEXI
|
||||
.args_type = "device:s?",
|
||||
.params = "[device]",
|
||||
.help = "start gdbserver on given device (default 'tcp::1234'), stop with 'none'",
|
||||
.cmd = hmp_gdbserver,
|
||||
.mhandler.cmd = hmp_gdbserver,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -449,7 +449,7 @@ ETEXI
|
||||
.args_type = "fmt:/,addr:l",
|
||||
.params = "/fmt addr",
|
||||
.help = "virtual memory dump starting at 'addr'",
|
||||
.cmd = hmp_memory_dump,
|
||||
.mhandler.cmd = hmp_memory_dump,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -463,7 +463,7 @@ ETEXI
|
||||
.args_type = "fmt:/,addr:l",
|
||||
.params = "/fmt addr",
|
||||
.help = "physical memory dump starting at 'addr'",
|
||||
.cmd = hmp_physical_memory_dump,
|
||||
.mhandler.cmd = hmp_physical_memory_dump,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -530,7 +530,7 @@ ETEXI
|
||||
.args_type = "fmt:/,val:l",
|
||||
.params = "/fmt expr",
|
||||
.help = "print expression value (use $reg for CPU register access)",
|
||||
.cmd = do_print,
|
||||
.mhandler.cmd = do_print,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -545,7 +545,7 @@ ETEXI
|
||||
.args_type = "fmt:/,addr:i,index:i.",
|
||||
.params = "/fmt addr",
|
||||
.help = "I/O port read",
|
||||
.cmd = hmp_ioport_read,
|
||||
.mhandler.cmd = hmp_ioport_read,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -559,7 +559,7 @@ ETEXI
|
||||
.args_type = "fmt:/,addr:i,val:i",
|
||||
.params = "/fmt addr value",
|
||||
.help = "I/O port write",
|
||||
.cmd = hmp_ioport_write,
|
||||
.mhandler.cmd = hmp_ioport_write,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -573,7 +573,7 @@ ETEXI
|
||||
.args_type = "keys:s,hold-time:i?",
|
||||
.params = "keys [hold_ms]",
|
||||
.help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)",
|
||||
.cmd = hmp_sendkey,
|
||||
.mhandler.cmd = hmp_sendkey,
|
||||
.command_completion = sendkey_completion,
|
||||
},
|
||||
|
||||
@@ -596,7 +596,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "reset the system",
|
||||
.cmd = hmp_system_reset,
|
||||
.mhandler.cmd = hmp_system_reset,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -610,7 +610,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "send system power down event",
|
||||
.cmd = hmp_system_powerdown,
|
||||
.mhandler.cmd = hmp_system_powerdown,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -624,7 +624,7 @@ ETEXI
|
||||
.args_type = "start:i,size:i",
|
||||
.params = "addr size",
|
||||
.help = "compute the checksum of a memory region",
|
||||
.cmd = hmp_sum,
|
||||
.mhandler.cmd = hmp_sum,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -638,7 +638,7 @@ ETEXI
|
||||
.args_type = "devname:s",
|
||||
.params = "device",
|
||||
.help = "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')",
|
||||
.cmd = hmp_usb_add,
|
||||
.mhandler.cmd = hmp_usb_add,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -653,7 +653,7 @@ ETEXI
|
||||
.args_type = "devname:s",
|
||||
.params = "device",
|
||||
.help = "remove USB device 'bus.addr'",
|
||||
.cmd = hmp_usb_del,
|
||||
.mhandler.cmd = hmp_usb_del,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -669,7 +669,7 @@ ETEXI
|
||||
.args_type = "device:O",
|
||||
.params = "driver[,prop=value][,...]",
|
||||
.help = "add device, like -device on the command line",
|
||||
.cmd = hmp_device_add,
|
||||
.mhandler.cmd = hmp_device_add,
|
||||
.command_completion = device_add_completion,
|
||||
},
|
||||
|
||||
@@ -684,7 +684,7 @@ ETEXI
|
||||
.args_type = "id:s",
|
||||
.params = "device",
|
||||
.help = "remove device",
|
||||
.cmd = hmp_device_del,
|
||||
.mhandler.cmd = hmp_device_del,
|
||||
.command_completion = device_del_completion,
|
||||
},
|
||||
|
||||
@@ -700,7 +700,7 @@ ETEXI
|
||||
.args_type = "index:i",
|
||||
.params = "index",
|
||||
.help = "set the default CPU",
|
||||
.cmd = hmp_cpu,
|
||||
.mhandler.cmd = hmp_cpu,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -714,7 +714,7 @@ ETEXI
|
||||
.args_type = "dx_str:s,dy_str:s,dz_str:s?",
|
||||
.params = "dx dy [dz]",
|
||||
.help = "send mouse move events",
|
||||
.cmd = hmp_mouse_move,
|
||||
.mhandler.cmd = hmp_mouse_move,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -729,7 +729,7 @@ ETEXI
|
||||
.args_type = "button_state:i",
|
||||
.params = "state",
|
||||
.help = "change mouse button state (1=L, 2=M, 4=R)",
|
||||
.cmd = hmp_mouse_button,
|
||||
.mhandler.cmd = hmp_mouse_button,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -743,7 +743,7 @@ ETEXI
|
||||
.args_type = "index:i",
|
||||
.params = "index",
|
||||
.help = "set which mouse device receives events",
|
||||
.cmd = hmp_mouse_set,
|
||||
.mhandler.cmd = hmp_mouse_set,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -761,7 +761,7 @@ ETEXI
|
||||
.args_type = "path:F,freq:i?,bits:i?,nchannels:i?",
|
||||
.params = "path [frequency [bits [channels]]]",
|
||||
.help = "capture audio to a wave file (default frequency=44100 bits=16 channels=2)",
|
||||
.cmd = hmp_wavcapture,
|
||||
.mhandler.cmd = hmp_wavcapture,
|
||||
},
|
||||
STEXI
|
||||
@item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels}]]]
|
||||
@@ -782,7 +782,7 @@ ETEXI
|
||||
.args_type = "n:i",
|
||||
.params = "capture index",
|
||||
.help = "stop capture",
|
||||
.cmd = hmp_stopcapture,
|
||||
.mhandler.cmd = hmp_stopcapture,
|
||||
},
|
||||
STEXI
|
||||
@item stopcapture @var{index}
|
||||
@@ -798,7 +798,7 @@ ETEXI
|
||||
.args_type = "val:l,size:i,filename:s",
|
||||
.params = "addr size file",
|
||||
.help = "save to disk virtual memory dump starting at 'addr' of size 'size'",
|
||||
.cmd = hmp_memsave,
|
||||
.mhandler.cmd = hmp_memsave,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -812,7 +812,7 @@ ETEXI
|
||||
.args_type = "val:l,size:i,filename:s",
|
||||
.params = "addr size file",
|
||||
.help = "save to disk physical memory dump starting at 'addr' of size 'size'",
|
||||
.cmd = hmp_pmemsave,
|
||||
.mhandler.cmd = hmp_pmemsave,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -826,7 +826,7 @@ ETEXI
|
||||
.args_type = "bootdevice:s",
|
||||
.params = "bootdevice",
|
||||
.help = "define new values for the boot device list",
|
||||
.cmd = hmp_boot_set,
|
||||
.mhandler.cmd = hmp_boot_set,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -844,7 +844,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "inject an NMI",
|
||||
.cmd = hmp_nmi,
|
||||
.mhandler.cmd = hmp_nmi,
|
||||
},
|
||||
STEXI
|
||||
@item nmi @var{cpu}
|
||||
@@ -858,7 +858,7 @@ ETEXI
|
||||
.args_type = "device:s,data:s",
|
||||
.params = "device data",
|
||||
.help = "Write to a ring buffer character device",
|
||||
.cmd = hmp_ringbuf_write,
|
||||
.mhandler.cmd = hmp_ringbuf_write,
|
||||
.command_completion = ringbuf_write_completion,
|
||||
},
|
||||
|
||||
@@ -875,7 +875,7 @@ ETEXI
|
||||
.args_type = "device:s,size:i",
|
||||
.params = "device size",
|
||||
.help = "Read from a ring buffer character device",
|
||||
.cmd = hmp_ringbuf_read,
|
||||
.mhandler.cmd = hmp_ringbuf_read,
|
||||
.command_completion = ringbuf_write_completion,
|
||||
},
|
||||
|
||||
@@ -901,7 +901,7 @@ ETEXI
|
||||
" full copy of disk\n\t\t\t -i for migration without "
|
||||
"shared storage with incremental copy of disk "
|
||||
"(base image shared between src and destination)",
|
||||
.cmd = hmp_migrate,
|
||||
.mhandler.cmd = hmp_migrate,
|
||||
},
|
||||
|
||||
|
||||
@@ -918,7 +918,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "cancel the current VM migration",
|
||||
.cmd = hmp_migrate_cancel,
|
||||
.mhandler.cmd = hmp_migrate_cancel,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -933,7 +933,7 @@ ETEXI
|
||||
.args_type = "uri:s",
|
||||
.params = "uri",
|
||||
.help = "Continue an incoming migration from an -incoming defer",
|
||||
.cmd = hmp_migrate_incoming,
|
||||
.mhandler.cmd = hmp_migrate_incoming,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -954,7 +954,7 @@ ETEXI
|
||||
"The cache size affects the number of cache misses."
|
||||
"In case of a high cache miss ratio you need to increase"
|
||||
" the cache size",
|
||||
.cmd = hmp_migrate_set_cache_size,
|
||||
.mhandler.cmd = hmp_migrate_set_cache_size,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -969,7 +969,7 @@ ETEXI
|
||||
.params = "value",
|
||||
.help = "set maximum speed (in bytes) for migrations. "
|
||||
"Defaults to MB if no size suffix is specified, ie. B/K/M/G/T",
|
||||
.cmd = hmp_migrate_set_speed,
|
||||
.mhandler.cmd = hmp_migrate_set_speed,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -983,7 +983,7 @@ ETEXI
|
||||
.args_type = "value:T",
|
||||
.params = "value",
|
||||
.help = "set maximum tolerated downtime (in seconds) for migrations",
|
||||
.cmd = hmp_migrate_set_downtime,
|
||||
.mhandler.cmd = hmp_migrate_set_downtime,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -997,7 +997,7 @@ ETEXI
|
||||
.args_type = "capability:s,state:b",
|
||||
.params = "capability state",
|
||||
.help = "Enable/Disable the usage of a capability for migration",
|
||||
.cmd = hmp_migrate_set_capability,
|
||||
.mhandler.cmd = hmp_migrate_set_capability,
|
||||
.command_completion = migrate_set_capability_completion,
|
||||
},
|
||||
|
||||
@@ -1012,7 +1012,7 @@ ETEXI
|
||||
.args_type = "parameter:s,value:s",
|
||||
.params = "parameter value",
|
||||
.help = "Set the parameter for migration",
|
||||
.cmd = hmp_migrate_set_parameter,
|
||||
.mhandler.cmd = hmp_migrate_set_parameter,
|
||||
.command_completion = migrate_set_parameter_completion,
|
||||
},
|
||||
|
||||
@@ -1029,7 +1029,7 @@ ETEXI
|
||||
.help = "Followup to a migration command to switch the migration"
|
||||
" to postcopy mode. The postcopy-ram capability must "
|
||||
"be set before the original migration command.",
|
||||
.cmd = hmp_migrate_start_postcopy,
|
||||
.mhandler.cmd = hmp_migrate_start_postcopy,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1044,7 +1044,7 @@ ETEXI
|
||||
.args_type = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
|
||||
.params = "protocol hostname port tls-port cert-subject",
|
||||
.help = "set migration information for remote display",
|
||||
.cmd = hmp_client_migrate_info,
|
||||
.mhandler.cmd = hmp_client_migrate_info,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1067,7 +1067,7 @@ ETEXI
|
||||
"-s: dump in kdump-compressed format, with snappy compression.\n\t\t\t"
|
||||
"begin: the starting physical address.\n\t\t\t"
|
||||
"length: the memory size, in bytes.",
|
||||
.cmd = hmp_dump_guest_memory,
|
||||
.mhandler.cmd = hmp_dump_guest_memory,
|
||||
},
|
||||
|
||||
|
||||
@@ -1094,7 +1094,7 @@ ETEXI
|
||||
.args_type = "filename:F",
|
||||
.params = "",
|
||||
.help = "Save guest storage keys into file 'filename'.\n",
|
||||
.cmd = hmp_dump_skeys,
|
||||
.mhandler.cmd = hmp_dump_skeys,
|
||||
},
|
||||
#endif
|
||||
|
||||
@@ -1116,7 +1116,7 @@ ETEXI
|
||||
"The default format is qcow2. The -n flag requests QEMU\n\t\t\t"
|
||||
"to reuse the image found in new-image-file, instead of\n\t\t\t"
|
||||
"recreating it from scratch.",
|
||||
.cmd = hmp_snapshot_blkdev,
|
||||
.mhandler.cmd = hmp_snapshot_blkdev,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1132,7 +1132,7 @@ ETEXI
|
||||
.help = "take an internal snapshot of device.\n\t\t\t"
|
||||
"The format of the image used by device must\n\t\t\t"
|
||||
"support it, such as qcow2.\n\t\t\t",
|
||||
.cmd = hmp_snapshot_blkdev_internal,
|
||||
.mhandler.cmd = hmp_snapshot_blkdev_internal,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1150,7 +1150,7 @@ ETEXI
|
||||
"the snapshot matching both id and name.\n\t\t\t"
|
||||
"The format of the image used by device must\n\t\t\t"
|
||||
"support it, such as qcow2.\n\t\t\t",
|
||||
.cmd = hmp_snapshot_delete_blkdev_internal,
|
||||
.mhandler.cmd = hmp_snapshot_delete_blkdev_internal,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1171,7 +1171,7 @@ ETEXI
|
||||
"in new-image-file, instead of recreating it from scratch.\n\t\t\t"
|
||||
"The -f flag requests QEMU to copy the whole disk,\n\t\t\t"
|
||||
"so that the result does not need a backing file.\n\t\t\t",
|
||||
.cmd = hmp_drive_mirror,
|
||||
.mhandler.cmd = hmp_drive_mirror,
|
||||
},
|
||||
STEXI
|
||||
@item drive_mirror
|
||||
@@ -1182,8 +1182,8 @@ ETEXI
|
||||
|
||||
{
|
||||
.name = "drive_backup",
|
||||
.args_type = "reuse:-n,full:-f,compress:-c,device:B,target:s,format:s?",
|
||||
.params = "[-n] [-f] [-c] device target [format]",
|
||||
.args_type = "reuse:-n,full:-f,device:B,target:s,format:s?",
|
||||
.params = "[-n] [-f] device target [format]",
|
||||
.help = "initiates a point-in-time\n\t\t\t"
|
||||
"copy for a device. The device's contents are\n\t\t\t"
|
||||
"copied to the new image file, excluding data that\n\t\t\t"
|
||||
@@ -1191,10 +1191,8 @@ ETEXI
|
||||
"The -n flag requests QEMU to reuse the image found\n\t\t\t"
|
||||
"in new-image-file, instead of recreating it from scratch.\n\t\t\t"
|
||||
"The -f flag requests QEMU to copy the whole disk,\n\t\t\t"
|
||||
"so that the result does not need a backing file.\n\t\t\t"
|
||||
"The -c flag requests QEMU to compress backup data\n\t\t\t"
|
||||
"(if the target format supports it).\n\t\t\t",
|
||||
.cmd = hmp_drive_backup,
|
||||
"so that the result does not need a backing file.\n\t\t\t",
|
||||
.mhandler.cmd = hmp_drive_backup,
|
||||
},
|
||||
STEXI
|
||||
@item drive_backup
|
||||
@@ -1212,7 +1210,7 @@ ETEXI
|
||||
"[,snapshot=on|off][,cache=on|off]\n"
|
||||
"[,readonly=on|off][,copy-on-read=on|off]",
|
||||
.help = "add drive to PCI storage controller",
|
||||
.cmd = hmp_drive_add,
|
||||
.mhandler.cmd = hmp_drive_add,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1236,7 +1234,7 @@ ETEXI
|
||||
"<error_status> = error string or 32bit\n\t\t\t"
|
||||
"<tlb header> = 32bit x 4\n\t\t\t"
|
||||
"<tlb header prefix> = 32bit x 4",
|
||||
.cmd = hmp_pcie_aer_inject_error,
|
||||
.mhandler.cmd = hmp_pcie_aer_inject_error,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1250,7 +1248,7 @@ ETEXI
|
||||
.args_type = "device:s,opts:s?",
|
||||
.params = "tap|user|socket|vde|netmap|bridge|vhost-user|dump [options]",
|
||||
.help = "add host VLAN client",
|
||||
.cmd = hmp_host_net_add,
|
||||
.mhandler.cmd = hmp_host_net_add,
|
||||
.command_completion = host_net_add_completion,
|
||||
},
|
||||
|
||||
@@ -1265,7 +1263,7 @@ ETEXI
|
||||
.args_type = "vlan_id:i,device:s",
|
||||
.params = "vlan_id name",
|
||||
.help = "remove host VLAN client",
|
||||
.cmd = hmp_host_net_remove,
|
||||
.mhandler.cmd = hmp_host_net_remove,
|
||||
.command_completion = host_net_remove_completion,
|
||||
},
|
||||
|
||||
@@ -1280,7 +1278,7 @@ ETEXI
|
||||
.args_type = "netdev:O",
|
||||
.params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]",
|
||||
.help = "add host network device",
|
||||
.cmd = hmp_netdev_add,
|
||||
.mhandler.cmd = hmp_netdev_add,
|
||||
.command_completion = netdev_add_completion,
|
||||
},
|
||||
|
||||
@@ -1295,7 +1293,7 @@ ETEXI
|
||||
.args_type = "id:s",
|
||||
.params = "id",
|
||||
.help = "remove host network device",
|
||||
.cmd = hmp_netdev_del,
|
||||
.mhandler.cmd = hmp_netdev_del,
|
||||
.command_completion = netdev_del_completion,
|
||||
},
|
||||
|
||||
@@ -1310,7 +1308,7 @@ ETEXI
|
||||
.args_type = "object:O",
|
||||
.params = "[qom-type=]type,id=str[,prop=value][,...]",
|
||||
.help = "create QOM object",
|
||||
.cmd = hmp_object_add,
|
||||
.mhandler.cmd = hmp_object_add,
|
||||
.command_completion = object_add_completion,
|
||||
},
|
||||
|
||||
@@ -1325,7 +1323,7 @@ ETEXI
|
||||
.args_type = "id:s",
|
||||
.params = "id",
|
||||
.help = "destroy QOM object",
|
||||
.cmd = hmp_object_del,
|
||||
.mhandler.cmd = hmp_object_del,
|
||||
.command_completion = object_del_completion,
|
||||
},
|
||||
|
||||
@@ -1341,7 +1339,7 @@ ETEXI
|
||||
.args_type = "arg1:s,arg2:s?,arg3:s?",
|
||||
.params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport",
|
||||
.help = "redirect TCP or UDP connections from host to guest (requires -net user)",
|
||||
.cmd = hmp_hostfwd_add,
|
||||
.mhandler.cmd = hmp_hostfwd_add,
|
||||
},
|
||||
#endif
|
||||
STEXI
|
||||
@@ -1356,7 +1354,7 @@ ETEXI
|
||||
.args_type = "arg1:s,arg2:s?,arg3:s?",
|
||||
.params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport",
|
||||
.help = "remove host-to-guest TCP or UDP redirection",
|
||||
.cmd = hmp_hostfwd_remove,
|
||||
.mhandler.cmd = hmp_hostfwd_remove,
|
||||
},
|
||||
|
||||
#endif
|
||||
@@ -1371,7 +1369,7 @@ ETEXI
|
||||
.args_type = "value:M",
|
||||
.params = "target",
|
||||
.help = "request VM to change its memory allocation (in MB)",
|
||||
.cmd = hmp_balloon,
|
||||
.mhandler.cmd = hmp_balloon,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1385,7 +1383,7 @@ ETEXI
|
||||
.args_type = "name:s,up:b",
|
||||
.params = "name on|off",
|
||||
.help = "change the link status of a network adapter",
|
||||
.cmd = hmp_set_link,
|
||||
.mhandler.cmd = hmp_set_link,
|
||||
.command_completion = set_link_completion,
|
||||
},
|
||||
|
||||
@@ -1400,7 +1398,7 @@ ETEXI
|
||||
.args_type = "action:s",
|
||||
.params = "[reset|shutdown|poweroff|pause|debug|none]",
|
||||
.help = "change watchdog action",
|
||||
.cmd = hmp_watchdog_action,
|
||||
.mhandler.cmd = hmp_watchdog_action,
|
||||
.command_completion = watchdog_action_completion,
|
||||
},
|
||||
|
||||
@@ -1415,7 +1413,7 @@ ETEXI
|
||||
.args_type = "aclname:s",
|
||||
.params = "aclname",
|
||||
.help = "list rules in the access control list",
|
||||
.cmd = hmp_acl_show,
|
||||
.mhandler.cmd = hmp_acl_show,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1432,7 +1430,7 @@ ETEXI
|
||||
.args_type = "aclname:s,policy:s",
|
||||
.params = "aclname allow|deny",
|
||||
.help = "set default access control list policy",
|
||||
.cmd = hmp_acl_policy,
|
||||
.mhandler.cmd = hmp_acl_policy,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1448,7 +1446,7 @@ ETEXI
|
||||
.args_type = "aclname:s,match:s,policy:s,index:i?",
|
||||
.params = "aclname match allow|deny [index]",
|
||||
.help = "add a match rule to the access control list",
|
||||
.cmd = hmp_acl_add,
|
||||
.mhandler.cmd = hmp_acl_add,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1467,7 +1465,7 @@ ETEXI
|
||||
.args_type = "aclname:s,match:s",
|
||||
.params = "aclname match",
|
||||
.help = "remove a match rule from the access control list",
|
||||
.cmd = hmp_acl_remove,
|
||||
.mhandler.cmd = hmp_acl_remove,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1481,7 +1479,7 @@ ETEXI
|
||||
.args_type = "aclname:s",
|
||||
.params = "aclname",
|
||||
.help = "reset the access control list",
|
||||
.cmd = hmp_acl_reset,
|
||||
.mhandler.cmd = hmp_acl_reset,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1496,7 +1494,7 @@ ETEXI
|
||||
.args_type = "all:-a,writable:-w,uri:s",
|
||||
.params = "nbd_server_start [-a] [-w] host:port",
|
||||
.help = "serve block devices on the given host and port",
|
||||
.cmd = hmp_nbd_server_start,
|
||||
.mhandler.cmd = hmp_nbd_server_start,
|
||||
},
|
||||
STEXI
|
||||
@item nbd_server_start @var{host}:@var{port}
|
||||
@@ -1512,7 +1510,7 @@ ETEXI
|
||||
.args_type = "writable:-w,device:B",
|
||||
.params = "nbd_server_add [-w] device",
|
||||
.help = "export a block device via NBD",
|
||||
.cmd = hmp_nbd_server_add,
|
||||
.mhandler.cmd = hmp_nbd_server_add,
|
||||
},
|
||||
STEXI
|
||||
@item nbd_server_add @var{device}
|
||||
@@ -1527,7 +1525,7 @@ ETEXI
|
||||
.args_type = "",
|
||||
.params = "nbd_server_stop",
|
||||
.help = "stop serving block devices using the NBD protocol",
|
||||
.cmd = hmp_nbd_server_stop,
|
||||
.mhandler.cmd = hmp_nbd_server_stop,
|
||||
},
|
||||
STEXI
|
||||
@item nbd_server_stop
|
||||
@@ -1543,7 +1541,7 @@ ETEXI
|
||||
.args_type = "broadcast:-b,cpu_index:i,bank:i,status:l,mcg_status:l,addr:l,misc:l",
|
||||
.params = "[-b] cpu bank status mcgstatus addr misc",
|
||||
.help = "inject a MCE on the given CPU [and broadcast to other CPUs with -b option]",
|
||||
.cmd = hmp_mce,
|
||||
.mhandler.cmd = hmp_mce,
|
||||
},
|
||||
|
||||
#endif
|
||||
@@ -1558,7 +1556,7 @@ ETEXI
|
||||
.args_type = "fdname:s",
|
||||
.params = "getfd name",
|
||||
.help = "receive a file descriptor via SCM rights and assign it a name",
|
||||
.cmd = hmp_getfd,
|
||||
.mhandler.cmd = hmp_getfd,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1574,7 +1572,7 @@ ETEXI
|
||||
.args_type = "fdname:s",
|
||||
.params = "closefd name",
|
||||
.help = "close a file descriptor previously passed via SCM rights",
|
||||
.cmd = hmp_closefd,
|
||||
.mhandler.cmd = hmp_closefd,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1590,7 +1588,7 @@ ETEXI
|
||||
.args_type = "device:B,password:s",
|
||||
.params = "block_passwd device password",
|
||||
.help = "set the password of encrypted block devices",
|
||||
.cmd = hmp_block_passwd,
|
||||
.mhandler.cmd = hmp_block_passwd,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1604,7 +1602,7 @@ ETEXI
|
||||
.args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l",
|
||||
.params = "device bps bps_rd bps_wr iops iops_rd iops_wr",
|
||||
.help = "change I/O throttle limits for a block drive",
|
||||
.cmd = hmp_block_set_io_throttle,
|
||||
.mhandler.cmd = hmp_block_set_io_throttle,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1618,7 +1616,7 @@ ETEXI
|
||||
.args_type = "protocol:s,password:s,connected:s?",
|
||||
.params = "protocol password action-if-connected",
|
||||
.help = "set spice/vnc password",
|
||||
.cmd = hmp_set_password,
|
||||
.mhandler.cmd = hmp_set_password,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1637,7 +1635,7 @@ ETEXI
|
||||
.args_type = "protocol:s,time:s",
|
||||
.params = "protocol time",
|
||||
.help = "set spice/vnc password expire-time",
|
||||
.cmd = hmp_expire_password,
|
||||
.mhandler.cmd = hmp_expire_password,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1668,7 +1666,7 @@ ETEXI
|
||||
.args_type = "args:s",
|
||||
.params = "args",
|
||||
.help = "add chardev",
|
||||
.cmd = hmp_chardev_add,
|
||||
.mhandler.cmd = hmp_chardev_add,
|
||||
.command_completion = chardev_add_completion,
|
||||
},
|
||||
|
||||
@@ -1684,7 +1682,7 @@ ETEXI
|
||||
.args_type = "id:s",
|
||||
.params = "id",
|
||||
.help = "remove chardev",
|
||||
.cmd = hmp_chardev_remove,
|
||||
.mhandler.cmd = hmp_chardev_remove,
|
||||
.command_completion = chardev_remove_completion,
|
||||
},
|
||||
|
||||
@@ -1700,7 +1698,7 @@ ETEXI
|
||||
.args_type = "device:B,command:s",
|
||||
.params = "[device] \"[command]\"",
|
||||
.help = "run a qemu-io command on a block device",
|
||||
.cmd = hmp_qemu_io,
|
||||
.mhandler.cmd = hmp_qemu_io,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1715,7 +1713,7 @@ ETEXI
|
||||
.args_type = "id:i",
|
||||
.params = "id",
|
||||
.help = "add cpu",
|
||||
.cmd = hmp_cpu_add,
|
||||
.mhandler.cmd = hmp_cpu_add,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1729,7 +1727,7 @@ ETEXI
|
||||
.args_type = "path:s?",
|
||||
.params = "path",
|
||||
.help = "list QOM properties",
|
||||
.cmd = hmp_qom_list,
|
||||
.mhandler.cmd = hmp_qom_list,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1742,7 +1740,7 @@ ETEXI
|
||||
.args_type = "path:s,property:s,value:s",
|
||||
.params = "path property value",
|
||||
.help = "set QOM property",
|
||||
.cmd = hmp_qom_set,
|
||||
.mhandler.cmd = hmp_qom_set,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1755,8 +1753,8 @@ ETEXI
|
||||
.args_type = "item:s?",
|
||||
.params = "[subcommand]",
|
||||
.help = "show various information about the system state",
|
||||
.cmd = hmp_info_help,
|
||||
.sub_table = info_cmds,
|
||||
.mhandler.cmd = hmp_info_help,
|
||||
.sub_table = info_cmds,
|
||||
},
|
||||
|
||||
STEXI
|
||||
|
61
hmp.c
61
hmp.c
@@ -1109,19 +1109,8 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
||||
const char *format = qdict_get_try_str(qdict, "format");
|
||||
bool reuse = qdict_get_try_bool(qdict, "reuse", false);
|
||||
bool full = qdict_get_try_bool(qdict, "full", false);
|
||||
bool compress = qdict_get_try_bool(qdict, "compress", false);
|
||||
enum NewImageMode mode;
|
||||
Error *err = NULL;
|
||||
DriveBackup backup = {
|
||||
.device = (char *)device,
|
||||
.target = (char *)filename,
|
||||
.has_format = !!format,
|
||||
.format = (char *)format,
|
||||
.sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
||||
.has_mode = true,
|
||||
.mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS,
|
||||
.has_compress = !!compress,
|
||||
.compress = compress,
|
||||
};
|
||||
|
||||
if (!filename) {
|
||||
error_setg(&err, QERR_MISSING_PARAMETER, "target");
|
||||
@@ -1129,7 +1118,16 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
||||
return;
|
||||
}
|
||||
|
||||
qmp_drive_backup(&backup, &err);
|
||||
if (reuse) {
|
||||
mode = NEW_IMAGE_MODE_EXISTING;
|
||||
} else {
|
||||
mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
||||
}
|
||||
|
||||
qmp_drive_backup(false, NULL, device, filename, !!format, format,
|
||||
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
||||
true, mode, false, 0, false, NULL,
|
||||
false, 0, false, 0, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
||||
@@ -1286,6 +1284,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
|
||||
break;
|
||||
case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT:
|
||||
has_cpu_throttle_increment = true;
|
||||
use_int_value = true;
|
||||
break;
|
||||
case MIGRATION_PARAMETER_TLS_CREDS:
|
||||
has_tls_creds = true;
|
||||
@@ -1376,7 +1375,7 @@ void hmp_eject(Monitor *mon, const QDict *qdict)
|
||||
const char *device = qdict_get_str(qdict, "device");
|
||||
Error *err = NULL;
|
||||
|
||||
qmp_eject(true, device, false, NULL, true, force, &err);
|
||||
qmp_eject(device, true, force, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
||||
@@ -1422,9 +1421,8 @@ void hmp_change(Monitor *mon, const QDict *qdict)
|
||||
}
|
||||
}
|
||||
|
||||
qmp_blockdev_change_medium(true, device, false, NULL, target,
|
||||
!!arg, arg, !!read_only, read_only_mode,
|
||||
&err);
|
||||
qmp_blockdev_change_medium(device, target, !!arg, arg,
|
||||
!!read_only, read_only_mode, &err);
|
||||
if (err &&
|
||||
error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
|
||||
error_free(err);
|
||||
@@ -1924,32 +1922,23 @@ void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
|
||||
void hmp_qemu_io(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
BlockBackend *local_blk = NULL;
|
||||
AioContext *aio_context;
|
||||
const char* device = qdict_get_str(qdict, "device");
|
||||
const char* command = qdict_get_str(qdict, "command");
|
||||
Error *err = NULL;
|
||||
|
||||
blk = blk_by_name(device);
|
||||
if (!blk) {
|
||||
BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
|
||||
if (bs) {
|
||||
blk = local_blk = blk_new();
|
||||
blk_insert_bs(blk, bs);
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
if (blk) {
|
||||
AioContext *aio_context = blk_get_aio_context(blk);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
qemuio_command(blk, command);
|
||||
|
||||
aio_context_release(aio_context);
|
||||
} else {
|
||||
error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND,
|
||||
"Device '%s' not found", device);
|
||||
}
|
||||
|
||||
aio_context = blk_get_aio_context(blk);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
qemuio_command(blk, command);
|
||||
|
||||
aio_context_release(aio_context);
|
||||
|
||||
fail:
|
||||
blk_unref(local_blk);
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
||||
|
@@ -1060,10 +1060,13 @@ static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
|
||||
const char *name, V9fsPath *target)
|
||||
{
|
||||
if (dir_path) {
|
||||
v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
|
||||
v9fs_string_sprintf((V9fsString *)target, "%s/%s",
|
||||
dir_path->data, name);
|
||||
} else {
|
||||
v9fs_path_sprintf(target, "%s", name);
|
||||
v9fs_string_sprintf((V9fsString *)target, "%s", name);
|
||||
}
|
||||
/* Bump the size for including terminating NULL */
|
||||
target->size++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -294,7 +294,8 @@ static int v9fs_receive_status(V9fsProxy *proxy,
|
||||
* This request read by proxy helper process
|
||||
* returns 0 on success and -errno on error
|
||||
*/
|
||||
static int v9fs_request(V9fsProxy *proxy, int type, void *response, ...)
|
||||
static int v9fs_request(V9fsProxy *proxy, int type,
|
||||
void *response, const char *fmt, ...)
|
||||
{
|
||||
dev_t rdev;
|
||||
va_list ap;
|
||||
@@ -316,7 +317,7 @@ static int v9fs_request(V9fsProxy *proxy, int type, void *response, ...)
|
||||
}
|
||||
iovec = &proxy->out_iovec;
|
||||
reply = &proxy->in_iovec;
|
||||
va_start(ap, response);
|
||||
va_start(ap, fmt);
|
||||
switch (type) {
|
||||
case T_OPEN:
|
||||
path = va_arg(ap, V9fsString *);
|
||||
@@ -604,7 +605,7 @@ close_error:
|
||||
static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
|
||||
{
|
||||
int retval;
|
||||
retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, fs_path);
|
||||
retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, "s", fs_path);
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
return -1;
|
||||
@@ -616,7 +617,8 @@ static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
|
||||
char *buf, size_t bufsz)
|
||||
{
|
||||
int retval;
|
||||
retval = v9fs_request(fs_ctx->private, T_READLINK, buf, fs_path, bufsz);
|
||||
retval = v9fs_request(fs_ctx->private, T_READLINK, buf, "sd",
|
||||
fs_path, bufsz);
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
return -1;
|
||||
@@ -637,7 +639,7 @@ static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs)
|
||||
static int proxy_open(FsContext *ctx, V9fsPath *fs_path,
|
||||
int flags, V9fsFidOpenState *fs)
|
||||
{
|
||||
fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, flags);
|
||||
fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, flags);
|
||||
if (fs->fd < 0) {
|
||||
errno = -fs->fd;
|
||||
fs->fd = -1;
|
||||
@@ -651,7 +653,7 @@ static int proxy_opendir(FsContext *ctx,
|
||||
int serrno, fd;
|
||||
|
||||
fs->dir.stream = NULL;
|
||||
fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, O_DIRECTORY);
|
||||
fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, O_DIRECTORY);
|
||||
if (fd < 0) {
|
||||
errno = -fd;
|
||||
return -1;
|
||||
@@ -733,8 +735,8 @@ static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
|
||||
static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
|
||||
{
|
||||
int retval;
|
||||
retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, fs_path,
|
||||
credp->fc_mode);
|
||||
retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, "sd",
|
||||
fs_path, credp->fc_mode);
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
}
|
||||
@@ -750,8 +752,8 @@ static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
|
||||
v9fs_string_init(&fullname);
|
||||
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
||||
|
||||
retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, &fullname,
|
||||
credp->fc_mode, credp->fc_rdev,
|
||||
retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, "sdqdd",
|
||||
&fullname, credp->fc_mode, credp->fc_rdev,
|
||||
credp->fc_uid, credp->fc_gid);
|
||||
v9fs_string_free(&fullname);
|
||||
if (retval < 0) {
|
||||
@@ -770,13 +772,14 @@ static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
|
||||
v9fs_string_init(&fullname);
|
||||
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
||||
|
||||
retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, &fullname,
|
||||
retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, "sddd", &fullname,
|
||||
credp->fc_mode, credp->fc_uid, credp->fc_gid);
|
||||
v9fs_string_free(&fullname);
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
retval = -1;
|
||||
}
|
||||
v9fs_string_free(&fullname);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -801,8 +804,9 @@ static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
|
||||
v9fs_string_init(&fullname);
|
||||
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
||||
|
||||
fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, &fullname, flags,
|
||||
credp->fc_mode, credp->fc_uid, credp->fc_gid);
|
||||
fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, "sdddd",
|
||||
&fullname, flags, credp->fc_mode,
|
||||
credp->fc_uid, credp->fc_gid);
|
||||
v9fs_string_free(&fullname);
|
||||
if (fs->fd < 0) {
|
||||
errno = -fs->fd;
|
||||
@@ -823,8 +827,8 @@ static int proxy_symlink(FsContext *fs_ctx, const char *oldpath,
|
||||
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
||||
v9fs_string_sprintf(&target, "%s", oldpath);
|
||||
|
||||
retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, &target, &fullname,
|
||||
credp->fc_uid, credp->fc_gid);
|
||||
retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, "ssdd",
|
||||
&target, &fullname, credp->fc_uid, credp->fc_gid);
|
||||
v9fs_string_free(&fullname);
|
||||
v9fs_string_free(&target);
|
||||
if (retval < 0) {
|
||||
@@ -843,7 +847,7 @@ static int proxy_link(FsContext *ctx, V9fsPath *oldpath,
|
||||
v9fs_string_init(&newpath);
|
||||
v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
|
||||
|
||||
retval = v9fs_request(ctx->private, T_LINK, NULL, oldpath, &newpath);
|
||||
retval = v9fs_request(ctx->private, T_LINK, NULL, "ss", oldpath, &newpath);
|
||||
v9fs_string_free(&newpath);
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
@@ -856,7 +860,7 @@ static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, fs_path, size);
|
||||
retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, "sq", fs_path, size);
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
return -1;
|
||||
@@ -875,7 +879,8 @@ static int proxy_rename(FsContext *ctx, const char *oldpath,
|
||||
|
||||
v9fs_string_sprintf(&oldname, "%s", oldpath);
|
||||
v9fs_string_sprintf(&newname, "%s", newpath);
|
||||
retval = v9fs_request(ctx->private, T_RENAME, NULL, &oldname, &newname);
|
||||
retval = v9fs_request(ctx->private, T_RENAME, NULL, "ss",
|
||||
&oldname, &newname);
|
||||
v9fs_string_free(&oldname);
|
||||
v9fs_string_free(&newname);
|
||||
if (retval < 0) {
|
||||
@@ -887,8 +892,8 @@ static int proxy_rename(FsContext *ctx, const char *oldpath,
|
||||
static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
|
||||
{
|
||||
int retval;
|
||||
retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, fs_path,
|
||||
credp->fc_uid, credp->fc_gid);
|
||||
retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, "sdd",
|
||||
fs_path, credp->fc_uid, credp->fc_gid);
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
}
|
||||
@@ -899,7 +904,8 @@ static int proxy_utimensat(FsContext *s, V9fsPath *fs_path,
|
||||
const struct timespec *buf)
|
||||
{
|
||||
int retval;
|
||||
retval = v9fs_request(s->private, T_UTIME, NULL, fs_path,
|
||||
retval = v9fs_request(s->private, T_UTIME, NULL, "sqqqq",
|
||||
fs_path,
|
||||
buf[0].tv_sec, buf[0].tv_nsec,
|
||||
buf[1].tv_sec, buf[1].tv_nsec);
|
||||
if (retval < 0) {
|
||||
@@ -914,7 +920,7 @@ static int proxy_remove(FsContext *ctx, const char *path)
|
||||
V9fsString name;
|
||||
v9fs_string_init(&name);
|
||||
v9fs_string_sprintf(&name, "%s", path);
|
||||
retval = v9fs_request(ctx->private, T_REMOVE, NULL, &name);
|
||||
retval = v9fs_request(ctx->private, T_REMOVE, NULL, "s", &name);
|
||||
v9fs_string_free(&name);
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
@@ -943,7 +949,7 @@ static int proxy_fsync(FsContext *ctx, int fid_type,
|
||||
static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
|
||||
{
|
||||
int retval;
|
||||
retval = v9fs_request(s->private, T_STATFS, stbuf, fs_path);
|
||||
retval = v9fs_request(s->private, T_STATFS, stbuf, "s", fs_path);
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
return -1;
|
||||
@@ -959,8 +965,8 @@ static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
|
||||
|
||||
v9fs_string_init(&xname);
|
||||
v9fs_string_sprintf(&xname, "%s", name);
|
||||
retval = v9fs_request(ctx->private, T_LGETXATTR, value, size, fs_path,
|
||||
&xname);
|
||||
retval = v9fs_request(ctx->private, T_LGETXATTR, value, "dss", size,
|
||||
fs_path, &xname);
|
||||
v9fs_string_free(&xname);
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
@@ -972,7 +978,8 @@ static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path,
|
||||
void *value, size_t size)
|
||||
{
|
||||
int retval;
|
||||
retval = v9fs_request(ctx->private, T_LLISTXATTR, value, size, fs_path);
|
||||
retval = v9fs_request(ctx->private, T_LLISTXATTR, value, "ds", size,
|
||||
fs_path);
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
}
|
||||
@@ -993,8 +1000,8 @@ static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
|
||||
xvalue.data = g_malloc(size);
|
||||
memcpy(xvalue.data, value, size);
|
||||
|
||||
retval = v9fs_request(ctx->private, T_LSETXATTR, value, fs_path, &xname,
|
||||
&xvalue, size, flags);
|
||||
retval = v9fs_request(ctx->private, T_LSETXATTR, value, "sssdd",
|
||||
fs_path, &xname, &xvalue, size, flags);
|
||||
v9fs_string_free(&xname);
|
||||
v9fs_string_free(&xvalue);
|
||||
if (retval < 0) {
|
||||
@@ -1011,7 +1018,8 @@ static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
|
||||
|
||||
v9fs_string_init(&xname);
|
||||
v9fs_string_sprintf(&xname, "%s", name);
|
||||
retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, fs_path, &xname);
|
||||
retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, "ss",
|
||||
fs_path, &xname);
|
||||
v9fs_string_free(&xname);
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
@@ -1023,10 +1031,13 @@ static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path,
|
||||
const char *name, V9fsPath *target)
|
||||
{
|
||||
if (dir_path) {
|
||||
v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
|
||||
v9fs_string_sprintf((V9fsString *)target, "%s/%s",
|
||||
dir_path->data, name);
|
||||
} else {
|
||||
v9fs_path_sprintf(target, "%s", name);
|
||||
v9fs_string_sprintf((V9fsString *)target, "%s", name);
|
||||
}
|
||||
/* Bump the size for including terminating NULL */
|
||||
target->size++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1075,7 +1086,7 @@ static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path,
|
||||
errno = ENOTTY;
|
||||
return -1;
|
||||
}
|
||||
err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, path);
|
||||
err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, "s", path);
|
||||
if (err < 0) {
|
||||
errno = -err;
|
||||
err = -1;
|
||||
|
27
hw/9pfs/9p.c
27
hw/9pfs/9p.c
@@ -12,7 +12,6 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <glib/gprintf.h>
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
@@ -180,20 +179,6 @@ void v9fs_path_free(V9fsPath *path)
|
||||
path->size = 0;
|
||||
}
|
||||
|
||||
|
||||
void GCC_FMT_ATTR(2, 3)
|
||||
v9fs_path_sprintf(V9fsPath *path, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
v9fs_path_free(path);
|
||||
|
||||
va_start(ap, fmt);
|
||||
/* Bump the size for including terminating NULL */
|
||||
path->size = g_vasprintf(&path->data, fmt, ap) + 1;
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs)
|
||||
{
|
||||
v9fs_path_free(lhs);
|
||||
@@ -825,15 +810,15 @@ static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
|
||||
v9stat->mtime = stbuf->st_mtime;
|
||||
v9stat->length = stbuf->st_size;
|
||||
|
||||
v9fs_string_free(&v9stat->uid);
|
||||
v9fs_string_free(&v9stat->gid);
|
||||
v9fs_string_free(&v9stat->muid);
|
||||
v9fs_string_null(&v9stat->uid);
|
||||
v9fs_string_null(&v9stat->gid);
|
||||
v9fs_string_null(&v9stat->muid);
|
||||
|
||||
v9stat->n_uid = stbuf->st_uid;
|
||||
v9stat->n_gid = stbuf->st_gid;
|
||||
v9stat->n_muid = 0;
|
||||
|
||||
v9fs_string_free(&v9stat->extension);
|
||||
v9fs_string_null(&v9stat->extension);
|
||||
|
||||
if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
|
||||
err = v9fs_co_readlink(pdu, name, &v9stat->extension);
|
||||
@@ -932,8 +917,10 @@ static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
|
||||
V9fsPath str;
|
||||
v9fs_path_init(&str);
|
||||
v9fs_path_copy(&str, dst);
|
||||
v9fs_path_sprintf(dst, "%s%s", src->data, str.data + len);
|
||||
v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len);
|
||||
v9fs_path_free(&str);
|
||||
/* +1 to include terminating NULL */
|
||||
dst->size++;
|
||||
}
|
||||
|
||||
static inline bool is_ro_export(FsContext *ctx)
|
||||
|
@@ -327,7 +327,6 @@ static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu)
|
||||
extern void v9fs_reclaim_fd(V9fsPDU *pdu);
|
||||
extern void v9fs_path_init(V9fsPath *path);
|
||||
extern void v9fs_path_free(V9fsPath *path);
|
||||
extern void v9fs_path_sprintf(V9fsPath *path, const char *fmt, ...);
|
||||
extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs);
|
||||
extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
|
||||
const char *name, V9fsPath *path);
|
||||
|
@@ -226,7 +226,7 @@ static void build_extop_package(GArray *package, uint8_t op)
|
||||
build_prepend_byte(package, 0x5B); /* ExtOpPrefix */
|
||||
}
|
||||
|
||||
void build_append_int_noprefix(GArray *table, uint64_t value, int size)
|
||||
static void build_append_int_noprefix(GArray *table, uint64_t value, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@@ -99,6 +99,7 @@ void build_acpi_ipmi_devices(Aml *scope, BusState *bus)
|
||||
|
||||
ii = IPMI_INTERFACE(obj);
|
||||
iic = IPMI_INTERFACE_GET_CLASS(obj);
|
||||
memset(&info, 0, sizeof(info));
|
||||
iic->get_fwinfo(ii, &info);
|
||||
aml_append(scope, aml_ipmi_device(&info));
|
||||
}
|
||||
|
@@ -17,4 +17,4 @@ obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
|
||||
obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
|
||||
obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
|
||||
obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += ast2400.o palmetto-bmc.o
|
||||
|
197
hw/arm/aspeed.c
197
hw/arm/aspeed.c
@@ -1,197 +0,0 @@
|
||||
/*
|
||||
* OpenPOWER Palmetto BMC
|
||||
*
|
||||
* Andrew Jeffery <andrew@aj.id.au>
|
||||
*
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/arm/aspeed_soc.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
|
||||
static struct arm_boot_info aspeed_board_binfo = {
|
||||
.board_id = -1, /* device-tree-only board */
|
||||
.nb_cpus = 1,
|
||||
};
|
||||
|
||||
typedef struct AspeedBoardState {
|
||||
AspeedSoCState soc;
|
||||
MemoryRegion ram;
|
||||
} AspeedBoardState;
|
||||
|
||||
typedef struct AspeedBoardConfig {
|
||||
const char *soc_name;
|
||||
uint32_t hw_strap1;
|
||||
} AspeedBoardConfig;
|
||||
|
||||
enum {
|
||||
PALMETTO_BMC,
|
||||
AST2500_EVB,
|
||||
};
|
||||
|
||||
#define PALMETTO_BMC_HW_STRAP1 ( \
|
||||
SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_256MB) | \
|
||||
SCU_AST2400_HW_STRAP_DRAM_CONFIG(2 /* DDR3 with CL=6, CWL=5 */) | \
|
||||
SCU_AST2400_HW_STRAP_ACPI_DIS | \
|
||||
SCU_AST2400_HW_STRAP_SET_CLK_SOURCE(AST2400_CLK_48M_IN) | \
|
||||
SCU_HW_STRAP_VGA_CLASS_CODE | \
|
||||
SCU_HW_STRAP_LPC_RESET_PIN | \
|
||||
SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_M_S_EN) | \
|
||||
SCU_AST2400_HW_STRAP_SET_CPU_AHB_RATIO(AST2400_CPU_AHB_RATIO_2_1) | \
|
||||
SCU_HW_STRAP_SPI_WIDTH | \
|
||||
SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \
|
||||
SCU_AST2400_HW_STRAP_BOOT_MODE(AST2400_SPI_BOOT))
|
||||
|
||||
#define AST2500_EVB_HW_STRAP1 (( \
|
||||
AST2500_HW_STRAP1_DEFAULTS | \
|
||||
SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \
|
||||
SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \
|
||||
SCU_AST2500_HW_STRAP_UART_DEBUG | \
|
||||
SCU_AST2500_HW_STRAP_DDR4_ENABLE | \
|
||||
SCU_HW_STRAP_MAC1_RGMII | \
|
||||
SCU_HW_STRAP_MAC0_RGMII) & \
|
||||
~SCU_HW_STRAP_2ND_BOOT_WDT)
|
||||
|
||||
static const AspeedBoardConfig aspeed_boards[] = {
|
||||
[PALMETTO_BMC] = { "ast2400-a0", PALMETTO_BMC_HW_STRAP1 },
|
||||
[AST2500_EVB] = { "ast2500-a1", AST2500_EVB_HW_STRAP1 },
|
||||
};
|
||||
|
||||
static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
|
||||
Error **errp)
|
||||
{
|
||||
int i ;
|
||||
|
||||
for (i = 0; i < s->num_cs; ++i) {
|
||||
AspeedSMCFlash *fl = &s->flashes[i];
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
qemu_irq cs_line;
|
||||
|
||||
/*
|
||||
* FIXME: check that we are not using a flash module exceeding
|
||||
* the controller segment size
|
||||
*/
|
||||
fl->flash = ssi_create_slave_no_init(s->spi, flashtype);
|
||||
if (dinfo) {
|
||||
qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo),
|
||||
errp);
|
||||
}
|
||||
qdev_init_nofail(fl->flash);
|
||||
|
||||
cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line);
|
||||
}
|
||||
}
|
||||
|
||||
static void aspeed_board_init(MachineState *machine,
|
||||
const AspeedBoardConfig *cfg)
|
||||
{
|
||||
AspeedBoardState *bmc;
|
||||
AspeedSoCClass *sc;
|
||||
|
||||
bmc = g_new0(AspeedBoardState, 1);
|
||||
object_initialize(&bmc->soc, (sizeof(bmc->soc)), cfg->soc_name);
|
||||
object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc),
|
||||
&error_abort);
|
||||
|
||||
sc = ASPEED_SOC_GET_CLASS(&bmc->soc);
|
||||
|
||||
object_property_set_int(OBJECT(&bmc->soc), ram_size, "ram-size",
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&bmc->soc), true, "realized",
|
||||
&error_abort);
|
||||
|
||||
/*
|
||||
* Allocate RAM after the memory controller has checked the size
|
||||
* was valid. If not, a default value is used.
|
||||
*/
|
||||
ram_size = object_property_get_int(OBJECT(&bmc->soc), "ram-size",
|
||||
&error_abort);
|
||||
|
||||
memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size);
|
||||
memory_region_add_subregion(get_system_memory(), sc->info->sdram_base,
|
||||
&bmc->ram);
|
||||
object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram),
|
||||
&error_abort);
|
||||
|
||||
aspeed_board_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort);
|
||||
aspeed_board_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort);
|
||||
|
||||
aspeed_board_binfo.kernel_filename = machine->kernel_filename;
|
||||
aspeed_board_binfo.initrd_filename = machine->initrd_filename;
|
||||
aspeed_board_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
aspeed_board_binfo.ram_size = ram_size;
|
||||
aspeed_board_binfo.loader_start = sc->info->sdram_base;
|
||||
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &aspeed_board_binfo);
|
||||
}
|
||||
|
||||
static void palmetto_bmc_init(MachineState *machine)
|
||||
{
|
||||
aspeed_board_init(machine, &aspeed_boards[PALMETTO_BMC]);
|
||||
}
|
||||
|
||||
static void palmetto_bmc_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "OpenPOWER Palmetto BMC (ARM926EJ-S)";
|
||||
mc->init = palmetto_bmc_init;
|
||||
mc->max_cpus = 1;
|
||||
mc->no_sdcard = 1;
|
||||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->no_parallel = 1;
|
||||
}
|
||||
|
||||
static const TypeInfo palmetto_bmc_type = {
|
||||
.name = MACHINE_TYPE_NAME("palmetto-bmc"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = palmetto_bmc_class_init,
|
||||
};
|
||||
|
||||
static void ast2500_evb_init(MachineState *machine)
|
||||
{
|
||||
aspeed_board_init(machine, &aspeed_boards[AST2500_EVB]);
|
||||
}
|
||||
|
||||
static void ast2500_evb_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Aspeed AST2500 EVB (ARM1176)";
|
||||
mc->init = ast2500_evb_init;
|
||||
mc->max_cpus = 1;
|
||||
mc->no_sdcard = 1;
|
||||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->no_parallel = 1;
|
||||
}
|
||||
|
||||
static const TypeInfo ast2500_evb_type = {
|
||||
.name = MACHINE_TYPE_NAME("ast2500-evb"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = ast2500_evb_class_init,
|
||||
};
|
||||
|
||||
static void aspeed_machine_init(void)
|
||||
{
|
||||
type_register_static(&palmetto_bmc_type);
|
||||
type_register_static(&ast2500_evb_type);
|
||||
}
|
||||
|
||||
type_init(aspeed_machine_init)
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* ASPEED SoC family
|
||||
* AST2400 SoC
|
||||
*
|
||||
* Andrew Jeffery <andrew@aj.id.au>
|
||||
* Jeremy Kerr <jk@ozlabs.org>
|
||||
@@ -15,68 +15,58 @@
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/arm/aspeed_soc.h"
|
||||
#include "hw/arm/ast2400.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/i2c/aspeed_i2c.h"
|
||||
|
||||
#define ASPEED_SOC_UART_5_BASE 0x00184000
|
||||
#define ASPEED_SOC_IOMEM_SIZE 0x00200000
|
||||
#define ASPEED_SOC_IOMEM_BASE 0x1E600000
|
||||
#define ASPEED_SOC_FMC_BASE 0x1E620000
|
||||
#define ASPEED_SOC_SPI_BASE 0x1E630000
|
||||
#define ASPEED_SOC_VIC_BASE 0x1E6C0000
|
||||
#define ASPEED_SOC_SDMC_BASE 0x1E6E0000
|
||||
#define ASPEED_SOC_SCU_BASE 0x1E6E2000
|
||||
#define ASPEED_SOC_TIMER_BASE 0x1E782000
|
||||
#define ASPEED_SOC_I2C_BASE 0x1E78A000
|
||||
#define AST2400_UART_5_BASE 0x00184000
|
||||
#define AST2400_IOMEM_SIZE 0x00200000
|
||||
#define AST2400_IOMEM_BASE 0x1E600000
|
||||
#define AST2400_SMC_BASE AST2400_IOMEM_BASE /* Legacy SMC */
|
||||
#define AST2400_FMC_BASE 0X1E620000
|
||||
#define AST2400_SPI_BASE 0X1E630000
|
||||
#define AST2400_VIC_BASE 0x1E6C0000
|
||||
#define AST2400_SCU_BASE 0x1E6E2000
|
||||
#define AST2400_TIMER_BASE 0x1E782000
|
||||
#define AST2400_I2C_BASE 0x1E78A000
|
||||
|
||||
#define ASPEED_SOC_FMC_FLASH_BASE 0x20000000
|
||||
#define ASPEED_SOC_SPI_FLASH_BASE 0x30000000
|
||||
#define AST2400_FMC_FLASH_BASE 0x20000000
|
||||
#define AST2400_SPI_FLASH_BASE 0x30000000
|
||||
|
||||
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
|
||||
static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, };
|
||||
|
||||
#define AST2400_SDRAM_BASE 0x40000000
|
||||
#define AST2500_SDRAM_BASE 0x80000000
|
||||
|
||||
static const AspeedSoCInfo aspeed_socs[] = {
|
||||
{ "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE },
|
||||
{ "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE },
|
||||
{ "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE },
|
||||
};
|
||||
|
||||
/*
|
||||
* IO handlers: simply catch any reads/writes to IO addresses that aren't
|
||||
* handled by a device mapping.
|
||||
*/
|
||||
|
||||
static uint64_t aspeed_soc_io_read(void *p, hwaddr offset, unsigned size)
|
||||
static uint64_t ast2400_io_read(void *p, hwaddr offset, unsigned size)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n",
|
||||
__func__, offset, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aspeed_soc_io_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
static void ast2400_io_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n",
|
||||
__func__, offset, value, size);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps aspeed_soc_io_ops = {
|
||||
.read = aspeed_soc_io_read,
|
||||
.write = aspeed_soc_io_write,
|
||||
static const MemoryRegionOps ast2400_io_ops = {
|
||||
.read = ast2400_io_read,
|
||||
.write = ast2400_io_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void aspeed_soc_init(Object *obj)
|
||||
static void ast2400_init(Object *obj)
|
||||
{
|
||||
AspeedSoCState *s = ASPEED_SOC(obj);
|
||||
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
|
||||
AST2400State *s = AST2400(obj);
|
||||
|
||||
s->cpu = cpu_arm_init(sc->info->cpu_model);
|
||||
s->cpu = cpu_arm_init("arm926");
|
||||
|
||||
object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC);
|
||||
object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL);
|
||||
@@ -94,7 +84,7 @@ static void aspeed_soc_init(Object *obj)
|
||||
object_property_add_child(obj, "scu", OBJECT(&s->scu), NULL);
|
||||
qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default());
|
||||
qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev",
|
||||
sc->info->silicon_rev);
|
||||
AST2400_A0_SILICON_REV);
|
||||
object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu),
|
||||
"hw-strap1", &error_abort);
|
||||
object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
|
||||
@@ -107,27 +97,19 @@ static void aspeed_soc_init(Object *obj)
|
||||
object_initialize(&s->spi, sizeof(s->spi), "aspeed.smc.spi");
|
||||
object_property_add_child(obj, "spi", OBJECT(&s->spi), NULL);
|
||||
qdev_set_parent_bus(DEVICE(&s->spi), sysbus_get_default());
|
||||
|
||||
object_initialize(&s->sdmc, sizeof(s->sdmc), TYPE_ASPEED_SDMC);
|
||||
object_property_add_child(obj, "sdmc", OBJECT(&s->sdmc), NULL);
|
||||
qdev_set_parent_bus(DEVICE(&s->sdmc), sysbus_get_default());
|
||||
qdev_prop_set_uint32(DEVICE(&s->sdmc), "silicon-rev",
|
||||
sc->info->silicon_rev);
|
||||
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
|
||||
"ram-size", &error_abort);
|
||||
}
|
||||
|
||||
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
static void ast2400_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
int i;
|
||||
AspeedSoCState *s = ASPEED_SOC(dev);
|
||||
AST2400State *s = AST2400(dev);
|
||||
Error *err = NULL, *local_err = NULL;
|
||||
|
||||
/* IO space */
|
||||
memory_region_init_io(&s->iomem, NULL, &aspeed_soc_io_ops, NULL,
|
||||
"aspeed_soc.io", ASPEED_SOC_IOMEM_SIZE);
|
||||
memory_region_add_subregion_overlap(get_system_memory(),
|
||||
ASPEED_SOC_IOMEM_BASE, &s->iomem, -1);
|
||||
memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL,
|
||||
"ast2400.io", AST2400_IOMEM_SIZE);
|
||||
memory_region_add_subregion_overlap(get_system_memory(), AST2400_IOMEM_BASE,
|
||||
&s->iomem, -1);
|
||||
|
||||
/* VIC */
|
||||
object_property_set_bool(OBJECT(&s->vic), true, "realized", &err);
|
||||
@@ -135,7 +117,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, ASPEED_SOC_VIC_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, AST2400_VIC_BASE);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0,
|
||||
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1,
|
||||
@@ -147,7 +129,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, ASPEED_SOC_TIMER_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, AST2400_TIMER_BASE);
|
||||
for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) {
|
||||
qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
|
||||
@@ -159,12 +141,12 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, ASPEED_SOC_SCU_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, AST2400_SCU_BASE);
|
||||
|
||||
/* UART - attach an 8250 to the IO space as our UART5 */
|
||||
if (serial_hds[0]) {
|
||||
qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]);
|
||||
serial_mm_init(&s->iomem, ASPEED_SOC_UART_5_BASE, 2,
|
||||
serial_mm_init(&s->iomem, AST2400_UART_5_BASE, 2,
|
||||
uart5, 38400, serial_hds[0], DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
@@ -174,7 +156,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, ASPEED_SOC_I2C_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, AST2400_I2C_BASE);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->vic), 12));
|
||||
|
||||
@@ -186,8 +168,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, ASPEED_SOC_FMC_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, ASPEED_SOC_FMC_FLASH_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, AST2400_FMC_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, AST2400_FMC_FLASH_BASE);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->smc), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->vic), 19));
|
||||
|
||||
@@ -199,25 +181,15 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, ASPEED_SOC_SPI_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, ASPEED_SOC_SPI_FLASH_BASE);
|
||||
|
||||
/* SDMC - SDRAM Memory Controller */
|
||||
object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, AST2400_SPI_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, AST2400_SPI_FLASH_BASE);
|
||||
}
|
||||
|
||||
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
|
||||
static void ast2400_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
|
||||
|
||||
sc->info = (AspeedSoCInfo *) data;
|
||||
dc->realize = aspeed_soc_realize;
|
||||
dc->realize = ast2400_realize;
|
||||
|
||||
/*
|
||||
* Reason: creates an ARM CPU, thus use after free(), see
|
||||
@@ -226,29 +198,17 @@ static void aspeed_soc_class_init(ObjectClass *oc, void *data)
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo aspeed_soc_type_info = {
|
||||
.name = TYPE_ASPEED_SOC,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_init = aspeed_soc_init,
|
||||
.instance_size = sizeof(AspeedSoCState),
|
||||
.class_size = sizeof(AspeedSoCClass),
|
||||
.abstract = true,
|
||||
static const TypeInfo ast2400_type_info = {
|
||||
.name = TYPE_AST2400,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(AST2400State),
|
||||
.instance_init = ast2400_init,
|
||||
.class_init = ast2400_class_init,
|
||||
};
|
||||
|
||||
static void aspeed_soc_register_types(void)
|
||||
static void ast2400_register_types(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
type_register_static(&aspeed_soc_type_info);
|
||||
for (i = 0; i < ARRAY_SIZE(aspeed_socs); ++i) {
|
||||
TypeInfo ti = {
|
||||
.name = aspeed_socs[i].name,
|
||||
.parent = TYPE_ASPEED_SOC,
|
||||
.class_init = aspeed_soc_class_init,
|
||||
.class_data = (void *) &aspeed_socs[i],
|
||||
};
|
||||
type_register(&ti);
|
||||
}
|
||||
type_register_static(&ast2400_type_info);
|
||||
}
|
||||
|
||||
type_init(aspeed_soc_register_types)
|
||||
type_init(ast2400_register_types)
|
@@ -837,7 +837,7 @@ static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s,
|
||||
s->freq = freq;
|
||||
|
||||
bh = qemu_bh_new(mv88w8618_timer_tick, s);
|
||||
s->ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
|
||||
s->ptimer = ptimer_init(bh);
|
||||
}
|
||||
|
||||
static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset,
|
||||
|
@@ -769,16 +769,14 @@ static void omap_sti_fifo_write(void *opaque, hwaddr addr,
|
||||
|
||||
if (ch == STI_TRACE_CONTROL_CHANNEL) {
|
||||
/* Flush channel <i>value</i>. */
|
||||
/* XXX this blocks entire thread. Rewrite to use
|
||||
* qemu_chr_fe_write and background I/O callbacks */
|
||||
qemu_chr_fe_write_all(s->chr, (const uint8_t *) "\r", 1);
|
||||
qemu_chr_fe_write(s->chr, (const uint8_t *) "\r", 1);
|
||||
} else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) {
|
||||
if (value == 0xc0 || value == 0xc3) {
|
||||
/* Open channel <i>ch</i>. */
|
||||
} else if (value == 0x00)
|
||||
qemu_chr_fe_write_all(s->chr, (const uint8_t *) "\n", 1);
|
||||
qemu_chr_fe_write(s->chr, (const uint8_t *) "\n", 1);
|
||||
else
|
||||
qemu_chr_fe_write_all(s->chr, &byte, 1);
|
||||
qemu_chr_fe_write(s->chr, &byte, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
102
hw/arm/palmetto-bmc.c
Normal file
102
hw/arm/palmetto-bmc.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* OpenPOWER Palmetto BMC
|
||||
*
|
||||
* Andrew Jeffery <andrew@aj.id.au>
|
||||
*
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/arm/ast2400.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
|
||||
static struct arm_boot_info palmetto_bmc_binfo = {
|
||||
.loader_start = AST2400_SDRAM_BASE,
|
||||
.board_id = 0,
|
||||
.nb_cpus = 1,
|
||||
};
|
||||
|
||||
typedef struct PalmettoBMCState {
|
||||
AST2400State soc;
|
||||
MemoryRegion ram;
|
||||
} PalmettoBMCState;
|
||||
|
||||
static void palmetto_bmc_init_flashes(AspeedSMCState *s, const char *flashtype,
|
||||
Error **errp)
|
||||
{
|
||||
int i ;
|
||||
|
||||
for (i = 0; i < s->num_cs; ++i) {
|
||||
AspeedSMCFlash *fl = &s->flashes[i];
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
qemu_irq cs_line;
|
||||
|
||||
/*
|
||||
* FIXME: check that we are not using a flash module exceeding
|
||||
* the controller segment size
|
||||
*/
|
||||
fl->flash = ssi_create_slave_no_init(s->spi, flashtype);
|
||||
if (dinfo) {
|
||||
qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo),
|
||||
errp);
|
||||
}
|
||||
qdev_init_nofail(fl->flash);
|
||||
|
||||
cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line);
|
||||
}
|
||||
}
|
||||
|
||||
static void palmetto_bmc_init(MachineState *machine)
|
||||
{
|
||||
PalmettoBMCState *bmc;
|
||||
|
||||
bmc = g_new0(PalmettoBMCState, 1);
|
||||
object_initialize(&bmc->soc, (sizeof(bmc->soc)), TYPE_AST2400);
|
||||
object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc),
|
||||
&error_abort);
|
||||
|
||||
memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size);
|
||||
memory_region_add_subregion(get_system_memory(), AST2400_SDRAM_BASE,
|
||||
&bmc->ram);
|
||||
object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram),
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&bmc->soc), 0x120CE416, "hw-strap1",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&bmc->soc), true, "realized",
|
||||
&error_abort);
|
||||
|
||||
palmetto_bmc_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort);
|
||||
palmetto_bmc_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort);
|
||||
|
||||
palmetto_bmc_binfo.kernel_filename = machine->kernel_filename;
|
||||
palmetto_bmc_binfo.initrd_filename = machine->initrd_filename;
|
||||
palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
palmetto_bmc_binfo.ram_size = ram_size;
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &palmetto_bmc_binfo);
|
||||
}
|
||||
|
||||
static void palmetto_bmc_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "OpenPOWER Palmetto BMC";
|
||||
mc->init = palmetto_bmc_init;
|
||||
mc->max_cpus = 1;
|
||||
mc->no_sdcard = 1;
|
||||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->no_sdcard = 1;
|
||||
mc->no_parallel = 1;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("palmetto-bmc", palmetto_bmc_machine_init);
|
@@ -1903,9 +1903,7 @@ static void pxa2xx_fir_write(void *opaque, hwaddr addr,
|
||||
else
|
||||
ch = ~value;
|
||||
if (s->chr && s->enable && (s->control[0] & (1 << 3))) /* TXE */
|
||||
/* XXX this blocks entire thread. Rewrite to use
|
||||
* qemu_chr_fe_write and background I/O callbacks */
|
||||
qemu_chr_fe_write_all(s->chr, &ch, 1);
|
||||
qemu_chr_fe_write(s->chr, &ch, 1);
|
||||
break;
|
||||
case ICSR0:
|
||||
s->status[0] &= ~(value & 0x66);
|
||||
|
@@ -1108,9 +1108,7 @@ static void strongarm_uart_tx(void *opaque)
|
||||
if (s->utcr3 & UTCR3_LBM) /* loopback */ {
|
||||
strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1);
|
||||
} else if (s->chr) {
|
||||
/* XXX this blocks entire thread. Rewrite to use
|
||||
* qemu_chr_fe_write and background I/O callbacks */
|
||||
qemu_chr_fe_write_all(s->chr, &s->tx_fifo[s->tx_start], 1);
|
||||
qemu_chr_fe_write(s->chr, &s->tx_fifo[s->tx_start], 1);
|
||||
}
|
||||
|
||||
s->tx_start = (s->tx_start + 1) % 8;
|
||||
|
@@ -53,7 +53,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus)
|
||||
uint16_t i;
|
||||
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
Aml *dev = aml_device("C%.03X", i);
|
||||
Aml *dev = aml_device("C%03x", i);
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(i)));
|
||||
aml_append(scope, dev);
|
||||
|
@@ -332,8 +332,6 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
||||
qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
|
||||
qdev_set_nic_properties(DEVICE(&s->gem[i]), nd);
|
||||
}
|
||||
object_property_set_int(OBJECT(&s->gem[i]), 2, "num-priority-queues",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
|
@@ -52,8 +52,8 @@ typedef struct {
|
||||
unsigned int pit_count;
|
||||
unsigned int samples;
|
||||
unsigned int play_pos;
|
||||
uint8_t data_on;
|
||||
uint8_t dummy_refresh_clock;
|
||||
int data_on;
|
||||
int dummy_refresh_clock;
|
||||
} PCSpkState;
|
||||
|
||||
static const char *s_spk = "pcspk";
|
||||
@@ -187,18 +187,6 @@ static void pcspk_realizefn(DeviceState *dev, Error **errp)
|
||||
pcspk_state = s;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_spk = {
|
||||
.name = "pcspk",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(data_on, PCSpkState),
|
||||
VMSTATE_UINT8(dummy_refresh_clock, PCSpkState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property pcspk_properties[] = {
|
||||
DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
@@ -210,7 +198,6 @@ static void pcspk_class_initfn(ObjectClass *klass, void *data)
|
||||
|
||||
dc->realize = pcspk_realizefn;
|
||||
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
|
||||
dc->vmsd = &vmstate_spk;
|
||||
dc->props = pcspk_properties;
|
||||
/* Reason: realize sets global pcspk_state */
|
||||
dc->cannot_instantiate_with_device_add_yet = true;
|
||||
|
@@ -1189,9 +1189,9 @@ static Property m25p80_properties[] = {
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_m25p80 = {
|
||||
.name = "m25p80",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.name = "xilinx_spi",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 1,
|
||||
.pre_save = m25p80_pre_save,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(state, Flash),
|
||||
@@ -1200,19 +1200,20 @@ static const VMStateDescription vmstate_m25p80 = {
|
||||
VMSTATE_UINT32(pos, Flash),
|
||||
VMSTATE_UINT8(needed_bytes, Flash),
|
||||
VMSTATE_UINT8(cmd_in_progress, Flash),
|
||||
VMSTATE_UNUSED(4),
|
||||
VMSTATE_UINT32(cur_addr, Flash),
|
||||
VMSTATE_BOOL(write_enable, Flash),
|
||||
VMSTATE_BOOL(reset_enable, Flash),
|
||||
VMSTATE_UINT8(ear, Flash),
|
||||
VMSTATE_BOOL(four_bytes_address_mode, Flash),
|
||||
VMSTATE_UINT32(nonvolatile_cfg, Flash),
|
||||
VMSTATE_UINT32(volatile_cfg, Flash),
|
||||
VMSTATE_UINT32(enh_volatile_cfg, Flash),
|
||||
VMSTATE_BOOL(quad_enable, Flash),
|
||||
VMSTATE_UINT8(spansion_cr1nv, Flash),
|
||||
VMSTATE_UINT8(spansion_cr2nv, Flash),
|
||||
VMSTATE_UINT8(spansion_cr3nv, Flash),
|
||||
VMSTATE_UINT8(spansion_cr4nv, Flash),
|
||||
VMSTATE_BOOL_V(reset_enable, Flash, 2),
|
||||
VMSTATE_UINT8_V(ear, Flash, 2),
|
||||
VMSTATE_BOOL_V(four_bytes_address_mode, Flash, 2),
|
||||
VMSTATE_UINT32_V(nonvolatile_cfg, Flash, 2),
|
||||
VMSTATE_UINT32_V(volatile_cfg, Flash, 2),
|
||||
VMSTATE_UINT32_V(enh_volatile_cfg, Flash, 2),
|
||||
VMSTATE_BOOL_V(quad_enable, Flash, 3),
|
||||
VMSTATE_UINT8_V(spansion_cr1nv, Flash, 3),
|
||||
VMSTATE_UINT8_V(spansion_cr2nv, Flash, 3),
|
||||
VMSTATE_UINT8_V(spansion_cr3nv, Flash, 3),
|
||||
VMSTATE_UINT8_V(spansion_cr4nv, Flash, 3),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@@ -258,8 +258,10 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
||||
req->has_sg = true;
|
||||
dma_acct_start(n->conf.blk, &req->acct, &req->qsg, acct);
|
||||
req->aiocb = is_write ?
|
||||
dma_blk_write(n->conf.blk, &req->qsg, data_offset, nvme_rw_cb, req) :
|
||||
dma_blk_read(n->conf.blk, &req->qsg, data_offset, nvme_rw_cb, req);
|
||||
dma_blk_write(n->conf.blk, &req->qsg, data_offset, BDRV_SECTOR_SIZE,
|
||||
nvme_rw_cb, req) :
|
||||
dma_blk_read(n->conf.blk, &req->qsg, data_offset, BDRV_SECTOR_SIZE,
|
||||
nvme_rw_cb, req);
|
||||
|
||||
return NVME_NO_COMPLETE;
|
||||
}
|
||||
|
@@ -992,7 +992,7 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data)
|
||||
vdc->load = virtio_blk_load_device;
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_blk_info = {
|
||||
static const TypeInfo virtio_device_info = {
|
||||
.name = TYPE_VIRTIO_BLK,
|
||||
.parent = TYPE_VIRTIO_DEVICE,
|
||||
.instance_size = sizeof(VirtIOBlock),
|
||||
@@ -1002,7 +1002,7 @@ static const TypeInfo virtio_blk_info = {
|
||||
|
||||
static void virtio_register_types(void)
|
||||
{
|
||||
type_register_static(&virtio_blk_info);
|
||||
type_register_static(&virtio_device_info);
|
||||
}
|
||||
|
||||
type_init(virtio_register_types)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user