Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
f71558480c
1
Kconfig
1
Kconfig
@ -1,5 +1,6 @@
|
|||||||
source Kconfig.host
|
source Kconfig.host
|
||||||
source backends/Kconfig
|
source backends/Kconfig
|
||||||
source accel/Kconfig
|
source accel/Kconfig
|
||||||
|
source target/Kconfig
|
||||||
source hw/Kconfig
|
source hw/Kconfig
|
||||||
source semihosting/Kconfig
|
source semihosting/Kconfig
|
||||||
|
81
MAINTAINERS
81
MAINTAINERS
@ -87,7 +87,7 @@ S390 general architecture support
|
|||||||
M: Cornelia Huck <cohuck@redhat.com>
|
M: Cornelia Huck <cohuck@redhat.com>
|
||||||
M: Thomas Huth <thuth@redhat.com>
|
M: Thomas Huth <thuth@redhat.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: default-configs/*/s390x-softmmu.mak
|
F: configs/devices/s390x-softmmu/default.mak
|
||||||
F: gdb-xml/s390*.xml
|
F: gdb-xml/s390*.xml
|
||||||
F: hw/char/sclp*.[hc]
|
F: hw/char/sclp*.[hc]
|
||||||
F: hw/char/terminal3270.c
|
F: hw/char/terminal3270.c
|
||||||
@ -196,7 +196,7 @@ F: target/hexagon/
|
|||||||
F: linux-user/hexagon/
|
F: linux-user/hexagon/
|
||||||
F: tests/tcg/hexagon/
|
F: tests/tcg/hexagon/
|
||||||
F: disas/hexagon.c
|
F: disas/hexagon.c
|
||||||
F: default-configs/targets/hexagon-linux-user.mak
|
F: configs/targets/hexagon-linux-user/default.mak
|
||||||
F: docker/dockerfiles/debian-hexagon-cross.docker
|
F: docker/dockerfiles/debian-hexagon-cross.docker
|
||||||
F: docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh
|
F: docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh
|
||||||
|
|
||||||
@ -229,7 +229,7 @@ R: Jiaxun Yang <jiaxun.yang@flygoat.com>
|
|||||||
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
|
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
|
||||||
S: Odd Fixes
|
S: Odd Fixes
|
||||||
F: target/mips/
|
F: target/mips/
|
||||||
F: default-configs/*/*mips*
|
F: configs/devices/mips*/*
|
||||||
F: disas/mips.c
|
F: disas/mips.c
|
||||||
F: docs/system/cpu-models-mips.rst.inc
|
F: docs/system/cpu-models-mips.rst.inc
|
||||||
F: hw/intc/mips_gic.c
|
F: hw/intc/mips_gic.c
|
||||||
@ -255,7 +255,7 @@ S: Maintained
|
|||||||
F: target/nios2/
|
F: target/nios2/
|
||||||
F: hw/nios2/
|
F: hw/nios2/
|
||||||
F: disas/nios2.c
|
F: disas/nios2.c
|
||||||
F: default-configs/*/nios2-softmmu.mak
|
F: configs/devices/nios2-softmmu/default.mak
|
||||||
|
|
||||||
OpenRISC TCG CPUs
|
OpenRISC TCG CPUs
|
||||||
M: Stafford Horne <shorne@gmail.com>
|
M: Stafford Horne <shorne@gmail.com>
|
||||||
@ -297,6 +297,8 @@ M: Richard Henderson <richard.henderson@linaro.org>
|
|||||||
M: David Hildenbrand <david@redhat.com>
|
M: David Hildenbrand <david@redhat.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: target/s390x/
|
F: target/s390x/
|
||||||
|
F: target/s390x/tcg
|
||||||
|
F: target/s390x/cpu_models_*.[ch]
|
||||||
F: hw/s390x/
|
F: hw/s390x/
|
||||||
F: disas/s390.c
|
F: disas/s390.c
|
||||||
F: tests/tcg/s390x/
|
F: tests/tcg/s390x/
|
||||||
@ -342,7 +344,7 @@ F: hw/xtensa/
|
|||||||
F: tests/tcg/xtensa/
|
F: tests/tcg/xtensa/
|
||||||
F: disas/xtensa.c
|
F: disas/xtensa.c
|
||||||
F: include/hw/xtensa/xtensa-isa.h
|
F: include/hw/xtensa/xtensa-isa.h
|
||||||
F: default-configs/*/xtensa*.mak
|
F: configs/devices/xtensa*/default.mak
|
||||||
|
|
||||||
TriCore TCG CPUs
|
TriCore TCG CPUs
|
||||||
M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
|
M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
|
||||||
@ -393,9 +395,7 @@ M: Halil Pasic <pasic@linux.ibm.com>
|
|||||||
M: Cornelia Huck <cohuck@redhat.com>
|
M: Cornelia Huck <cohuck@redhat.com>
|
||||||
M: Christian Borntraeger <borntraeger@de.ibm.com>
|
M: Christian Borntraeger <borntraeger@de.ibm.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: target/s390x/kvm.c
|
F: target/s390x/kvm/
|
||||||
F: target/s390x/kvm_s390x.h
|
|
||||||
F: target/s390x/kvm-stub.c
|
|
||||||
F: target/s390x/ioinst.[ch]
|
F: target/s390x/ioinst.[ch]
|
||||||
F: target/s390x/machine.c
|
F: target/s390x/machine.c
|
||||||
F: target/s390x/sigp.c
|
F: target/s390x/sigp.c
|
||||||
@ -794,6 +794,7 @@ F: hw/input/tsc2005.c
|
|||||||
F: hw/misc/cbus.c
|
F: hw/misc/cbus.c
|
||||||
F: hw/rtc/twl92230.c
|
F: hw/rtc/twl92230.c
|
||||||
F: include/hw/display/blizzard.h
|
F: include/hw/display/blizzard.h
|
||||||
|
F: include/hw/input/lm832x.h
|
||||||
F: include/hw/input/tsc2xxx.h
|
F: include/hw/input/tsc2xxx.h
|
||||||
F: include/hw/misc/cbus.h
|
F: include/hw/misc/cbus.h
|
||||||
F: tests/acceptance/machine_arm_n8x0.py
|
F: tests/acceptance/machine_arm_n8x0.py
|
||||||
@ -846,8 +847,8 @@ F: hw/display/tc6393xb.c
|
|||||||
F: hw/gpio/max7310.c
|
F: hw/gpio/max7310.c
|
||||||
F: hw/gpio/zaurus.c
|
F: hw/gpio/zaurus.c
|
||||||
F: hw/misc/mst_fpga.c
|
F: hw/misc/mst_fpga.c
|
||||||
F: hw/misc/max111x.c
|
F: hw/adc/max111x.c
|
||||||
F: include/hw/misc/max111x.h
|
F: include/hw/adc/max111x.h
|
||||||
F: include/hw/arm/pxa.h
|
F: include/hw/arm/pxa.h
|
||||||
F: include/hw/arm/sharpsl.h
|
F: include/hw/arm/sharpsl.h
|
||||||
F: include/hw/display/tc6393xb.h
|
F: include/hw/display/tc6393xb.h
|
||||||
@ -893,6 +894,13 @@ F: hw/*/stellaris*
|
|||||||
F: include/hw/input/gamepad.h
|
F: include/hw/input/gamepad.h
|
||||||
F: docs/system/arm/stellaris.rst
|
F: docs/system/arm/stellaris.rst
|
||||||
|
|
||||||
|
STM32VLDISCOVERY
|
||||||
|
M: Alexandre Iooss <erdnaxe@crans.org>
|
||||||
|
L: qemu-arm@nongnu.org
|
||||||
|
S: Maintained
|
||||||
|
F: hw/arm/stm32vldiscovery.c
|
||||||
|
F: docs/system/arm/stm32.rst
|
||||||
|
|
||||||
Versatile Express
|
Versatile Express
|
||||||
M: Peter Maydell <peter.maydell@linaro.org>
|
M: Peter Maydell <peter.maydell@linaro.org>
|
||||||
L: qemu-arm@nongnu.org
|
L: qemu-arm@nongnu.org
|
||||||
@ -925,8 +933,10 @@ L: qemu-arm@nongnu.org
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/*/xilinx_*
|
F: hw/*/xilinx_*
|
||||||
F: hw/*/cadence_*
|
F: hw/*/cadence_*
|
||||||
F: hw/misc/zynq*
|
F: hw/misc/zynq_slcr.c
|
||||||
F: include/hw/misc/zynq*
|
F: hw/adc/zynq-xadc.c
|
||||||
|
F: include/hw/misc/zynq_slcr.h
|
||||||
|
F: include/hw/adc/zynq-xadc.h
|
||||||
X: hw/ssi/xilinx_*
|
X: hw/ssi/xilinx_*
|
||||||
|
|
||||||
Xilinx ZynqMP and Versal
|
Xilinx ZynqMP and Versal
|
||||||
@ -948,6 +958,12 @@ L: qemu-arm@nongnu.org
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/arm/virt-acpi-build.c
|
F: hw/arm/virt-acpi-build.c
|
||||||
|
|
||||||
|
STM32F100
|
||||||
|
M: Alexandre Iooss <erdnaxe@crans.org>
|
||||||
|
L: qemu-arm@nongnu.org
|
||||||
|
S: Maintained
|
||||||
|
F: hw/arm/stm32f100_soc.c
|
||||||
|
|
||||||
STM32F205
|
STM32F205
|
||||||
M: Alistair Francis <alistair@alistair23.me>
|
M: Alistair Francis <alistair@alistair23.me>
|
||||||
M: Peter Maydell <peter.maydell@linaro.org>
|
M: Peter Maydell <peter.maydell@linaro.org>
|
||||||
@ -1041,7 +1057,7 @@ AVR Machines
|
|||||||
AVR MCUs
|
AVR MCUs
|
||||||
M: Michael Rolnik <mrolnik@gmail.com>
|
M: Michael Rolnik <mrolnik@gmail.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: default-configs/*/avr-softmmu.mak
|
F: configs/devices/avr-softmmu/default.mak
|
||||||
F: hw/avr/
|
F: hw/avr/
|
||||||
F: include/hw/char/avr_usart.h
|
F: include/hw/char/avr_usart.h
|
||||||
F: hw/char/avr_usart.c
|
F: hw/char/avr_usart.c
|
||||||
@ -1069,7 +1085,7 @@ HP B160L
|
|||||||
M: Richard Henderson <richard.henderson@linaro.org>
|
M: Richard Henderson <richard.henderson@linaro.org>
|
||||||
R: Helge Deller <deller@gmx.de>
|
R: Helge Deller <deller@gmx.de>
|
||||||
S: Odd Fixes
|
S: Odd Fixes
|
||||||
F: default-configs/*/hppa-softmmu.mak
|
F: configs/devices/hppa-softmmu/default.mak
|
||||||
F: hw/hppa/
|
F: hw/hppa/
|
||||||
F: pc-bios/hppa-firmware.img
|
F: pc-bios/hppa-firmware.img
|
||||||
|
|
||||||
@ -1288,7 +1304,7 @@ S: Maintained
|
|||||||
F: hw/ppc/prep.c
|
F: hw/ppc/prep.c
|
||||||
F: hw/ppc/prep_systemio.c
|
F: hw/ppc/prep_systemio.c
|
||||||
F: hw/ppc/rs6000_mc.c
|
F: hw/ppc/rs6000_mc.c
|
||||||
F: hw/pci-host/prep.[hc]
|
F: hw/pci-host/raven.c
|
||||||
F: hw/isa/i82378.c
|
F: hw/isa/i82378.c
|
||||||
F: hw/isa/pc87312.c
|
F: hw/isa/pc87312.c
|
||||||
F: hw/dma/i82374.c
|
F: hw/dma/i82374.c
|
||||||
@ -1360,6 +1376,18 @@ F: hw/pci-host/mv64361.c
|
|||||||
F: hw/pci-host/mv643xx.h
|
F: hw/pci-host/mv643xx.h
|
||||||
F: include/hw/pci-host/mv64361.h
|
F: include/hw/pci-host/mv64361.h
|
||||||
|
|
||||||
|
Virtual Open Firmware (VOF)
|
||||||
|
M: Alexey Kardashevskiy <aik@ozlabs.ru>
|
||||||
|
R: David Gibson <david@gibson.dropbear.id.au>
|
||||||
|
R: Greg Kurz <groug@kaod.org>
|
||||||
|
L: qemu-ppc@nongnu.org
|
||||||
|
S: Maintained
|
||||||
|
F: hw/ppc/spapr_vof*
|
||||||
|
F: hw/ppc/vof*
|
||||||
|
F: include/hw/ppc/vof*
|
||||||
|
F: pc-bios/vof/*
|
||||||
|
F: pc-bios/vof*
|
||||||
|
|
||||||
RISC-V Machines
|
RISC-V Machines
|
||||||
---------------
|
---------------
|
||||||
OpenTitan
|
OpenTitan
|
||||||
@ -1496,7 +1524,7 @@ F: hw/s390x/
|
|||||||
F: include/hw/s390x/
|
F: include/hw/s390x/
|
||||||
F: hw/watchdog/wdt_diag288.c
|
F: hw/watchdog/wdt_diag288.c
|
||||||
F: include/hw/watchdog/wdt_diag288.h
|
F: include/hw/watchdog/wdt_diag288.h
|
||||||
F: default-configs/*/s390x-softmmu.mak
|
F: configs/devices/s390x-softmmu/default.mak
|
||||||
F: tests/acceptance/machine_s390_ccw_virtio.py
|
F: tests/acceptance/machine_s390_ccw_virtio.py
|
||||||
T: git https://gitlab.com/cohuck/qemu.git s390-next
|
T: git https://gitlab.com/cohuck/qemu.git s390-next
|
||||||
T: git https://github.com/borntraeger/qemu.git s390-next
|
T: git https://github.com/borntraeger/qemu.git s390-next
|
||||||
@ -1703,7 +1731,6 @@ F: hw/pci-bridge/*
|
|||||||
F: qapi/pci.json
|
F: qapi/pci.json
|
||||||
F: docs/pci*
|
F: docs/pci*
|
||||||
F: docs/specs/*pci*
|
F: docs/specs/*pci*
|
||||||
F: default-configs/pci.mak
|
|
||||||
|
|
||||||
ACPI/SMBIOS
|
ACPI/SMBIOS
|
||||||
M: Michael S. Tsirkin <mst@redhat.com>
|
M: Michael S. Tsirkin <mst@redhat.com>
|
||||||
@ -1796,7 +1823,8 @@ F: include/hw/sd/sd*
|
|||||||
F: hw/sd/core.c
|
F: hw/sd/core.c
|
||||||
F: hw/sd/sd*
|
F: hw/sd/sd*
|
||||||
F: hw/sd/ssi-sd.c
|
F: hw/sd/ssi-sd.c
|
||||||
F: tests/qtest/sd*
|
F: tests/qtest/fuzz-sdcard-test.c
|
||||||
|
F: tests/qtest/sdhci-test.c
|
||||||
|
|
||||||
USB
|
USB
|
||||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||||
@ -1808,7 +1836,6 @@ F: docs/usb2.txt
|
|||||||
F: docs/usb-storage.txt
|
F: docs/usb-storage.txt
|
||||||
F: include/hw/usb.h
|
F: include/hw/usb.h
|
||||||
F: include/hw/usb/
|
F: include/hw/usb/
|
||||||
F: default-configs/usb.mak
|
|
||||||
|
|
||||||
USB (serial adapter)
|
USB (serial adapter)
|
||||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||||
@ -1952,6 +1979,15 @@ F: include/sysemu/rng*.h
|
|||||||
F: backends/rng*.c
|
F: backends/rng*.c
|
||||||
F: tests/qtest/virtio-rng-test.c
|
F: tests/qtest/virtio-rng-test.c
|
||||||
|
|
||||||
|
vhost-user-rng
|
||||||
|
M: Mathieu Poirier <mathieu.poirier@linaro.org>
|
||||||
|
S: Supported
|
||||||
|
F: docs/tools/vhost-user-rng.rst
|
||||||
|
F: hw/virtio/vhost-user-rng.c
|
||||||
|
F: hw/virtio/vhost-user-rng-pci.c
|
||||||
|
F: include/hw/virtio/vhost-user-rng.h
|
||||||
|
F: tools/vhost-user-rng/*
|
||||||
|
|
||||||
virtio-crypto
|
virtio-crypto
|
||||||
M: Gonglei <arei.gonglei@huawei.com>
|
M: Gonglei <arei.gonglei@huawei.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
@ -2958,14 +2994,14 @@ M: Warner Losh <imp@bsdimp.com>
|
|||||||
R: Kyle Evans <kevans@freebsd.org>
|
R: Kyle Evans <kevans@freebsd.org>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: bsd-user/
|
F: bsd-user/
|
||||||
F: default-configs/targets/*-bsd-user.mak
|
F: configs/targets/*-bsd-user.mak
|
||||||
T: git https://github.com/qemu-bsd-user/qemu-bsd-user bsd-user-rebase-3.1
|
T: git https://github.com/qemu-bsd-user/qemu-bsd-user bsd-user-rebase-3.1
|
||||||
|
|
||||||
Linux user
|
Linux user
|
||||||
M: Laurent Vivier <laurent@vivier.eu>
|
M: Laurent Vivier <laurent@vivier.eu>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: linux-user/
|
F: linux-user/
|
||||||
F: default-configs/targets/*linux-user.mak
|
F: configs/targets/*linux-user.mak
|
||||||
F: scripts/qemu-binfmt-conf.sh
|
F: scripts/qemu-binfmt-conf.sh
|
||||||
F: scripts/update-syscalltbl.sh
|
F: scripts/update-syscalltbl.sh
|
||||||
F: scripts/update-mips-syscall-args.sh
|
F: scripts/update-mips-syscall-args.sh
|
||||||
@ -3060,7 +3096,8 @@ S: Supported
|
|||||||
F: block/vmdk.c
|
F: block/vmdk.c
|
||||||
|
|
||||||
RBD
|
RBD
|
||||||
M: Jason Dillaman <dillaman@redhat.com>
|
M: Ilya Dryomov <idryomov@gmail.com>
|
||||||
|
R: Peter Lieven <pl@kamp.de>
|
||||||
L: qemu-block@nongnu.org
|
L: qemu-block@nongnu.org
|
||||||
S: Supported
|
S: Supported
|
||||||
F: block/rbd.c
|
F: block/rbd.c
|
||||||
|
@ -44,7 +44,7 @@ static const TypeInfo accel_type = {
|
|||||||
AccelClass *accel_find(const char *opt_name)
|
AccelClass *accel_find(const char *opt_name)
|
||||||
{
|
{
|
||||||
char *class_name = g_strdup_printf(ACCEL_CLASS_NAME("%s"), opt_name);
|
char *class_name = g_strdup_printf(ACCEL_CLASS_NAME("%s"), opt_name);
|
||||||
AccelClass *ac = ACCEL_CLASS(object_class_by_name(class_name));
|
AccelClass *ac = ACCEL_CLASS(module_object_class_by_name(class_name));
|
||||||
g_free(class_name);
|
g_free(class_name);
|
||||||
return ac;
|
return ac;
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ void accel_init_ops_interfaces(AccelClass *ac)
|
|||||||
g_assert(ac_name != NULL);
|
g_assert(ac_name != NULL);
|
||||||
|
|
||||||
ops_name = g_strdup_printf("%s" ACCEL_OPS_SUFFIX, ac_name);
|
ops_name = g_strdup_printf("%s" ACCEL_OPS_SUFFIX, ac_name);
|
||||||
ops = ACCEL_OPS_CLASS(object_class_by_name(ops_name));
|
ops = ACCEL_OPS_CLASS(module_object_class_by_name(ops_name));
|
||||||
g_free(ops_name);
|
g_free(ops_name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,6 +1,2 @@
|
|||||||
qtest_ss = ss.source_set()
|
qtest_module_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_POSIX'],
|
||||||
qtest_ss.add(files(
|
if_true: files('qtest.c'))
|
||||||
'qtest.c',
|
|
||||||
))
|
|
||||||
|
|
||||||
specific_ss.add_all(when: ['CONFIG_SOFTMMU', 'CONFIG_POSIX'], if_true: qtest_ss)
|
|
||||||
|
@ -45,6 +45,7 @@ static const TypeInfo qtest_accel_type = {
|
|||||||
.parent = TYPE_ACCEL,
|
.parent = TYPE_ACCEL,
|
||||||
.class_init = qtest_accel_class_init,
|
.class_init = qtest_accel_class_init,
|
||||||
};
|
};
|
||||||
|
module_obj(TYPE_QTEST_ACCEL);
|
||||||
|
|
||||||
static void qtest_accel_ops_class_init(ObjectClass *oc, void *data)
|
static void qtest_accel_ops_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
@ -61,6 +62,7 @@ static const TypeInfo qtest_accel_ops_type = {
|
|||||||
.class_init = qtest_accel_ops_class_init,
|
.class_init = qtest_accel_ops_class_init,
|
||||||
.abstract = true,
|
.abstract = true,
|
||||||
};
|
};
|
||||||
|
module_obj(ACCEL_OPS_NAME("qtest"));
|
||||||
|
|
||||||
static void qtest_type_init(void)
|
static void qtest_type_init(void)
|
||||||
{
|
{
|
||||||
|
@ -38,8 +38,8 @@
|
|||||||
#include "exec/cpu-all.h"
|
#include "exec/cpu-all.h"
|
||||||
#include "sysemu/cpu-timers.h"
|
#include "sysemu/cpu-timers.h"
|
||||||
#include "sysemu/replay.h"
|
#include "sysemu/replay.h"
|
||||||
|
#include "exec/helper-proto.h"
|
||||||
#include "tb-hash.h"
|
#include "tb-hash.h"
|
||||||
#include "tb-lookup.h"
|
|
||||||
#include "tb-context.h"
|
#include "tb-context.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@ -145,6 +145,93 @@ static void init_delay_params(SyncClocks *sc, const CPUState *cpu)
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG USER ONLY */
|
#endif /* CONFIG USER ONLY */
|
||||||
|
|
||||||
|
/* Might cause an exception, so have a longjmp destination ready */
|
||||||
|
static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc,
|
||||||
|
target_ulong cs_base,
|
||||||
|
uint32_t flags, uint32_t cflags)
|
||||||
|
{
|
||||||
|
TranslationBlock *tb;
|
||||||
|
uint32_t hash;
|
||||||
|
|
||||||
|
/* we should never be trying to look up an INVALID tb */
|
||||||
|
tcg_debug_assert(!(cflags & CF_INVALID));
|
||||||
|
|
||||||
|
hash = tb_jmp_cache_hash_func(pc);
|
||||||
|
tb = qatomic_rcu_read(&cpu->tb_jmp_cache[hash]);
|
||||||
|
|
||||||
|
if (likely(tb &&
|
||||||
|
tb->pc == pc &&
|
||||||
|
tb->cs_base == cs_base &&
|
||||||
|
tb->flags == flags &&
|
||||||
|
tb->trace_vcpu_dstate == *cpu->trace_dstate &&
|
||||||
|
tb_cflags(tb) == cflags)) {
|
||||||
|
return tb;
|
||||||
|
}
|
||||||
|
tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags);
|
||||||
|
if (tb == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
qatomic_set(&cpu->tb_jmp_cache[hash], tb);
|
||||||
|
return tb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void log_cpu_exec(target_ulong pc, CPUState *cpu,
|
||||||
|
const TranslationBlock *tb)
|
||||||
|
{
|
||||||
|
if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_CPU | CPU_LOG_EXEC))
|
||||||
|
&& qemu_log_in_addr_range(pc)) {
|
||||||
|
|
||||||
|
qemu_log_mask(CPU_LOG_EXEC,
|
||||||
|
"Trace %d: %p [" TARGET_FMT_lx
|
||||||
|
"/" TARGET_FMT_lx "/%08x/%08x] %s\n",
|
||||||
|
cpu->cpu_index, tb->tc.ptr, tb->cs_base, pc,
|
||||||
|
tb->flags, tb->cflags, lookup_symbol(pc));
|
||||||
|
|
||||||
|
#if defined(DEBUG_DISAS)
|
||||||
|
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
|
||||||
|
FILE *logfile = qemu_log_lock();
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
if (qemu_loglevel_mask(CPU_LOG_TB_FPU)) {
|
||||||
|
flags |= CPU_DUMP_FPU;
|
||||||
|
}
|
||||||
|
#if defined(TARGET_I386)
|
||||||
|
flags |= CPU_DUMP_CCOP;
|
||||||
|
#endif
|
||||||
|
log_cpu_state(cpu, flags);
|
||||||
|
qemu_log_unlock(logfile);
|
||||||
|
}
|
||||||
|
#endif /* DEBUG_DISAS */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* helper_lookup_tb_ptr: quick check for next tb
|
||||||
|
* @env: current cpu state
|
||||||
|
*
|
||||||
|
* Look for an existing TB matching the current cpu state.
|
||||||
|
* If found, return the code pointer. If not found, return
|
||||||
|
* the tcg epilogue so that we return into cpu_tb_exec.
|
||||||
|
*/
|
||||||
|
const void *HELPER(lookup_tb_ptr)(CPUArchState *env)
|
||||||
|
{
|
||||||
|
CPUState *cpu = env_cpu(env);
|
||||||
|
TranslationBlock *tb;
|
||||||
|
target_ulong cs_base, pc;
|
||||||
|
uint32_t flags;
|
||||||
|
|
||||||
|
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||||
|
|
||||||
|
tb = tb_lookup(cpu, pc, cs_base, flags, curr_cflags(cpu));
|
||||||
|
if (tb == NULL) {
|
||||||
|
return tcg_code_gen_epilogue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_cpu_exec(pc, cpu, tb);
|
||||||
|
|
||||||
|
return tb->tc.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
/* Execute a TB, and fix up the CPU state afterwards if necessary */
|
/* Execute a TB, and fix up the CPU state afterwards if necessary */
|
||||||
/*
|
/*
|
||||||
* Disable CFI checks.
|
* Disable CFI checks.
|
||||||
@ -163,28 +250,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
|
|||||||
TranslationBlock *last_tb;
|
TranslationBlock *last_tb;
|
||||||
const void *tb_ptr = itb->tc.ptr;
|
const void *tb_ptr = itb->tc.ptr;
|
||||||
|
|
||||||
qemu_log_mask_and_addr(CPU_LOG_EXEC, itb->pc,
|
log_cpu_exec(itb->pc, cpu, itb);
|
||||||
"Trace %d: %p ["
|
|
||||||
TARGET_FMT_lx "/" TARGET_FMT_lx "/%#x] %s\n",
|
|
||||||
cpu->cpu_index, itb->tc.ptr,
|
|
||||||
itb->cs_base, itb->pc, itb->flags,
|
|
||||||
lookup_symbol(itb->pc));
|
|
||||||
|
|
||||||
#if defined(DEBUG_DISAS)
|
|
||||||
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)
|
|
||||||
&& qemu_log_in_addr_range(itb->pc)) {
|
|
||||||
FILE *logfile = qemu_log_lock();
|
|
||||||
int flags = 0;
|
|
||||||
if (qemu_loglevel_mask(CPU_LOG_TB_FPU)) {
|
|
||||||
flags |= CPU_DUMP_FPU;
|
|
||||||
}
|
|
||||||
#if defined(TARGET_I386)
|
|
||||||
flags |= CPU_DUMP_CCOP;
|
|
||||||
#endif
|
|
||||||
log_cpu_state(cpu, flags);
|
|
||||||
qemu_log_unlock(logfile);
|
|
||||||
}
|
|
||||||
#endif /* DEBUG_DISAS */
|
|
||||||
|
|
||||||
qemu_thread_jit_execute();
|
qemu_thread_jit_execute();
|
||||||
ret = tcg_qemu_tb_exec(env, tb_ptr);
|
ret = tcg_qemu_tb_exec(env, tb_ptr);
|
||||||
|
29
accel/tcg/hmp.c
Normal file
29
accel/tcg/hmp.c
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
#include "exec/exec-all.h"
|
||||||
|
#include "monitor/monitor.h"
|
||||||
|
#include "sysemu/tcg.h"
|
||||||
|
|
||||||
|
static void hmp_info_jit(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
if (!tcg_enabled()) {
|
||||||
|
error_report("JIT information is only available with accel=tcg");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dump_exec_info();
|
||||||
|
dump_drift_info();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hmp_info_opcount(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
dump_opcount_info();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hmp_tcg_register(void)
|
||||||
|
{
|
||||||
|
monitor_register_hmp("jit", true, hmp_info_jit);
|
||||||
|
monitor_register_hmp("opcount", true, hmp_info_opcount);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(hmp_tcg_register);
|
@ -15,8 +15,12 @@ specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
|
|||||||
|
|
||||||
specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(
|
specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(
|
||||||
'cputlb.c',
|
'cputlb.c',
|
||||||
|
'hmp.c',
|
||||||
|
))
|
||||||
|
|
||||||
|
tcg_module_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(
|
||||||
'tcg-accel-ops.c',
|
'tcg-accel-ops.c',
|
||||||
'tcg-accel-ops-mttcg.c',
|
'tcg-accel-ops-mttcg.c',
|
||||||
'tcg-accel-ops-icount.c',
|
'tcg-accel-ops-icount.c',
|
||||||
'tcg-accel-ops-rr.c'
|
'tcg-accel-ops-rr.c',
|
||||||
))
|
))
|
||||||
|
@ -34,6 +34,7 @@ struct TBContext {
|
|||||||
|
|
||||||
/* statistics */
|
/* statistics */
|
||||||
unsigned tb_flush_count;
|
unsigned tb_flush_count;
|
||||||
|
unsigned tb_phys_invalidate_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern TBContext tb_ctx;
|
extern TBContext tb_ctx;
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
|
|
||||||
*
|
|
||||||
* License: GNU GPL, version 2 or later.
|
|
||||||
* See the COPYING file in the top-level directory.
|
|
||||||
*/
|
|
||||||
#ifndef EXEC_TB_LOOKUP_H
|
|
||||||
#define EXEC_TB_LOOKUP_H
|
|
||||||
|
|
||||||
#ifdef NEED_CPU_H
|
|
||||||
#include "cpu.h"
|
|
||||||
#else
|
|
||||||
#include "exec/poison.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "exec/exec-all.h"
|
|
||||||
#include "tb-hash.h"
|
|
||||||
|
|
||||||
/* Might cause an exception, so have a longjmp destination ready */
|
|
||||||
static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc,
|
|
||||||
target_ulong cs_base,
|
|
||||||
uint32_t flags, uint32_t cflags)
|
|
||||||
{
|
|
||||||
TranslationBlock *tb;
|
|
||||||
uint32_t hash;
|
|
||||||
|
|
||||||
/* we should never be trying to look up an INVALID tb */
|
|
||||||
tcg_debug_assert(!(cflags & CF_INVALID));
|
|
||||||
|
|
||||||
hash = tb_jmp_cache_hash_func(pc);
|
|
||||||
tb = qatomic_rcu_read(&cpu->tb_jmp_cache[hash]);
|
|
||||||
|
|
||||||
if (likely(tb &&
|
|
||||||
tb->pc == pc &&
|
|
||||||
tb->cs_base == cs_base &&
|
|
||||||
tb->flags == flags &&
|
|
||||||
tb->trace_vcpu_dstate == *cpu->trace_dstate &&
|
|
||||||
tb_cflags(tb) == cflags)) {
|
|
||||||
return tb;
|
|
||||||
}
|
|
||||||
tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags);
|
|
||||||
if (tb == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
qatomic_set(&cpu->tb_jmp_cache[hash], tb);
|
|
||||||
return tb;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* EXEC_TB_LOOKUP_H */
|
|
@ -124,6 +124,7 @@ static const TypeInfo tcg_accel_ops_type = {
|
|||||||
.class_init = tcg_accel_ops_class_init,
|
.class_init = tcg_accel_ops_class_init,
|
||||||
.abstract = true,
|
.abstract = true,
|
||||||
};
|
};
|
||||||
|
module_obj(ACCEL_OPS_NAME("tcg"));
|
||||||
|
|
||||||
static void tcg_accel_ops_register_types(void)
|
static void tcg_accel_ops_register_types(void)
|
||||||
{
|
{
|
||||||
|
@ -238,6 +238,7 @@ static const TypeInfo tcg_accel_type = {
|
|||||||
.class_init = tcg_accel_class_init,
|
.class_init = tcg_accel_class_init,
|
||||||
.instance_size = sizeof(TCGState),
|
.instance_size = sizeof(TCGState),
|
||||||
};
|
};
|
||||||
|
module_obj(TYPE_TCG_ACCEL);
|
||||||
|
|
||||||
static void register_accel_types(void)
|
static void register_accel_types(void)
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include "disas/disas.h"
|
#include "disas/disas.h"
|
||||||
#include "exec/log.h"
|
#include "exec/log.h"
|
||||||
#include "tcg/tcg.h"
|
#include "tcg/tcg.h"
|
||||||
#include "tb-lookup.h"
|
|
||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
@ -158,27 +157,6 @@ uint64_t HELPER(ctpop_i64)(uint64_t arg)
|
|||||||
return ctpop64(arg);
|
return ctpop64(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *HELPER(lookup_tb_ptr)(CPUArchState *env)
|
|
||||||
{
|
|
||||||
CPUState *cpu = env_cpu(env);
|
|
||||||
TranslationBlock *tb;
|
|
||||||
target_ulong cs_base, pc;
|
|
||||||
uint32_t flags;
|
|
||||||
|
|
||||||
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
|
||||||
|
|
||||||
tb = tb_lookup(cpu, pc, cs_base, flags, curr_cflags(cpu));
|
|
||||||
if (tb == NULL) {
|
|
||||||
return tcg_code_gen_epilogue;
|
|
||||||
}
|
|
||||||
qemu_log_mask_and_addr(CPU_LOG_EXEC, pc,
|
|
||||||
"Chain %d: %p ["
|
|
||||||
TARGET_FMT_lx "/" TARGET_FMT_lx "/%#x] %s\n",
|
|
||||||
cpu->cpu_index, tb->tc.ptr, cs_base, pc, flags,
|
|
||||||
lookup_symbol(pc));
|
|
||||||
return tb->tc.ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HELPER(exit_atomic)(CPUArchState *env)
|
void HELPER(exit_atomic)(CPUArchState *env)
|
||||||
{
|
{
|
||||||
cpu_loop_exit_atomic(env_cpu(env), GETPC());
|
cpu_loop_exit_atomic(env_cpu(env), GETPC());
|
||||||
|
@ -496,11 +496,6 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tb_destroy(TranslationBlock *tb)
|
|
||||||
{
|
|
||||||
qemu_spin_destroy(&tb->jmp_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
|
bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -1342,8 +1337,8 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
|
|||||||
/* suppress any remaining jumps to this TB */
|
/* suppress any remaining jumps to this TB */
|
||||||
tb_jmp_unlink(tb);
|
tb_jmp_unlink(tb);
|
||||||
|
|
||||||
qatomic_set(&tcg_ctx->tb_phys_invalidate_count,
|
qatomic_set(&tb_ctx.tb_phys_invalidate_count,
|
||||||
tcg_ctx->tb_phys_invalidate_count + 1);
|
tb_ctx.tb_phys_invalidate_count + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tb_phys_invalidate__locked(TranslationBlock *tb)
|
static void tb_phys_invalidate__locked(TranslationBlock *tb)
|
||||||
@ -1911,6 +1906,13 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
|||||||
return tb;
|
return tb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert TB into the corresponding region tree before publishing it
|
||||||
|
* through QHT. Otherwise rewinding happened in the TB might fail to
|
||||||
|
* lookup itself using host PC.
|
||||||
|
*/
|
||||||
|
tcg_tb_insert(tb);
|
||||||
|
|
||||||
/* check next page if needed */
|
/* check next page if needed */
|
||||||
virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
|
virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
|
||||||
phys_page2 = -1;
|
phys_page2 = -1;
|
||||||
@ -1928,10 +1930,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
|||||||
|
|
||||||
orig_aligned -= ROUND_UP(sizeof(*tb), qemu_icache_linesize);
|
orig_aligned -= ROUND_UP(sizeof(*tb), qemu_icache_linesize);
|
||||||
qatomic_set(&tcg_ctx->code_gen_ptr, (void *)orig_aligned);
|
qatomic_set(&tcg_ctx->code_gen_ptr, (void *)orig_aligned);
|
||||||
tb_destroy(tb);
|
tcg_tb_remove(tb);
|
||||||
return existing_tb;
|
return existing_tb;
|
||||||
}
|
}
|
||||||
tcg_tb_insert(tb);
|
|
||||||
return tb;
|
return tb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2381,8 +2382,8 @@ void dump_exec_info(void)
|
|||||||
qemu_printf("\nStatistics:\n");
|
qemu_printf("\nStatistics:\n");
|
||||||
qemu_printf("TB flush count %u\n",
|
qemu_printf("TB flush count %u\n",
|
||||||
qatomic_read(&tb_ctx.tb_flush_count));
|
qatomic_read(&tb_ctx.tb_flush_count));
|
||||||
qemu_printf("TB invalidate count %zu\n",
|
qemu_printf("TB invalidate count %u\n",
|
||||||
tcg_tb_phys_invalidate_count());
|
qatomic_read(&tb_ctx.tb_phys_invalidate_count));
|
||||||
|
|
||||||
tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
|
tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
|
||||||
qemu_printf("TLB full flushes %zu\n", flush_full);
|
qemu_printf("TLB full flushes %zu\n", flush_full);
|
||||||
|
@ -42,6 +42,17 @@ void translator_loop_temp_check(DisasContextBase *db)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest)
|
||||||
|
{
|
||||||
|
/* Suppress goto_tb in the case of single-steping. */
|
||||||
|
if (db->singlestep_enabled || singlestep) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for the dest on the same page as the start of the TB. */
|
||||||
|
return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||||
CPUState *cpu, TranslationBlock *tb, int max_insns)
|
CPUState *cpu, TranslationBlock *tb, int max_insns)
|
||||||
{
|
{
|
||||||
|
@ -317,3 +317,5 @@ static void register_audio_spice(void)
|
|||||||
audio_driver_register(&spice_audio_driver);
|
audio_driver_register(&spice_audio_driver);
|
||||||
}
|
}
|
||||||
type_init(register_audio_spice);
|
type_init(register_audio_spice);
|
||||||
|
|
||||||
|
module_dep("ui-spice-core");
|
||||||
|
108
block.c
108
block.c
@ -4095,6 +4095,19 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
|
|||||||
NULL, 0, keep_old_opts);
|
NULL, 0, keep_old_opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bdrv_reopen_queue_free(BlockReopenQueue *bs_queue)
|
||||||
|
{
|
||||||
|
if (bs_queue) {
|
||||||
|
BlockReopenQueueEntry *bs_entry, *next;
|
||||||
|
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
|
||||||
|
qobject_unref(bs_entry->state.explicit_options);
|
||||||
|
qobject_unref(bs_entry->state.options);
|
||||||
|
g_free(bs_entry);
|
||||||
|
}
|
||||||
|
g_free(bs_queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reopen multiple BlockDriverStates atomically & transactionally.
|
* Reopen multiple BlockDriverStates atomically & transactionally.
|
||||||
*
|
*
|
||||||
@ -4111,19 +4124,26 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
|
|||||||
*
|
*
|
||||||
* All affected nodes must be drained between bdrv_reopen_queue() and
|
* All affected nodes must be drained between bdrv_reopen_queue() and
|
||||||
* bdrv_reopen_multiple().
|
* bdrv_reopen_multiple().
|
||||||
|
*
|
||||||
|
* To be called from the main thread, with all other AioContexts unlocked.
|
||||||
*/
|
*/
|
||||||
int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
|
int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
BlockReopenQueueEntry *bs_entry, *next;
|
BlockReopenQueueEntry *bs_entry, *next;
|
||||||
|
AioContext *ctx;
|
||||||
Transaction *tran = tran_new();
|
Transaction *tran = tran_new();
|
||||||
g_autoptr(GHashTable) found = NULL;
|
g_autoptr(GHashTable) found = NULL;
|
||||||
g_autoptr(GSList) refresh_list = NULL;
|
g_autoptr(GSList) refresh_list = NULL;
|
||||||
|
|
||||||
|
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
|
||||||
assert(bs_queue != NULL);
|
assert(bs_queue != NULL);
|
||||||
|
|
||||||
QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
|
QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
|
||||||
|
ctx = bdrv_get_aio_context(bs_entry->state.bs);
|
||||||
|
aio_context_acquire(ctx);
|
||||||
ret = bdrv_flush(bs_entry->state.bs);
|
ret = bdrv_flush(bs_entry->state.bs);
|
||||||
|
aio_context_release(ctx);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Error flushing drive");
|
error_setg_errno(errp, -ret, "Error flushing drive");
|
||||||
goto abort;
|
goto abort;
|
||||||
@ -4132,7 +4152,10 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
|
|||||||
|
|
||||||
QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
|
QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
|
||||||
assert(bs_entry->state.bs->quiesce_counter > 0);
|
assert(bs_entry->state.bs->quiesce_counter > 0);
|
||||||
|
ctx = bdrv_get_aio_context(bs_entry->state.bs);
|
||||||
|
aio_context_acquire(ctx);
|
||||||
ret = bdrv_reopen_prepare(&bs_entry->state, bs_queue, tran, errp);
|
ret = bdrv_reopen_prepare(&bs_entry->state, bs_queue, tran, errp);
|
||||||
|
aio_context_release(ctx);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
@ -4175,7 +4198,10 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
|
|||||||
* to first element.
|
* to first element.
|
||||||
*/
|
*/
|
||||||
QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
|
QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
|
||||||
|
ctx = bdrv_get_aio_context(bs_entry->state.bs);
|
||||||
|
aio_context_acquire(ctx);
|
||||||
bdrv_reopen_commit(&bs_entry->state);
|
bdrv_reopen_commit(&bs_entry->state);
|
||||||
|
aio_context_release(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
tran_commit(tran);
|
tran_commit(tran);
|
||||||
@ -4184,7 +4210,10 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
|
|||||||
BlockDriverState *bs = bs_entry->state.bs;
|
BlockDriverState *bs = bs_entry->state.bs;
|
||||||
|
|
||||||
if (bs->drv->bdrv_reopen_commit_post) {
|
if (bs->drv->bdrv_reopen_commit_post) {
|
||||||
|
ctx = bdrv_get_aio_context(bs);
|
||||||
|
aio_context_acquire(ctx);
|
||||||
bs->drv->bdrv_reopen_commit_post(&bs_entry->state);
|
bs->drv->bdrv_reopen_commit_post(&bs_entry->state);
|
||||||
|
aio_context_release(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4195,17 +4224,38 @@ abort:
|
|||||||
tran_abort(tran);
|
tran_abort(tran);
|
||||||
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
|
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
|
||||||
if (bs_entry->prepared) {
|
if (bs_entry->prepared) {
|
||||||
|
ctx = bdrv_get_aio_context(bs_entry->state.bs);
|
||||||
|
aio_context_acquire(ctx);
|
||||||
bdrv_reopen_abort(&bs_entry->state);
|
bdrv_reopen_abort(&bs_entry->state);
|
||||||
|
aio_context_release(ctx);
|
||||||
}
|
}
|
||||||
qobject_unref(bs_entry->state.explicit_options);
|
|
||||||
qobject_unref(bs_entry->state.options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
|
bdrv_reopen_queue_free(bs_queue);
|
||||||
g_free(bs_entry);
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bdrv_reopen(BlockDriverState *bs, QDict *opts, bool keep_old_opts,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||||
|
BlockReopenQueue *queue;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
bdrv_subtree_drained_begin(bs);
|
||||||
|
if (ctx != qemu_get_aio_context()) {
|
||||||
|
aio_context_release(ctx);
|
||||||
}
|
}
|
||||||
g_free(bs_queue);
|
|
||||||
|
queue = bdrv_reopen_queue(NULL, bs, opts, keep_old_opts);
|
||||||
|
ret = bdrv_reopen_multiple(queue, errp);
|
||||||
|
|
||||||
|
if (ctx != qemu_get_aio_context()) {
|
||||||
|
aio_context_acquire(ctx);
|
||||||
|
}
|
||||||
|
bdrv_subtree_drained_end(bs);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -4213,18 +4263,11 @@ cleanup:
|
|||||||
int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
|
int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
BlockReopenQueue *queue;
|
|
||||||
QDict *opts = qdict_new();
|
QDict *opts = qdict_new();
|
||||||
|
|
||||||
qdict_put_bool(opts, BDRV_OPT_READ_ONLY, read_only);
|
qdict_put_bool(opts, BDRV_OPT_READ_ONLY, read_only);
|
||||||
|
|
||||||
bdrv_subtree_drained_begin(bs);
|
return bdrv_reopen(bs, opts, true, errp);
|
||||||
queue = bdrv_reopen_queue(NULL, bs, opts, true);
|
|
||||||
ret = bdrv_reopen_multiple(queue, errp);
|
|
||||||
bdrv_subtree_drained_end(bs);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4573,6 +4616,8 @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
|
|||||||
/* set BDS specific flags now */
|
/* set BDS specific flags now */
|
||||||
qobject_unref(bs->explicit_options);
|
qobject_unref(bs->explicit_options);
|
||||||
qobject_unref(bs->options);
|
qobject_unref(bs->options);
|
||||||
|
qobject_ref(reopen_state->explicit_options);
|
||||||
|
qobject_ref(reopen_state->options);
|
||||||
|
|
||||||
bs->explicit_options = reopen_state->explicit_options;
|
bs->explicit_options = reopen_state->explicit_options;
|
||||||
bs->options = reopen_state->options;
|
bs->options = reopen_state->options;
|
||||||
@ -5074,7 +5119,7 @@ int coroutine_fn bdrv_co_check(BlockDriverState *bs,
|
|||||||
* -ENOTSUP - format driver doesn't support changing the backing file
|
* -ENOTSUP - format driver doesn't support changing the backing file
|
||||||
*/
|
*/
|
||||||
int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
|
int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
|
||||||
const char *backing_fmt, bool warn)
|
const char *backing_fmt, bool require)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
int ret;
|
int ret;
|
||||||
@ -5088,10 +5133,8 @@ int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (warn && backing_file && !backing_fmt) {
|
if (require && backing_file && !backing_fmt) {
|
||||||
warn_report("Deprecated use of backing file without explicit "
|
return -EINVAL;
|
||||||
"backing format, use of this image requires "
|
|
||||||
"potentially unsafe format probing");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drv->bdrv_change_backing_file != NULL) {
|
if (drv->bdrv_change_backing_file != NULL) {
|
||||||
@ -6601,24 +6644,11 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
|||||||
goto out;
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
if (!backing_fmt) {
|
if (!backing_fmt) {
|
||||||
warn_report("Deprecated use of backing file without explicit "
|
error_setg(&local_err,
|
||||||
"backing format (detected format of %s)",
|
"Backing file specified without backing format");
|
||||||
bs->drv->format_name);
|
error_append_hint(&local_err, "Detected format of %s.",
|
||||||
if (bs->drv != &bdrv_raw) {
|
bs->drv->format_name);
|
||||||
/*
|
goto out;
|
||||||
* A probe of raw deserves the most attention:
|
|
||||||
* leaving the backing format out of the image
|
|
||||||
* will ensure bs->probed is set (ensuring we
|
|
||||||
* don't accidentally commit into the backing
|
|
||||||
* file), and allow more spots to warn the users
|
|
||||||
* to fix their toolchain when opening this image
|
|
||||||
* later. For other images, we can safely record
|
|
||||||
* the format that we probed.
|
|
||||||
*/
|
|
||||||
backing_fmt = bs->drv->format_name;
|
|
||||||
qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, backing_fmt,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (size == -1) {
|
if (size == -1) {
|
||||||
/* Opened BS, have no size */
|
/* Opened BS, have no size */
|
||||||
@ -6635,9 +6665,9 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
|||||||
}
|
}
|
||||||
/* (backing_file && !(flags & BDRV_O_NO_BACKING)) */
|
/* (backing_file && !(flags & BDRV_O_NO_BACKING)) */
|
||||||
} else if (backing_file && !backing_fmt) {
|
} else if (backing_file && !backing_fmt) {
|
||||||
warn_report("Deprecated use of unopened backing file without "
|
error_setg(&local_err,
|
||||||
"explicit backing format, use of this image requires "
|
"Backing file specified without backing format");
|
||||||
"potentially unsafe format probing");
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size == -1) {
|
if (size == -1) {
|
||||||
|
@ -46,6 +46,12 @@ typedef struct FuseExport {
|
|||||||
char *mountpoint;
|
char *mountpoint;
|
||||||
bool writable;
|
bool writable;
|
||||||
bool growable;
|
bool growable;
|
||||||
|
/* Whether allow_other was used as a mount option or not */
|
||||||
|
bool allow_other;
|
||||||
|
|
||||||
|
mode_t st_mode;
|
||||||
|
uid_t st_uid;
|
||||||
|
gid_t st_gid;
|
||||||
} FuseExport;
|
} FuseExport;
|
||||||
|
|
||||||
static GHashTable *exports;
|
static GHashTable *exports;
|
||||||
@ -57,7 +63,7 @@ static void fuse_export_delete(BlockExport *exp);
|
|||||||
static void init_exports_table(void);
|
static void init_exports_table(void);
|
||||||
|
|
||||||
static int setup_fuse_export(FuseExport *exp, const char *mountpoint,
|
static int setup_fuse_export(FuseExport *exp, const char *mountpoint,
|
||||||
Error **errp);
|
bool allow_other, Error **errp);
|
||||||
static void read_from_fuse_export(void *opaque);
|
static void read_from_fuse_export(void *opaque);
|
||||||
|
|
||||||
static bool is_regular_file(const char *path, Error **errp);
|
static bool is_regular_file(const char *path, Error **errp);
|
||||||
@ -118,7 +124,29 @@ static int fuse_export_create(BlockExport *blk_exp,
|
|||||||
exp->writable = blk_exp_args->writable;
|
exp->writable = blk_exp_args->writable;
|
||||||
exp->growable = args->growable;
|
exp->growable = args->growable;
|
||||||
|
|
||||||
ret = setup_fuse_export(exp, args->mountpoint, errp);
|
/* set default */
|
||||||
|
if (!args->has_allow_other) {
|
||||||
|
args->allow_other = FUSE_EXPORT_ALLOW_OTHER_AUTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
exp->st_mode = S_IFREG | S_IRUSR;
|
||||||
|
if (exp->writable) {
|
||||||
|
exp->st_mode |= S_IWUSR;
|
||||||
|
}
|
||||||
|
exp->st_uid = getuid();
|
||||||
|
exp->st_gid = getgid();
|
||||||
|
|
||||||
|
if (args->allow_other == FUSE_EXPORT_ALLOW_OTHER_AUTO) {
|
||||||
|
/* Ignore errors on our first attempt */
|
||||||
|
ret = setup_fuse_export(exp, args->mountpoint, true, NULL);
|
||||||
|
exp->allow_other = ret == 0;
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = setup_fuse_export(exp, args->mountpoint, false, errp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
exp->allow_other = args->allow_other == FUSE_EXPORT_ALLOW_OTHER_ON;
|
||||||
|
ret = setup_fuse_export(exp, args->mountpoint, exp->allow_other, errp);
|
||||||
|
}
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@ -146,15 +174,20 @@ static void init_exports_table(void)
|
|||||||
* Create exp->fuse_session and mount it.
|
* Create exp->fuse_session and mount it.
|
||||||
*/
|
*/
|
||||||
static int setup_fuse_export(FuseExport *exp, const char *mountpoint,
|
static int setup_fuse_export(FuseExport *exp, const char *mountpoint,
|
||||||
Error **errp)
|
bool allow_other, Error **errp)
|
||||||
{
|
{
|
||||||
const char *fuse_argv[4];
|
const char *fuse_argv[4];
|
||||||
char *mount_opts;
|
char *mount_opts;
|
||||||
struct fuse_args fuse_args;
|
struct fuse_args fuse_args;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Needs to match what fuse_init() sets. Only max_read must be supplied. */
|
/*
|
||||||
mount_opts = g_strdup_printf("max_read=%zu", FUSE_MAX_BOUNCE_BYTES);
|
* max_read needs to match what fuse_init() sets.
|
||||||
|
* max_write need not be supplied.
|
||||||
|
*/
|
||||||
|
mount_opts = g_strdup_printf("max_read=%zu,default_permissions%s",
|
||||||
|
FUSE_MAX_BOUNCE_BYTES,
|
||||||
|
allow_other ? ",allow_other" : "");
|
||||||
|
|
||||||
fuse_argv[0] = ""; /* Dummy program name */
|
fuse_argv[0] = ""; /* Dummy program name */
|
||||||
fuse_argv[1] = "-o";
|
fuse_argv[1] = "-o";
|
||||||
@ -316,7 +349,6 @@ static void fuse_getattr(fuse_req_t req, fuse_ino_t inode,
|
|||||||
int64_t length, allocated_blocks;
|
int64_t length, allocated_blocks;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
FuseExport *exp = fuse_req_userdata(req);
|
FuseExport *exp = fuse_req_userdata(req);
|
||||||
mode_t mode;
|
|
||||||
|
|
||||||
length = blk_getlength(exp->common.blk);
|
length = blk_getlength(exp->common.blk);
|
||||||
if (length < 0) {
|
if (length < 0) {
|
||||||
@ -331,17 +363,12 @@ static void fuse_getattr(fuse_req_t req, fuse_ino_t inode,
|
|||||||
allocated_blocks = DIV_ROUND_UP(allocated_blocks, 512);
|
allocated_blocks = DIV_ROUND_UP(allocated_blocks, 512);
|
||||||
}
|
}
|
||||||
|
|
||||||
mode = S_IFREG | S_IRUSR;
|
|
||||||
if (exp->writable) {
|
|
||||||
mode |= S_IWUSR;
|
|
||||||
}
|
|
||||||
|
|
||||||
statbuf = (struct stat) {
|
statbuf = (struct stat) {
|
||||||
.st_ino = inode,
|
.st_ino = inode,
|
||||||
.st_mode = mode,
|
.st_mode = exp->st_mode,
|
||||||
.st_nlink = 1,
|
.st_nlink = 1,
|
||||||
.st_uid = getuid(),
|
.st_uid = exp->st_uid,
|
||||||
.st_gid = getgid(),
|
.st_gid = exp->st_gid,
|
||||||
.st_size = length,
|
.st_size = length,
|
||||||
.st_blksize = blk_bs(exp->common.blk)->bl.request_alignment,
|
.st_blksize = blk_bs(exp->common.blk)->bl.request_alignment,
|
||||||
.st_blocks = allocated_blocks,
|
.st_blocks = allocated_blocks,
|
||||||
@ -387,28 +414,76 @@ static int fuse_do_truncate(const FuseExport *exp, int64_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Let clients set file attributes. Only resizing is supported.
|
* Let clients set file attributes. Only resizing and changing
|
||||||
|
* permissions (st_mode, st_uid, st_gid) is allowed.
|
||||||
|
* Changing permissions is only allowed as far as it will actually
|
||||||
|
* permit access: Read-only exports cannot be given +w, and exports
|
||||||
|
* without allow_other cannot be given a different UID or GID, and
|
||||||
|
* they cannot be given non-owner access.
|
||||||
*/
|
*/
|
||||||
static void fuse_setattr(fuse_req_t req, fuse_ino_t inode, struct stat *statbuf,
|
static void fuse_setattr(fuse_req_t req, fuse_ino_t inode, struct stat *statbuf,
|
||||||
int to_set, struct fuse_file_info *fi)
|
int to_set, struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
FuseExport *exp = fuse_req_userdata(req);
|
FuseExport *exp = fuse_req_userdata(req);
|
||||||
|
int supported_attrs;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!exp->writable) {
|
supported_attrs = FUSE_SET_ATTR_SIZE | FUSE_SET_ATTR_MODE;
|
||||||
fuse_reply_err(req, EACCES);
|
if (exp->allow_other) {
|
||||||
return;
|
supported_attrs |= FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to_set & ~FUSE_SET_ATTR_SIZE) {
|
if (to_set & ~supported_attrs) {
|
||||||
fuse_reply_err(req, ENOTSUP);
|
fuse_reply_err(req, ENOTSUP);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = fuse_do_truncate(exp, statbuf->st_size, true, PREALLOC_MODE_OFF);
|
/* Do some argument checks first before committing to anything */
|
||||||
if (ret < 0) {
|
if (to_set & FUSE_SET_ATTR_MODE) {
|
||||||
fuse_reply_err(req, -ret);
|
/*
|
||||||
return;
|
* Without allow_other, non-owners can never access the export, so do
|
||||||
|
* not allow setting permissions for them
|
||||||
|
*/
|
||||||
|
if (!exp->allow_other &&
|
||||||
|
(statbuf->st_mode & (S_IRWXG | S_IRWXO)) != 0)
|
||||||
|
{
|
||||||
|
fuse_reply_err(req, EPERM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* +w for read-only exports makes no sense, disallow it */
|
||||||
|
if (!exp->writable &&
|
||||||
|
(statbuf->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
|
||||||
|
{
|
||||||
|
fuse_reply_err(req, EROFS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_set & FUSE_SET_ATTR_SIZE) {
|
||||||
|
if (!exp->writable) {
|
||||||
|
fuse_reply_err(req, EACCES);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fuse_do_truncate(exp, statbuf->st_size, true, PREALLOC_MODE_OFF);
|
||||||
|
if (ret < 0) {
|
||||||
|
fuse_reply_err(req, -ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_set & FUSE_SET_ATTR_MODE) {
|
||||||
|
/* Ignore FUSE-supplied file type, only change the mode */
|
||||||
|
exp->st_mode = (statbuf->st_mode & 07777) | S_IFREG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_set & FUSE_SET_ATTR_UID) {
|
||||||
|
exp->st_uid = statbuf->st_uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_set & FUSE_SET_ATTR_GID) {
|
||||||
|
exp->st_gid = statbuf->st_gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
fuse_getattr(req, inode, fi);
|
fuse_getattr(req, inode, fi);
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#if defined(HAVE_HOST_BLOCK_DEVICE)
|
#if defined(HAVE_HOST_BLOCK_DEVICE)
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
#include <IOKit/IOKitLib.h>
|
#include <IOKit/IOKitLib.h>
|
||||||
#include <IOKit/IOBSD.h>
|
#include <IOKit/IOBSD.h>
|
||||||
#include <IOKit/storage/IOMediaBSDClient.h>
|
#include <IOKit/storage/IOMediaBSDClient.h>
|
||||||
@ -1254,6 +1255,15 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__APPLE__) && (__MACH__)
|
||||||
|
struct statfs buf;
|
||||||
|
|
||||||
|
if (!fstatfs(s->fd, &buf)) {
|
||||||
|
bs->bl.opt_transfer = buf.f_iosize;
|
||||||
|
bs->bl.pdiscard_alignment = buf.f_bsize;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (bs->sg || S_ISBLK(st.st_mode)) {
|
if (bs->sg || S_ISBLK(st.st_mode)) {
|
||||||
int ret = hdev_get_max_hw_transfer(s->fd, &st);
|
int ret = hdev_get_max_hw_transfer(s->fd, &st);
|
||||||
|
|
||||||
@ -1591,6 +1601,7 @@ out:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_FALLOCATE) || defined(BLKZEROOUT) || defined(BLKDISCARD)
|
||||||
static int translate_err(int err)
|
static int translate_err(int err)
|
||||||
{
|
{
|
||||||
if (err == -ENODEV || err == -ENOSYS || err == -EOPNOTSUPP ||
|
if (err == -ENODEV || err == -ENOSYS || err == -EOPNOTSUPP ||
|
||||||
@ -1599,6 +1610,7 @@ static int translate_err(int err)
|
|||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_FALLOCATE
|
#ifdef CONFIG_FALLOCATE
|
||||||
static int do_fallocate(int fd, int mode, off_t offset, off_t len)
|
static int do_fallocate(int fd, int mode, off_t offset, off_t len)
|
||||||
@ -1811,16 +1823,27 @@ static int handle_aiocb_discard(void *opaque)
|
|||||||
}
|
}
|
||||||
} while (errno == EINTR);
|
} while (errno == EINTR);
|
||||||
|
|
||||||
ret = -errno;
|
ret = translate_err(-errno);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
|
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
|
||||||
ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
||||||
aiocb->aio_offset, aiocb->aio_nbytes);
|
aiocb->aio_offset, aiocb->aio_nbytes);
|
||||||
|
ret = translate_err(-errno);
|
||||||
|
#elif defined(__APPLE__) && (__MACH__)
|
||||||
|
fpunchhole_t fpunchhole;
|
||||||
|
fpunchhole.fp_flags = 0;
|
||||||
|
fpunchhole.reserved = 0;
|
||||||
|
fpunchhole.fp_offset = aiocb->aio_offset;
|
||||||
|
fpunchhole.fp_length = aiocb->aio_nbytes;
|
||||||
|
if (fcntl(s->fd, F_PUNCHHOLE, &fpunchhole) == -1) {
|
||||||
|
ret = errno == ENODEV ? -ENOTSUP : -errno;
|
||||||
|
} else {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = translate_err(ret);
|
|
||||||
if (ret == -ENOTSUP) {
|
if (ret == -ENOTSUP) {
|
||||||
s->has_discard = false;
|
s->has_discard = false;
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,8 @@ void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll)
|
|||||||
|
|
||||||
static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src)
|
static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src)
|
||||||
{
|
{
|
||||||
|
dst->pdiscard_alignment = MAX(dst->pdiscard_alignment,
|
||||||
|
src->pdiscard_alignment);
|
||||||
dst->opt_transfer = MAX(dst->opt_transfer, src->opt_transfer);
|
dst->opt_transfer = MAX(dst->opt_transfer, src->opt_transfer);
|
||||||
dst->max_transfer = MIN_NON_ZERO(dst->max_transfer, src->max_transfer);
|
dst->max_transfer = MIN_NON_ZERO(dst->max_transfer, src->max_transfer);
|
||||||
dst->max_hw_transfer = MIN_NON_ZERO(dst->max_hw_transfer,
|
dst->max_hw_transfer = MIN_NON_ZERO(dst->max_hw_transfer,
|
||||||
|
@ -68,3 +68,4 @@ static void iscsi_block_opts_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
block_init(iscsi_block_opts_init);
|
block_init(iscsi_block_opts_init);
|
||||||
|
module_opts("iscsi");
|
||||||
|
@ -66,7 +66,7 @@ block_ss.add(when: libiscsi, if_true: files('iscsi-opts.c'))
|
|||||||
block_ss.add(when: 'CONFIG_LINUX', if_true: files('nvme.c'))
|
block_ss.add(when: 'CONFIG_LINUX', if_true: files('nvme.c'))
|
||||||
block_ss.add(when: 'CONFIG_REPLICATION', if_true: files('replication.c'))
|
block_ss.add(when: 'CONFIG_REPLICATION', if_true: files('replication.c'))
|
||||||
block_ss.add(when: ['CONFIG_LINUX_AIO', libaio], if_true: files('linux-aio.c'))
|
block_ss.add(when: ['CONFIG_LINUX_AIO', libaio], if_true: files('linux-aio.c'))
|
||||||
block_ss.add(when: ['CONFIG_LINUX_IO_URING', linux_io_uring], if_true: files('io_uring.c'))
|
block_ss.add(when: linux_io_uring, if_true: files('io_uring.c'))
|
||||||
|
|
||||||
block_modules = {}
|
block_modules = {}
|
||||||
|
|
||||||
|
@ -147,9 +147,7 @@ out:
|
|||||||
if (qp) {
|
if (qp) {
|
||||||
query_params_free(qp);
|
query_params_free(qp);
|
||||||
}
|
}
|
||||||
if (uri) {
|
uri_free(uri);
|
||||||
uri_free(uri);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1926,6 +1926,7 @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||||||
static int qcow2_reopen_prepare(BDRVReopenState *state,
|
static int qcow2_reopen_prepare(BDRVReopenState *state,
|
||||||
BlockReopenQueue *queue, Error **errp)
|
BlockReopenQueue *queue, Error **errp)
|
||||||
{
|
{
|
||||||
|
BDRVQcow2State *s = state->bs->opaque;
|
||||||
Qcow2ReopenState *r;
|
Qcow2ReopenState *r;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -1956,6 +1957,16 @@ static int qcow2_reopen_prepare(BDRVReopenState *state,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Without an external data file, s->data_file points to the same BdrvChild
|
||||||
|
* as bs->file. It needs to be resynced after reopen because bs->file may
|
||||||
|
* be changed. We can't use it in the meantime.
|
||||||
|
*/
|
||||||
|
if (!has_data_file(state->bs)) {
|
||||||
|
assert(s->data_file == state->bs->file);
|
||||||
|
s->data_file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
@ -1966,7 +1977,16 @@ fail:
|
|||||||
|
|
||||||
static void qcow2_reopen_commit(BDRVReopenState *state)
|
static void qcow2_reopen_commit(BDRVReopenState *state)
|
||||||
{
|
{
|
||||||
|
BDRVQcow2State *s = state->bs->opaque;
|
||||||
|
|
||||||
qcow2_update_options_commit(state->bs, state->opaque);
|
qcow2_update_options_commit(state->bs, state->opaque);
|
||||||
|
if (!s->data_file) {
|
||||||
|
/*
|
||||||
|
* If we don't have an external data file, s->data_file was cleared by
|
||||||
|
* qcow2_reopen_prepare() and needs to be updated.
|
||||||
|
*/
|
||||||
|
s->data_file = state->bs->file;
|
||||||
|
}
|
||||||
g_free(state->opaque);
|
g_free(state->opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1990,6 +2010,15 @@ static void qcow2_reopen_commit_post(BDRVReopenState *state)
|
|||||||
|
|
||||||
static void qcow2_reopen_abort(BDRVReopenState *state)
|
static void qcow2_reopen_abort(BDRVReopenState *state)
|
||||||
{
|
{
|
||||||
|
BDRVQcow2State *s = state->bs->opaque;
|
||||||
|
|
||||||
|
if (!s->data_file) {
|
||||||
|
/*
|
||||||
|
* If we don't have an external data file, s->data_file was cleared by
|
||||||
|
* qcow2_reopen_prepare() and needs to be restored.
|
||||||
|
*/
|
||||||
|
s->data_file = state->bs->file;
|
||||||
|
}
|
||||||
qcow2_update_options_abort(state->bs, state->opaque);
|
qcow2_update_options_abort(state->bs, state->opaque);
|
||||||
g_free(state->opaque);
|
g_free(state->opaque);
|
||||||
}
|
}
|
||||||
@ -5620,15 +5649,10 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
|
|||||||
if (backing_file || backing_format) {
|
if (backing_file || backing_format) {
|
||||||
if (g_strcmp0(backing_file, s->image_backing_file) ||
|
if (g_strcmp0(backing_file, s->image_backing_file) ||
|
||||||
g_strcmp0(backing_format, s->image_backing_format)) {
|
g_strcmp0(backing_format, s->image_backing_format)) {
|
||||||
warn_report("Deprecated use of amend to alter the backing file; "
|
error_setg(errp, "Cannot amend the backing file");
|
||||||
"use qemu-img rebase instead");
|
error_append_hint(errp,
|
||||||
}
|
"You can use 'qemu-img rebase' instead.\n");
|
||||||
ret = qcow2_change_backing_file(bs,
|
return -EINVAL;
|
||||||
backing_file ?: s->image_backing_file,
|
|
||||||
backing_format ?: s->image_backing_format);
|
|
||||||
if (ret < 0) {
|
|
||||||
error_setg_errno(errp, -ret, "Failed to change the backing file");
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
779
block/rbd.c
779
block/rbd.c
@ -55,49 +55,30 @@
|
|||||||
* leading "\".
|
* leading "\".
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* rbd_aio_discard added in 0.1.2 */
|
|
||||||
#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 2)
|
|
||||||
#define LIBRBD_SUPPORTS_DISCARD
|
|
||||||
#else
|
|
||||||
#undef LIBRBD_SUPPORTS_DISCARD
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER)
|
#define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER)
|
||||||
|
|
||||||
#define RBD_MAX_SNAPS 100
|
#define RBD_MAX_SNAPS 100
|
||||||
|
|
||||||
/* The LIBRBD_SUPPORTS_IOVEC is defined in librbd.h */
|
#define RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN 8
|
||||||
#ifdef LIBRBD_SUPPORTS_IOVEC
|
|
||||||
#define LIBRBD_USE_IOVEC 1
|
static const char rbd_luks_header_verification[
|
||||||
#else
|
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
|
||||||
#define LIBRBD_USE_IOVEC 0
|
'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 1
|
||||||
#endif
|
};
|
||||||
|
|
||||||
|
static const char rbd_luks2_header_verification[
|
||||||
|
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
|
||||||
|
'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RBD_AIO_READ,
|
RBD_AIO_READ,
|
||||||
RBD_AIO_WRITE,
|
RBD_AIO_WRITE,
|
||||||
RBD_AIO_DISCARD,
|
RBD_AIO_DISCARD,
|
||||||
RBD_AIO_FLUSH
|
RBD_AIO_FLUSH,
|
||||||
|
RBD_AIO_WRITE_ZEROES
|
||||||
} RBDAIOCmd;
|
} RBDAIOCmd;
|
||||||
|
|
||||||
typedef struct RBDAIOCB {
|
|
||||||
BlockAIOCB common;
|
|
||||||
int64_t ret;
|
|
||||||
QEMUIOVector *qiov;
|
|
||||||
char *bounce;
|
|
||||||
RBDAIOCmd cmd;
|
|
||||||
int error;
|
|
||||||
struct BDRVRBDState *s;
|
|
||||||
} RBDAIOCB;
|
|
||||||
|
|
||||||
typedef struct RADOSCB {
|
|
||||||
RBDAIOCB *acb;
|
|
||||||
struct BDRVRBDState *s;
|
|
||||||
int64_t size;
|
|
||||||
char *buf;
|
|
||||||
int64_t ret;
|
|
||||||
} RADOSCB;
|
|
||||||
|
|
||||||
typedef struct BDRVRBDState {
|
typedef struct BDRVRBDState {
|
||||||
rados_t cluster;
|
rados_t cluster;
|
||||||
rados_ioctx_t io_ctx;
|
rados_ioctx_t io_ctx;
|
||||||
@ -106,8 +87,16 @@ typedef struct BDRVRBDState {
|
|||||||
char *snap;
|
char *snap;
|
||||||
char *namespace;
|
char *namespace;
|
||||||
uint64_t image_size;
|
uint64_t image_size;
|
||||||
|
uint64_t object_size;
|
||||||
} BDRVRBDState;
|
} BDRVRBDState;
|
||||||
|
|
||||||
|
typedef struct RBDTask {
|
||||||
|
BlockDriverState *bs;
|
||||||
|
Coroutine *co;
|
||||||
|
bool complete;
|
||||||
|
int64_t ret;
|
||||||
|
} RBDTask;
|
||||||
|
|
||||||
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
|
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
|
||||||
BlockdevOptionsRbd *opts, bool cache,
|
BlockdevOptionsRbd *opts, bool cache,
|
||||||
const char *keypairs, const char *secretid,
|
const char *keypairs, const char *secretid,
|
||||||
@ -251,14 +240,6 @@ done:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void qemu_rbd_refresh_limits(BlockDriverState *bs, Error **errp)
|
|
||||||
{
|
|
||||||
/* XXX Does RBD support AIO on less than 512-byte alignment? */
|
|
||||||
bs->bl.request_alignment = 512;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int qemu_rbd_set_auth(rados_t cluster, BlockdevOptionsRbd *opts,
|
static int qemu_rbd_set_auth(rados_t cluster, BlockdevOptionsRbd *opts,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
@ -340,17 +321,203 @@ static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs_json,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)
|
#ifdef LIBRBD_SUPPORTS_ENCRYPTION
|
||||||
|
static int qemu_rbd_convert_luks_options(
|
||||||
|
RbdEncryptionOptionsLUKSBase *luks_opts,
|
||||||
|
char **passphrase,
|
||||||
|
size_t *passphrase_len,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
if (LIBRBD_USE_IOVEC) {
|
return qcrypto_secret_lookup(luks_opts->key_secret, (uint8_t **)passphrase,
|
||||||
RBDAIOCB *acb = rcb->acb;
|
passphrase_len, errp);
|
||||||
iov_memset(acb->qiov->iov, acb->qiov->niov, offs, 0,
|
|
||||||
acb->qiov->size - offs);
|
|
||||||
} else {
|
|
||||||
memset(rcb->buf + offs, 0, rcb->size - offs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qemu_rbd_convert_luks_create_options(
|
||||||
|
RbdEncryptionCreateOptionsLUKSBase *luks_opts,
|
||||||
|
rbd_encryption_algorithm_t *alg,
|
||||||
|
char **passphrase,
|
||||||
|
size_t *passphrase_len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
r = qemu_rbd_convert_luks_options(
|
||||||
|
qapi_RbdEncryptionCreateOptionsLUKSBase_base(luks_opts),
|
||||||
|
passphrase, passphrase_len, errp);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luks_opts->has_cipher_alg) {
|
||||||
|
switch (luks_opts->cipher_alg) {
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_128: {
|
||||||
|
*alg = RBD_ENCRYPTION_ALGORITHM_AES128;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_256: {
|
||||||
|
*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
r = -ENOTSUP;
|
||||||
|
error_setg_errno(errp, -r, "unknown encryption algorithm: %u",
|
||||||
|
luks_opts->cipher_alg);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* default alg */
|
||||||
|
*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qemu_rbd_encryption_format(rbd_image_t image,
|
||||||
|
RbdEncryptionCreateOptions *encrypt,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
g_autofree char *passphrase = NULL;
|
||||||
|
size_t passphrase_len;
|
||||||
|
rbd_encryption_format_t format;
|
||||||
|
rbd_encryption_options_t opts;
|
||||||
|
rbd_encryption_luks1_format_options_t luks_opts;
|
||||||
|
rbd_encryption_luks2_format_options_t luks2_opts;
|
||||||
|
size_t opts_size;
|
||||||
|
uint64_t raw_size, effective_size;
|
||||||
|
|
||||||
|
r = rbd_get_size(image, &raw_size);
|
||||||
|
if (r < 0) {
|
||||||
|
error_setg_errno(errp, -r, "cannot get raw image size");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (encrypt->format) {
|
||||||
|
case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
|
||||||
|
memset(&luks_opts, 0, sizeof(luks_opts));
|
||||||
|
format = RBD_ENCRYPTION_FORMAT_LUKS1;
|
||||||
|
opts = &luks_opts;
|
||||||
|
opts_size = sizeof(luks_opts);
|
||||||
|
r = qemu_rbd_convert_luks_create_options(
|
||||||
|
qapi_RbdEncryptionCreateOptionsLUKS_base(&encrypt->u.luks),
|
||||||
|
&luks_opts.alg, &passphrase, &passphrase_len, errp);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
luks_opts.passphrase = passphrase;
|
||||||
|
luks_opts.passphrase_size = passphrase_len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
|
||||||
|
memset(&luks2_opts, 0, sizeof(luks2_opts));
|
||||||
|
format = RBD_ENCRYPTION_FORMAT_LUKS2;
|
||||||
|
opts = &luks2_opts;
|
||||||
|
opts_size = sizeof(luks2_opts);
|
||||||
|
r = qemu_rbd_convert_luks_create_options(
|
||||||
|
qapi_RbdEncryptionCreateOptionsLUKS2_base(
|
||||||
|
&encrypt->u.luks2),
|
||||||
|
&luks2_opts.alg, &passphrase, &passphrase_len, errp);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
luks2_opts.passphrase = passphrase;
|
||||||
|
luks2_opts.passphrase_size = passphrase_len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
r = -ENOTSUP;
|
||||||
|
error_setg_errno(
|
||||||
|
errp, -r, "unknown image encryption format: %u",
|
||||||
|
encrypt->format);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r = rbd_encryption_format(image, format, opts, opts_size);
|
||||||
|
if (r < 0) {
|
||||||
|
error_setg_errno(errp, -r, "encryption format fail");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = rbd_get_size(image, &effective_size);
|
||||||
|
if (r < 0) {
|
||||||
|
error_setg_errno(errp, -r, "cannot get effective image size");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = rbd_resize(image, raw_size + (raw_size - effective_size));
|
||||||
|
if (r < 0) {
|
||||||
|
error_setg_errno(errp, -r, "cannot resize image after format");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qemu_rbd_encryption_load(rbd_image_t image,
|
||||||
|
RbdEncryptionOptions *encrypt,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
g_autofree char *passphrase = NULL;
|
||||||
|
size_t passphrase_len;
|
||||||
|
rbd_encryption_luks1_format_options_t luks_opts;
|
||||||
|
rbd_encryption_luks2_format_options_t luks2_opts;
|
||||||
|
rbd_encryption_format_t format;
|
||||||
|
rbd_encryption_options_t opts;
|
||||||
|
size_t opts_size;
|
||||||
|
|
||||||
|
switch (encrypt->format) {
|
||||||
|
case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
|
||||||
|
memset(&luks_opts, 0, sizeof(luks_opts));
|
||||||
|
format = RBD_ENCRYPTION_FORMAT_LUKS1;
|
||||||
|
opts = &luks_opts;
|
||||||
|
opts_size = sizeof(luks_opts);
|
||||||
|
r = qemu_rbd_convert_luks_options(
|
||||||
|
qapi_RbdEncryptionOptionsLUKS_base(&encrypt->u.luks),
|
||||||
|
&passphrase, &passphrase_len, errp);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
luks_opts.passphrase = passphrase;
|
||||||
|
luks_opts.passphrase_size = passphrase_len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
|
||||||
|
memset(&luks2_opts, 0, sizeof(luks2_opts));
|
||||||
|
format = RBD_ENCRYPTION_FORMAT_LUKS2;
|
||||||
|
opts = &luks2_opts;
|
||||||
|
opts_size = sizeof(luks2_opts);
|
||||||
|
r = qemu_rbd_convert_luks_options(
|
||||||
|
qapi_RbdEncryptionOptionsLUKS2_base(&encrypt->u.luks2),
|
||||||
|
&passphrase, &passphrase_len, errp);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
luks2_opts.passphrase = passphrase;
|
||||||
|
luks2_opts.passphrase_size = passphrase_len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
r = -ENOTSUP;
|
||||||
|
error_setg_errno(
|
||||||
|
errp, -r, "unknown image encryption format: %u",
|
||||||
|
encrypt->format);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r = rbd_encryption_load(image, format, opts, opts_size);
|
||||||
|
if (r < 0) {
|
||||||
|
error_setg_errno(errp, -r, "encryption load fail");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* FIXME Deprecate and remove keypairs or make it available in QMP. */
|
/* FIXME Deprecate and remove keypairs or make it available in QMP. */
|
||||||
static int qemu_rbd_do_create(BlockdevCreateOptions *options,
|
static int qemu_rbd_do_create(BlockdevCreateOptions *options,
|
||||||
const char *keypairs, const char *password_secret,
|
const char *keypairs, const char *password_secret,
|
||||||
@ -368,6 +535,13 @@ static int qemu_rbd_do_create(BlockdevCreateOptions *options,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef LIBRBD_SUPPORTS_ENCRYPTION
|
||||||
|
if (opts->has_encrypt) {
|
||||||
|
error_setg(errp, "RBD library does not support image encryption");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (opts->has_cluster_size) {
|
if (opts->has_cluster_size) {
|
||||||
int64_t objsize = opts->cluster_size;
|
int64_t objsize = opts->cluster_size;
|
||||||
if ((objsize - 1) & objsize) { /* not a power of 2? */
|
if ((objsize - 1) & objsize) { /* not a power of 2? */
|
||||||
@ -393,6 +567,28 @@ static int qemu_rbd_do_create(BlockdevCreateOptions *options,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LIBRBD_SUPPORTS_ENCRYPTION
|
||||||
|
if (opts->has_encrypt) {
|
||||||
|
rbd_image_t image;
|
||||||
|
|
||||||
|
ret = rbd_open(io_ctx, opts->location->image, &image, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg_errno(errp, -ret,
|
||||||
|
"error opening image '%s' for encryption format",
|
||||||
|
opts->location->image);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = qemu_rbd_encryption_format(image, opts->encrypt, errp);
|
||||||
|
rbd_close(image);
|
||||||
|
if (ret < 0) {
|
||||||
|
/* encryption format fail, try removing the image */
|
||||||
|
rbd_remove(io_ctx, opts->location->image);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
rados_ioctx_destroy(io_ctx);
|
rados_ioctx_destroy(io_ctx);
|
||||||
@ -405,6 +601,43 @@ static int qemu_rbd_co_create(BlockdevCreateOptions *options, Error **errp)
|
|||||||
return qemu_rbd_do_create(options, NULL, NULL, errp);
|
return qemu_rbd_do_create(options, NULL, NULL, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qemu_rbd_extract_encryption_create_options(
|
||||||
|
QemuOpts *opts,
|
||||||
|
RbdEncryptionCreateOptions **spec,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QDict *opts_qdict;
|
||||||
|
QDict *encrypt_qdict;
|
||||||
|
Visitor *v;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
opts_qdict = qemu_opts_to_qdict(opts, NULL);
|
||||||
|
qdict_extract_subqdict(opts_qdict, &encrypt_qdict, "encrypt.");
|
||||||
|
qobject_unref(opts_qdict);
|
||||||
|
if (!qdict_size(encrypt_qdict)) {
|
||||||
|
*spec = NULL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert options into a QAPI object */
|
||||||
|
v = qobject_input_visitor_new_flat_confused(encrypt_qdict, errp);
|
||||||
|
if (!v) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
visit_type_RbdEncryptionCreateOptions(v, NULL, spec, errp);
|
||||||
|
visit_free(v);
|
||||||
|
if (!*spec) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
qobject_unref(encrypt_qdict);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int coroutine_fn qemu_rbd_co_create_opts(BlockDriver *drv,
|
static int coroutine_fn qemu_rbd_co_create_opts(BlockDriver *drv,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
QemuOpts *opts,
|
QemuOpts *opts,
|
||||||
@ -413,6 +646,7 @@ static int coroutine_fn qemu_rbd_co_create_opts(BlockDriver *drv,
|
|||||||
BlockdevCreateOptions *create_options;
|
BlockdevCreateOptions *create_options;
|
||||||
BlockdevCreateOptionsRbd *rbd_opts;
|
BlockdevCreateOptionsRbd *rbd_opts;
|
||||||
BlockdevOptionsRbd *loc;
|
BlockdevOptionsRbd *loc;
|
||||||
|
RbdEncryptionCreateOptions *encrypt = NULL;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
const char *keypairs, *password_secret;
|
const char *keypairs, *password_secret;
|
||||||
QDict *options = NULL;
|
QDict *options = NULL;
|
||||||
@ -441,6 +675,13 @@ static int coroutine_fn qemu_rbd_co_create_opts(BlockDriver *drv,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = qemu_rbd_extract_encryption_create_options(opts, &encrypt, errp);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
rbd_opts->encrypt = encrypt;
|
||||||
|
rbd_opts->has_encrypt = !!encrypt;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Caution: while qdict_get_try_str() is fine, getting non-string
|
* Caution: while qdict_get_try_str() is fine, getting non-string
|
||||||
* types would require more care. When @options come from -blockdev
|
* types would require more care. When @options come from -blockdev
|
||||||
@ -469,53 +710,6 @@ exit:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This aio completion is being called from rbd_finish_bh() and runs in qemu
|
|
||||||
* BH context.
|
|
||||||
*/
|
|
||||||
static void qemu_rbd_complete_aio(RADOSCB *rcb)
|
|
||||||
{
|
|
||||||
RBDAIOCB *acb = rcb->acb;
|
|
||||||
int64_t r;
|
|
||||||
|
|
||||||
r = rcb->ret;
|
|
||||||
|
|
||||||
if (acb->cmd != RBD_AIO_READ) {
|
|
||||||
if (r < 0) {
|
|
||||||
acb->ret = r;
|
|
||||||
acb->error = 1;
|
|
||||||
} else if (!acb->error) {
|
|
||||||
acb->ret = rcb->size;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (r < 0) {
|
|
||||||
qemu_rbd_memset(rcb, 0);
|
|
||||||
acb->ret = r;
|
|
||||||
acb->error = 1;
|
|
||||||
} else if (r < rcb->size) {
|
|
||||||
qemu_rbd_memset(rcb, r);
|
|
||||||
if (!acb->error) {
|
|
||||||
acb->ret = rcb->size;
|
|
||||||
}
|
|
||||||
} else if (!acb->error) {
|
|
||||||
acb->ret = r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free(rcb);
|
|
||||||
|
|
||||||
if (!LIBRBD_USE_IOVEC) {
|
|
||||||
if (acb->cmd == RBD_AIO_READ) {
|
|
||||||
qemu_iovec_from_buf(acb->qiov, 0, acb->bounce, acb->qiov->size);
|
|
||||||
}
|
|
||||||
qemu_vfree(acb->bounce);
|
|
||||||
}
|
|
||||||
|
|
||||||
acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
|
|
||||||
|
|
||||||
qemu_aio_unref(acb);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *qemu_rbd_mon_host(BlockdevOptionsRbd *opts, Error **errp)
|
static char *qemu_rbd_mon_host(BlockdevOptionsRbd *opts, Error **errp)
|
||||||
{
|
{
|
||||||
const char **vals;
|
const char **vals;
|
||||||
@ -702,6 +896,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
const QDictEntry *e;
|
const QDictEntry *e;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
char *keypairs, *secretid;
|
char *keypairs, *secretid;
|
||||||
|
rbd_image_info_t info;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
keypairs = g_strdup(qdict_get_try_str(options, "=keyvalue-pairs"));
|
keypairs = g_strdup(qdict_get_try_str(options, "=keyvalue-pairs"));
|
||||||
@ -766,30 +961,49 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto failed_open;
|
goto failed_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = rbd_get_size(s->image, &s->image_size);
|
if (opts->has_encrypt) {
|
||||||
if (r < 0) {
|
#ifdef LIBRBD_SUPPORTS_ENCRYPTION
|
||||||
error_setg_errno(errp, -r, "error getting image size from %s",
|
r = qemu_rbd_encryption_load(s->image, opts->encrypt, errp);
|
||||||
s->image_name);
|
if (r < 0) {
|
||||||
rbd_close(s->image);
|
goto failed_post_open;
|
||||||
goto failed_open;
|
}
|
||||||
|
#else
|
||||||
|
r = -ENOTSUP;
|
||||||
|
error_setg(errp, "RBD library does not support image encryption");
|
||||||
|
goto failed_post_open;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = rbd_stat(s->image, &info, sizeof(info));
|
||||||
|
if (r < 0) {
|
||||||
|
error_setg_errno(errp, -r, "error getting image info from %s",
|
||||||
|
s->image_name);
|
||||||
|
goto failed_post_open;
|
||||||
|
}
|
||||||
|
s->image_size = info.size;
|
||||||
|
s->object_size = info.obj_size;
|
||||||
|
|
||||||
/* If we are using an rbd snapshot, we must be r/o, otherwise
|
/* If we are using an rbd snapshot, we must be r/o, otherwise
|
||||||
* leave as-is */
|
* leave as-is */
|
||||||
if (s->snap != NULL) {
|
if (s->snap != NULL) {
|
||||||
r = bdrv_apply_auto_read_only(bs, "rbd snapshots are read-only", errp);
|
r = bdrv_apply_auto_read_only(bs, "rbd snapshots are read-only", errp);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
rbd_close(s->image);
|
goto failed_post_open;
|
||||||
goto failed_open;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LIBRBD_SUPPORTS_WRITE_ZEROES
|
||||||
|
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* When extending regular files, we get zeros from the OS */
|
/* When extending regular files, we get zeros from the OS */
|
||||||
bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
|
bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
|
||||||
|
|
||||||
r = 0;
|
r = 0;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
failed_post_open:
|
||||||
|
rbd_close(s->image);
|
||||||
failed_open:
|
failed_open:
|
||||||
rados_ioctx_destroy(s->io_ctx);
|
rados_ioctx_destroy(s->io_ctx);
|
||||||
g_free(s->snap);
|
g_free(s->snap);
|
||||||
@ -849,229 +1063,213 @@ static int qemu_rbd_resize(BlockDriverState *bs, uint64_t size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const AIOCBInfo rbd_aiocb_info = {
|
static void qemu_rbd_finish_bh(void *opaque)
|
||||||
.aiocb_size = sizeof(RBDAIOCB),
|
|
||||||
};
|
|
||||||
|
|
||||||
static void rbd_finish_bh(void *opaque)
|
|
||||||
{
|
{
|
||||||
RADOSCB *rcb = opaque;
|
RBDTask *task = opaque;
|
||||||
qemu_rbd_complete_aio(rcb);
|
task->complete = true;
|
||||||
|
aio_co_wake(task->co);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the callback function for rbd_aio_read and _write
|
* This is the completion callback function for all rbd aio calls
|
||||||
|
* started from qemu_rbd_start_co().
|
||||||
*
|
*
|
||||||
* Note: this function is being called from a non qemu thread so
|
* Note: this function is being called from a non qemu thread so
|
||||||
* we need to be careful about what we do here. Generally we only
|
* we need to be careful about what we do here. Generally we only
|
||||||
* schedule a BH, and do the rest of the io completion handling
|
* schedule a BH, and do the rest of the io completion handling
|
||||||
* from rbd_finish_bh() which runs in a qemu context.
|
* from qemu_rbd_finish_bh() which runs in a qemu context.
|
||||||
*/
|
*/
|
||||||
static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
|
static void qemu_rbd_completion_cb(rbd_completion_t c, RBDTask *task)
|
||||||
{
|
{
|
||||||
RBDAIOCB *acb = rcb->acb;
|
task->ret = rbd_aio_get_return_value(c);
|
||||||
|
|
||||||
rcb->ret = rbd_aio_get_return_value(c);
|
|
||||||
rbd_aio_release(c);
|
rbd_aio_release(c);
|
||||||
|
aio_bh_schedule_oneshot(bdrv_get_aio_context(task->bs),
|
||||||
replay_bh_schedule_oneshot_event(bdrv_get_aio_context(acb->common.bs),
|
qemu_rbd_finish_bh, task);
|
||||||
rbd_finish_bh, rcb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rbd_aio_discard_wrapper(rbd_image_t image,
|
static int coroutine_fn qemu_rbd_start_co(BlockDriverState *bs,
|
||||||
uint64_t off,
|
uint64_t offset,
|
||||||
uint64_t len,
|
uint64_t bytes,
|
||||||
rbd_completion_t comp)
|
QEMUIOVector *qiov,
|
||||||
|
int flags,
|
||||||
|
RBDAIOCmd cmd)
|
||||||
{
|
{
|
||||||
#ifdef LIBRBD_SUPPORTS_DISCARD
|
BDRVRBDState *s = bs->opaque;
|
||||||
return rbd_aio_discard(image, off, len, comp);
|
RBDTask task = { .bs = bs, .co = qemu_coroutine_self() };
|
||||||
#else
|
|
||||||
return -ENOTSUP;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rbd_aio_flush_wrapper(rbd_image_t image,
|
|
||||||
rbd_completion_t comp)
|
|
||||||
{
|
|
||||||
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
|
|
||||||
return rbd_aio_flush(image, comp);
|
|
||||||
#else
|
|
||||||
return -ENOTSUP;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
|
|
||||||
int64_t off,
|
|
||||||
QEMUIOVector *qiov,
|
|
||||||
int64_t size,
|
|
||||||
BlockCompletionFunc *cb,
|
|
||||||
void *opaque,
|
|
||||||
RBDAIOCmd cmd)
|
|
||||||
{
|
|
||||||
RBDAIOCB *acb;
|
|
||||||
RADOSCB *rcb = NULL;
|
|
||||||
rbd_completion_t c;
|
rbd_completion_t c;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
BDRVRBDState *s = bs->opaque;
|
assert(!qiov || qiov->size == bytes);
|
||||||
|
|
||||||
acb = qemu_aio_get(&rbd_aiocb_info, bs, cb, opaque);
|
r = rbd_aio_create_completion(&task,
|
||||||
acb->cmd = cmd;
|
(rbd_callback_t) qemu_rbd_completion_cb, &c);
|
||||||
acb->qiov = qiov;
|
|
||||||
assert(!qiov || qiov->size == size);
|
|
||||||
|
|
||||||
rcb = g_new(RADOSCB, 1);
|
|
||||||
|
|
||||||
if (!LIBRBD_USE_IOVEC) {
|
|
||||||
if (cmd == RBD_AIO_DISCARD || cmd == RBD_AIO_FLUSH) {
|
|
||||||
acb->bounce = NULL;
|
|
||||||
} else {
|
|
||||||
acb->bounce = qemu_try_blockalign(bs, qiov->size);
|
|
||||||
if (acb->bounce == NULL) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cmd == RBD_AIO_WRITE) {
|
|
||||||
qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
|
|
||||||
}
|
|
||||||
rcb->buf = acb->bounce;
|
|
||||||
}
|
|
||||||
|
|
||||||
acb->ret = 0;
|
|
||||||
acb->error = 0;
|
|
||||||
acb->s = s;
|
|
||||||
|
|
||||||
rcb->acb = acb;
|
|
||||||
rcb->s = acb->s;
|
|
||||||
rcb->size = size;
|
|
||||||
r = rbd_aio_create_completion(rcb, (rbd_callback_t) rbd_finish_aiocb, &c);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
goto failed;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case RBD_AIO_WRITE: {
|
|
||||||
/*
|
|
||||||
* RBD APIs don't allow us to write more than actual size, so in order
|
|
||||||
* to support growing images, we resize the image before write
|
|
||||||
* operations that exceed the current size.
|
|
||||||
*/
|
|
||||||
if (off + size > s->image_size) {
|
|
||||||
r = qemu_rbd_resize(bs, off + size);
|
|
||||||
if (r < 0) {
|
|
||||||
goto failed_completion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef LIBRBD_SUPPORTS_IOVEC
|
|
||||||
r = rbd_aio_writev(s->image, qiov->iov, qiov->niov, off, c);
|
|
||||||
#else
|
|
||||||
r = rbd_aio_write(s->image, off, size, rcb->buf, c);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RBD_AIO_READ:
|
case RBD_AIO_READ:
|
||||||
#ifdef LIBRBD_SUPPORTS_IOVEC
|
r = rbd_aio_readv(s->image, qiov->iov, qiov->niov, offset, c);
|
||||||
r = rbd_aio_readv(s->image, qiov->iov, qiov->niov, off, c);
|
break;
|
||||||
#else
|
case RBD_AIO_WRITE:
|
||||||
r = rbd_aio_read(s->image, off, size, rcb->buf, c);
|
r = rbd_aio_writev(s->image, qiov->iov, qiov->niov, offset, c);
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case RBD_AIO_DISCARD:
|
case RBD_AIO_DISCARD:
|
||||||
r = rbd_aio_discard_wrapper(s->image, off, size, c);
|
r = rbd_aio_discard(s->image, offset, bytes, c);
|
||||||
break;
|
break;
|
||||||
case RBD_AIO_FLUSH:
|
case RBD_AIO_FLUSH:
|
||||||
r = rbd_aio_flush_wrapper(s->image, c);
|
r = rbd_aio_flush(s->image, c);
|
||||||
break;
|
break;
|
||||||
|
#ifdef LIBRBD_SUPPORTS_WRITE_ZEROES
|
||||||
|
case RBD_AIO_WRITE_ZEROES: {
|
||||||
|
int zero_flags = 0;
|
||||||
|
#ifdef RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
|
||||||
|
if (!(flags & BDRV_REQ_MAY_UNMAP)) {
|
||||||
|
zero_flags = RBD_WRITE_ZEROES_FLAG_THICK_PROVISION;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
r = rbd_aio_write_zeroes(s->image, offset, bytes, c, zero_flags, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
r = -EINVAL;
|
r = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
goto failed_completion;
|
error_report("rbd request failed early: cmd %d offset %" PRIu64
|
||||||
}
|
" bytes %" PRIu64 " flags %d r %d (%s)", cmd, offset,
|
||||||
return &acb->common;
|
bytes, flags, r, strerror(-r));
|
||||||
|
rbd_aio_release(c);
|
||||||
failed_completion:
|
return r;
|
||||||
rbd_aio_release(c);
|
|
||||||
failed:
|
|
||||||
g_free(rcb);
|
|
||||||
if (!LIBRBD_USE_IOVEC) {
|
|
||||||
qemu_vfree(acb->bounce);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_aio_unref(acb);
|
while (!task.complete) {
|
||||||
return NULL;
|
qemu_coroutine_yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockAIOCB *qemu_rbd_aio_preadv(BlockDriverState *bs,
|
if (task.ret < 0) {
|
||||||
uint64_t offset, uint64_t bytes,
|
error_report("rbd request failed: cmd %d offset %" PRIu64 " bytes %"
|
||||||
QEMUIOVector *qiov, int flags,
|
PRIu64 " flags %d task.ret %" PRIi64 " (%s)", cmd, offset,
|
||||||
BlockCompletionFunc *cb,
|
bytes, flags, task.ret, strerror(-task.ret));
|
||||||
void *opaque)
|
return task.ret;
|
||||||
{
|
}
|
||||||
return rbd_start_aio(bs, offset, qiov, bytes, cb, opaque,
|
|
||||||
RBD_AIO_READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
static BlockAIOCB *qemu_rbd_aio_pwritev(BlockDriverState *bs,
|
/* zero pad short reads */
|
||||||
uint64_t offset, uint64_t bytes,
|
if (cmd == RBD_AIO_READ && task.ret < qiov->size) {
|
||||||
QEMUIOVector *qiov, int flags,
|
qemu_iovec_memset(qiov, task.ret, 0, qiov->size - task.ret);
|
||||||
BlockCompletionFunc *cb,
|
}
|
||||||
void *opaque)
|
|
||||||
{
|
|
||||||
return rbd_start_aio(bs, offset, qiov, bytes, cb, opaque,
|
|
||||||
RBD_AIO_WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
|
|
||||||
static BlockAIOCB *qemu_rbd_aio_flush(BlockDriverState *bs,
|
|
||||||
BlockCompletionFunc *cb,
|
|
||||||
void *opaque)
|
|
||||||
{
|
|
||||||
return rbd_start_aio(bs, 0, NULL, 0, cb, opaque, RBD_AIO_FLUSH);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static int qemu_rbd_co_flush(BlockDriverState *bs)
|
|
||||||
{
|
|
||||||
#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1)
|
|
||||||
/* rbd_flush added in 0.1.1 */
|
|
||||||
BDRVRBDState *s = bs->opaque;
|
|
||||||
return rbd_flush(s->image);
|
|
||||||
#else
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
coroutine_fn qemu_rbd_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||||
|
uint64_t bytes, QEMUIOVector *qiov,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
return qemu_rbd_start_co(bs, offset, bytes, qiov, flags, RBD_AIO_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
coroutine_fn qemu_rbd_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||||
|
uint64_t bytes, QEMUIOVector *qiov,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
BDRVRBDState *s = bs->opaque;
|
||||||
|
/*
|
||||||
|
* RBD APIs don't allow us to write more than actual size, so in order
|
||||||
|
* to support growing images, we resize the image before write
|
||||||
|
* operations that exceed the current size.
|
||||||
|
*/
|
||||||
|
if (offset + bytes > s->image_size) {
|
||||||
|
int r = qemu_rbd_resize(bs, offset + bytes);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return qemu_rbd_start_co(bs, offset, bytes, qiov, flags, RBD_AIO_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int coroutine_fn qemu_rbd_co_flush(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
return qemu_rbd_start_co(bs, 0, 0, NULL, 0, RBD_AIO_FLUSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int coroutine_fn qemu_rbd_co_pdiscard(BlockDriverState *bs,
|
||||||
|
int64_t offset, int count)
|
||||||
|
{
|
||||||
|
return qemu_rbd_start_co(bs, offset, count, NULL, 0, RBD_AIO_DISCARD);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LIBRBD_SUPPORTS_WRITE_ZEROES
|
||||||
|
static int
|
||||||
|
coroutine_fn qemu_rbd_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
||||||
|
int count, BdrvRequestFlags flags)
|
||||||
|
{
|
||||||
|
return qemu_rbd_start_co(bs, offset, count, NULL, flags,
|
||||||
|
RBD_AIO_WRITE_ZEROES);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
|
static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||||
{
|
{
|
||||||
BDRVRBDState *s = bs->opaque;
|
BDRVRBDState *s = bs->opaque;
|
||||||
rbd_image_info_t info;
|
bdi->cluster_size = s->object_size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
BDRVRBDState *s = bs->opaque;
|
||||||
|
ImageInfoSpecific *spec_info;
|
||||||
|
char buf[RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {0};
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = rbd_stat(s->image, &info, sizeof(info));
|
if (s->image_size >= RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) {
|
||||||
if (r < 0) {
|
r = rbd_read(s->image, 0,
|
||||||
return r;
|
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN, buf);
|
||||||
|
if (r < 0) {
|
||||||
|
error_setg_errno(errp, -r, "cannot read image start for probe");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bdi->cluster_size = info.obj_size;
|
spec_info = g_new(ImageInfoSpecific, 1);
|
||||||
return 0;
|
*spec_info = (ImageInfoSpecific){
|
||||||
|
.type = IMAGE_INFO_SPECIFIC_KIND_RBD,
|
||||||
|
.u.rbd.data = g_new0(ImageInfoSpecificRbd, 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (memcmp(buf, rbd_luks_header_verification,
|
||||||
|
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
|
||||||
|
spec_info->u.rbd.data->encryption_format =
|
||||||
|
RBD_IMAGE_ENCRYPTION_FORMAT_LUKS;
|
||||||
|
spec_info->u.rbd.data->has_encryption_format = true;
|
||||||
|
} else if (memcmp(buf, rbd_luks2_header_verification,
|
||||||
|
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
|
||||||
|
spec_info->u.rbd.data->encryption_format =
|
||||||
|
RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
|
||||||
|
spec_info->u.rbd.data->has_encryption_format = true;
|
||||||
|
} else {
|
||||||
|
spec_info->u.rbd.data->has_encryption_format = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return spec_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t qemu_rbd_getlength(BlockDriverState *bs)
|
static int64_t qemu_rbd_getlength(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVRBDState *s = bs->opaque;
|
BDRVRBDState *s = bs->opaque;
|
||||||
rbd_image_info_t info;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = rbd_stat(s->image, &info, sizeof(info));
|
r = rbd_get_size(s->image, &s->image_size);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return info.size;
|
return s->image_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs,
|
static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs,
|
||||||
@ -1210,19 +1408,6 @@ static int qemu_rbd_snap_list(BlockDriverState *bs,
|
|||||||
return snap_count;
|
return snap_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LIBRBD_SUPPORTS_DISCARD
|
|
||||||
static BlockAIOCB *qemu_rbd_aio_pdiscard(BlockDriverState *bs,
|
|
||||||
int64_t offset,
|
|
||||||
int bytes,
|
|
||||||
BlockCompletionFunc *cb,
|
|
||||||
void *opaque)
|
|
||||||
{
|
|
||||||
return rbd_start_aio(bs, offset, NULL, bytes, cb, opaque,
|
|
||||||
RBD_AIO_DISCARD);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef LIBRBD_SUPPORTS_INVALIDATE
|
|
||||||
static void coroutine_fn qemu_rbd_co_invalidate_cache(BlockDriverState *bs,
|
static void coroutine_fn qemu_rbd_co_invalidate_cache(BlockDriverState *bs,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
@ -1232,7 +1417,6 @@ static void coroutine_fn qemu_rbd_co_invalidate_cache(BlockDriverState *bs,
|
|||||||
error_setg_errno(errp, -r, "Failed to invalidate the cache");
|
error_setg_errno(errp, -r, "Failed to invalidate the cache");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static QemuOptsList qemu_rbd_create_opts = {
|
static QemuOptsList qemu_rbd_create_opts = {
|
||||||
.name = "rbd-create-opts",
|
.name = "rbd-create-opts",
|
||||||
@ -1253,6 +1437,22 @@ static QemuOptsList qemu_rbd_create_opts = {
|
|||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
.help = "ID of secret providing the password",
|
.help = "ID of secret providing the password",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "encrypt.format",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "Encrypt the image, format choices: 'luks', 'luks2'",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "encrypt.cipher-alg",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "Name of encryption cipher algorithm"
|
||||||
|
" (allowed values: aes-128, aes-256)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "encrypt.key-secret",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "ID of secret providing LUKS passphrase",
|
||||||
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1274,7 +1474,6 @@ static BlockDriver bdrv_rbd = {
|
|||||||
.format_name = "rbd",
|
.format_name = "rbd",
|
||||||
.instance_size = sizeof(BDRVRBDState),
|
.instance_size = sizeof(BDRVRBDState),
|
||||||
.bdrv_parse_filename = qemu_rbd_parse_filename,
|
.bdrv_parse_filename = qemu_rbd_parse_filename,
|
||||||
.bdrv_refresh_limits = qemu_rbd_refresh_limits,
|
|
||||||
.bdrv_file_open = qemu_rbd_open,
|
.bdrv_file_open = qemu_rbd_open,
|
||||||
.bdrv_close = qemu_rbd_close,
|
.bdrv_close = qemu_rbd_close,
|
||||||
.bdrv_reopen_prepare = qemu_rbd_reopen_prepare,
|
.bdrv_reopen_prepare = qemu_rbd_reopen_prepare,
|
||||||
@ -1282,31 +1481,25 @@ static BlockDriver bdrv_rbd = {
|
|||||||
.bdrv_co_create_opts = qemu_rbd_co_create_opts,
|
.bdrv_co_create_opts = qemu_rbd_co_create_opts,
|
||||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||||
.bdrv_get_info = qemu_rbd_getinfo,
|
.bdrv_get_info = qemu_rbd_getinfo,
|
||||||
|
.bdrv_get_specific_info = qemu_rbd_get_specific_info,
|
||||||
.create_opts = &qemu_rbd_create_opts,
|
.create_opts = &qemu_rbd_create_opts,
|
||||||
.bdrv_getlength = qemu_rbd_getlength,
|
.bdrv_getlength = qemu_rbd_getlength,
|
||||||
.bdrv_co_truncate = qemu_rbd_co_truncate,
|
.bdrv_co_truncate = qemu_rbd_co_truncate,
|
||||||
.protocol_name = "rbd",
|
.protocol_name = "rbd",
|
||||||
|
|
||||||
.bdrv_aio_preadv = qemu_rbd_aio_preadv,
|
.bdrv_co_preadv = qemu_rbd_co_preadv,
|
||||||
.bdrv_aio_pwritev = qemu_rbd_aio_pwritev,
|
.bdrv_co_pwritev = qemu_rbd_co_pwritev,
|
||||||
|
|
||||||
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
|
|
||||||
.bdrv_aio_flush = qemu_rbd_aio_flush,
|
|
||||||
#else
|
|
||||||
.bdrv_co_flush_to_disk = qemu_rbd_co_flush,
|
.bdrv_co_flush_to_disk = qemu_rbd_co_flush,
|
||||||
#endif
|
.bdrv_co_pdiscard = qemu_rbd_co_pdiscard,
|
||||||
|
#ifdef LIBRBD_SUPPORTS_WRITE_ZEROES
|
||||||
#ifdef LIBRBD_SUPPORTS_DISCARD
|
.bdrv_co_pwrite_zeroes = qemu_rbd_co_pwrite_zeroes,
|
||||||
.bdrv_aio_pdiscard = qemu_rbd_aio_pdiscard,
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
.bdrv_snapshot_create = qemu_rbd_snap_create,
|
.bdrv_snapshot_create = qemu_rbd_snap_create,
|
||||||
.bdrv_snapshot_delete = qemu_rbd_snap_remove,
|
.bdrv_snapshot_delete = qemu_rbd_snap_remove,
|
||||||
.bdrv_snapshot_list = qemu_rbd_snap_list,
|
.bdrv_snapshot_list = qemu_rbd_snap_list,
|
||||||
.bdrv_snapshot_goto = qemu_rbd_snap_rollback,
|
.bdrv_snapshot_goto = qemu_rbd_snap_rollback,
|
||||||
#ifdef LIBRBD_SUPPORTS_INVALIDATE
|
|
||||||
.bdrv_co_invalidate_cache = qemu_rbd_co_invalidate_cache,
|
.bdrv_co_invalidate_cache = qemu_rbd_co_invalidate_cache,
|
||||||
#endif
|
|
||||||
|
|
||||||
.strong_runtime_opts = qemu_rbd_strong_runtime_opts,
|
.strong_runtime_opts = qemu_rbd_strong_runtime_opts,
|
||||||
};
|
};
|
||||||
|
@ -390,7 +390,14 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (reopen_queue) {
|
if (reopen_queue) {
|
||||||
|
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||||
|
if (ctx != qemu_get_aio_context()) {
|
||||||
|
aio_context_release(ctx);
|
||||||
|
}
|
||||||
bdrv_reopen_multiple(reopen_queue, errp);
|
bdrv_reopen_multiple(reopen_queue, errp);
|
||||||
|
if (ctx != qemu_get_aio_context()) {
|
||||||
|
aio_context_acquire(ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_subtree_drained_end(s->hidden_disk->bs);
|
bdrv_subtree_drained_end(s->hidden_disk->bs);
|
||||||
|
@ -237,9 +237,7 @@ static int parse_uri(const char *filename, QDict *options, Error **errp)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
if (uri) {
|
uri_free(uri);
|
||||||
uri_free(uri);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
81
blockdev.c
81
blockdev.c
@ -1714,6 +1714,7 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
|
|||||||
aio_context = bdrv_get_aio_context(bs);
|
aio_context = bdrv_get_aio_context(bs);
|
||||||
aio_context_acquire(aio_context);
|
aio_context_acquire(aio_context);
|
||||||
|
|
||||||
|
state->bs = bs;
|
||||||
/* Paired with .clean() */
|
/* Paired with .clean() */
|
||||||
bdrv_drained_begin(bs);
|
bdrv_drained_begin(bs);
|
||||||
|
|
||||||
@ -1813,8 +1814,6 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state->bs = bs;
|
|
||||||
|
|
||||||
state->job = do_backup_common(qapi_DriveBackup_base(backup),
|
state->job = do_backup_common(qapi_DriveBackup_base(backup),
|
||||||
bs, target_bs, aio_context,
|
bs, target_bs, aio_context,
|
||||||
common->block_job_txn, errp);
|
common->block_job_txn, errp);
|
||||||
@ -3560,46 +3559,60 @@ fail:
|
|||||||
visit_free(v);
|
visit_free(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qmp_x_blockdev_reopen(BlockdevOptions *options, Error **errp)
|
void qmp_blockdev_reopen(BlockdevOptionsList *reopen_list, Error **errp)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs;
|
BlockReopenQueue *queue = NULL;
|
||||||
AioContext *ctx;
|
GSList *drained = NULL;
|
||||||
QObject *obj;
|
|
||||||
Visitor *v = qobject_output_visitor_new(&obj);
|
|
||||||
BlockReopenQueue *queue;
|
|
||||||
QDict *qdict;
|
|
||||||
|
|
||||||
/* Check for the selected node name */
|
/* Add each one of the BDS that we want to reopen to the queue */
|
||||||
if (!options->has_node_name) {
|
for (; reopen_list != NULL; reopen_list = reopen_list->next) {
|
||||||
error_setg(errp, "node-name not specified");
|
BlockdevOptions *options = reopen_list->value;
|
||||||
goto fail;
|
BlockDriverState *bs;
|
||||||
|
AioContext *ctx;
|
||||||
|
QObject *obj;
|
||||||
|
Visitor *v;
|
||||||
|
QDict *qdict;
|
||||||
|
|
||||||
|
/* Check for the selected node name */
|
||||||
|
if (!options->has_node_name) {
|
||||||
|
error_setg(errp, "node-name not specified");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
bs = bdrv_find_node(options->node_name);
|
||||||
|
if (!bs) {
|
||||||
|
error_setg(errp, "Failed to find node with node-name='%s'",
|
||||||
|
options->node_name);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Put all options in a QDict and flatten it */
|
||||||
|
v = qobject_output_visitor_new(&obj);
|
||||||
|
visit_type_BlockdevOptions(v, NULL, &options, &error_abort);
|
||||||
|
visit_complete(v, &obj);
|
||||||
|
visit_free(v);
|
||||||
|
|
||||||
|
qdict = qobject_to(QDict, obj);
|
||||||
|
|
||||||
|
qdict_flatten(qdict);
|
||||||
|
|
||||||
|
ctx = bdrv_get_aio_context(bs);
|
||||||
|
aio_context_acquire(ctx);
|
||||||
|
|
||||||
|
bdrv_subtree_drained_begin(bs);
|
||||||
|
queue = bdrv_reopen_queue(queue, bs, qdict, false);
|
||||||
|
drained = g_slist_prepend(drained, bs);
|
||||||
|
|
||||||
|
aio_context_release(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bs = bdrv_find_node(options->node_name);
|
|
||||||
if (!bs) {
|
|
||||||
error_setg(errp, "Failed to find node with node-name='%s'",
|
|
||||||
options->node_name);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Put all options in a QDict and flatten it */
|
|
||||||
visit_type_BlockdevOptions(v, NULL, &options, &error_abort);
|
|
||||||
visit_complete(v, &obj);
|
|
||||||
qdict = qobject_to(QDict, obj);
|
|
||||||
|
|
||||||
qdict_flatten(qdict);
|
|
||||||
|
|
||||||
/* Perform the reopen operation */
|
/* Perform the reopen operation */
|
||||||
ctx = bdrv_get_aio_context(bs);
|
|
||||||
aio_context_acquire(ctx);
|
|
||||||
bdrv_subtree_drained_begin(bs);
|
|
||||||
queue = bdrv_reopen_queue(NULL, bs, qdict, false);
|
|
||||||
bdrv_reopen_multiple(queue, errp);
|
bdrv_reopen_multiple(queue, errp);
|
||||||
bdrv_subtree_drained_end(bs);
|
queue = NULL;
|
||||||
aio_context_release(ctx);
|
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
visit_free(v);
|
bdrv_reopen_queue_free(queue);
|
||||||
|
g_slist_free_full(drained, (GDestroyNotify) bdrv_subtree_drained_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qmp_blockdev_del(const char *node_name, Error **errp)
|
void qmp_blockdev_del(const char *node_name, Error **errp)
|
||||||
|
@ -680,6 +680,7 @@ static const TypeInfo char_braille_type_info = {
|
|||||||
.instance_finalize = char_braille_finalize,
|
.instance_finalize = char_braille_finalize,
|
||||||
.class_init = char_braille_class_init,
|
.class_init = char_braille_class_init,
|
||||||
};
|
};
|
||||||
|
module_obj(TYPE_CHARDEV_BRAILLE);
|
||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
|
@ -366,6 +366,7 @@ static const TypeInfo char_spice_type_info = {
|
|||||||
.class_init = char_spice_class_init,
|
.class_init = char_spice_class_init,
|
||||||
.abstract = true,
|
.abstract = true,
|
||||||
};
|
};
|
||||||
|
module_obj(TYPE_CHARDEV_SPICE);
|
||||||
|
|
||||||
static void char_spicevmc_class_init(ObjectClass *oc, void *data)
|
static void char_spicevmc_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
@ -396,6 +397,7 @@ static const TypeInfo char_spiceport_type_info = {
|
|||||||
.parent = TYPE_CHARDEV_SPICE,
|
.parent = TYPE_CHARDEV_SPICE,
|
||||||
.class_init = char_spiceport_class_init,
|
.class_init = char_spiceport_class_init,
|
||||||
};
|
};
|
||||||
|
module_obj(TYPE_CHARDEV_SPICEPORT);
|
||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
@ -405,3 +407,5 @@ static void register_types(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
type_init(register_types);
|
type_init(register_types);
|
||||||
|
|
||||||
|
module_dep("ui-spice-core");
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Default configuration for aarch64-softmmu
|
# Default configuration for aarch64-softmmu
|
||||||
|
|
||||||
# We support all the 32 bit boards so need all their config
|
# We support all the 32 bit boards so need all their config
|
||||||
include arm-softmmu.mak
|
include ../arm-softmmu/default.mak
|
||||||
|
|
||||||
CONFIG_XLNX_ZYNQMP_ARM=y
|
CONFIG_XLNX_ZYNQMP_ARM=y
|
||||||
CONFIG_XLNX_VERSAL=y
|
CONFIG_XLNX_VERSAL=y
|
9
configs/devices/aarch64-softmmu/minimal.mak
Normal file
9
configs/devices/aarch64-softmmu/minimal.mak
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#
|
||||||
|
# A minimal version of the config that only supports only a few
|
||||||
|
# virtual machines. This avoids bringing in any of numerous legacy
|
||||||
|
# features from the 32bit platform (although virt still supports 32bit
|
||||||
|
# itself)
|
||||||
|
#
|
||||||
|
|
||||||
|
CONFIG_ARM_VIRT=y
|
||||||
|
CONFIG_SBSA_REF=y
|
@ -1,8 +1,5 @@
|
|||||||
# Default configuration for arm-softmmu
|
# Default configuration for arm-softmmu
|
||||||
|
|
||||||
# TODO: ARM_V7M is currently always required - make this more flexible!
|
|
||||||
CONFIG_ARM_V7M=y
|
|
||||||
|
|
||||||
# CONFIG_PCI_DEVICES=n
|
# CONFIG_PCI_DEVICES=n
|
||||||
# CONFIG_TEST_DEVICES=n
|
# CONFIG_TEST_DEVICES=n
|
||||||
|
|
||||||
@ -18,6 +15,7 @@ CONFIG_CHEETAH=y
|
|||||||
CONFIG_SX1=y
|
CONFIG_SX1=y
|
||||||
CONFIG_NSERIES=y
|
CONFIG_NSERIES=y
|
||||||
CONFIG_STELLARIS=y
|
CONFIG_STELLARIS=y
|
||||||
|
CONFIG_STM32VLDISCOVERY=y
|
||||||
CONFIG_REALVIEW=y
|
CONFIG_REALVIEW=y
|
||||||
CONFIG_VERSATILE=y
|
CONFIG_VERSATILE=y
|
||||||
CONFIG_VEXPRESS=y
|
CONFIG_VEXPRESS=y
|
@ -1,3 +1,3 @@
|
|||||||
# Default configuration for microblazeel-softmmu
|
# Default configuration for microblazeel-softmmu
|
||||||
|
|
||||||
include microblaze-softmmu.mak
|
include ../microblaze-softmmu/default.mak
|
@ -1,3 +1,3 @@
|
|||||||
# Default configuration for mips-softmmu
|
# Default configuration for mips-softmmu
|
||||||
|
|
||||||
include mips-softmmu-common.mak
|
include common.mak
|
@ -1,4 +1,4 @@
|
|||||||
# Default configuration for mips64-softmmu
|
# Default configuration for mips64-softmmu
|
||||||
|
|
||||||
include mips-softmmu-common.mak
|
include ../mips-softmmu/common.mak
|
||||||
CONFIG_JAZZ=y
|
CONFIG_JAZZ=y
|
@ -1,6 +1,6 @@
|
|||||||
# Default configuration for mips64el-softmmu
|
# Default configuration for mips64el-softmmu
|
||||||
|
|
||||||
include mips-softmmu-common.mak
|
include ../mips-softmmu/common.mak
|
||||||
CONFIG_IDE_VIA=y
|
CONFIG_IDE_VIA=y
|
||||||
CONFIG_FULOONG=y
|
CONFIG_FULOONG=y
|
||||||
CONFIG_LOONGSON3V=y
|
CONFIG_LOONGSON3V=y
|
@ -1,3 +1,3 @@
|
|||||||
# Default configuration for mipsel-softmmu
|
# Default configuration for mipsel-softmmu
|
||||||
|
|
||||||
include mips-softmmu-common.mak
|
include ../mips-softmmu/common.mak
|
@ -14,7 +14,7 @@ CONFIG_SAM460EX=y
|
|||||||
CONFIG_MAC_OLDWORLD=y
|
CONFIG_MAC_OLDWORLD=y
|
||||||
CONFIG_MAC_NEWWORLD=y
|
CONFIG_MAC_NEWWORLD=y
|
||||||
|
|
||||||
CONFIG_PEGASOS2=n
|
CONFIG_PEGASOS2=y
|
||||||
|
|
||||||
# For PReP
|
# For PReP
|
||||||
CONFIG_PREP=y
|
CONFIG_PREP=y
|
@ -1,7 +1,7 @@
|
|||||||
# Default configuration for ppc64-softmmu
|
# Default configuration for ppc64-softmmu
|
||||||
|
|
||||||
# Include all 32-bit boards
|
# Include all 32-bit boards
|
||||||
include ppc-softmmu.mak
|
include ../ppc-softmmu/default.mak
|
||||||
|
|
||||||
# For PowerNV
|
# For PowerNV
|
||||||
CONFIG_POWERNV=y
|
CONFIG_POWERNV=y
|
@ -1,3 +1,3 @@
|
|||||||
# Default configuration for sh4eb-softmmu
|
# Default configuration for sh4eb-softmmu
|
||||||
|
|
||||||
include sh4-softmmu.mak
|
include ../sh4-softmmu/default.mak
|
@ -1,3 +1,3 @@
|
|||||||
# Default configuration for x86_64-softmmu
|
# Default configuration for x86_64-softmmu
|
||||||
|
|
||||||
include i386-softmmu.mak
|
include ../i386-softmmu/default.mak
|
3
configs/devices/xtensaeb-softmmu/default.mak
Normal file
3
configs/devices/xtensaeb-softmmu/default.mak
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Default configuration for Xtensa
|
||||||
|
|
||||||
|
include ../xtensa-softmmu/default.mak
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user