|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [qemu-xen master] Merge remote-tracking branch 'remotes/berrange/tags/pull-qio-2016-10-27-1' into staging
=== This changeset includes merge from high-traffic branch ===
Commits on that branch are not reported individually.
commit 01b601f06154c0d35f945b1321ddb3f39530cc43
Merge: fd209e4a773dd5a7fea79eaaffd276ebcb99e92a
c3ff757d25115d6a530e8859d7287a862b1dc02d
Author: Peter Maydell <peter.maydell@xxxxxxxxxx>
AuthorDate: Fri Oct 28 15:30:55 2016 +0100
Commit: Peter Maydell <peter.maydell@xxxxxxxxxx>
CommitDate: Fri Oct 28 15:30:55 2016 +0100
Merge remote-tracking branch 'remotes/berrange/tags/pull-qio-2016-10-27-1'
into staging
Merge qio 2016/10/27 v1
# gpg: Signature made Thu 27 Oct 2016 13:54:03 BST
# gpg: using RSA key 0xBE86EBB415104FDF
# gpg: Good signature from "Daniel P. Berrange <dan@xxxxxxxxxxxx>"
# gpg: aka "Daniel P. Berrange <berrange@xxxxxxxxxx>"
# Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E 8E3F BE86 EBB4 1510
4FDF
* remotes/berrange/tags/pull-qio-2016-10-27-1:
main: set names for main loop sources created
vnc: set name for all I/O channels created
migration: set name for all I/O channels created
char: set name for all I/O channels created
nbd: set name for all I/O channels created
io: add ability to set a name for IO channels
io: Add a QIOChannelSocket cleanup test
io: set LISTEN flag explicitly for listen sockets
io: Introduce a qio_channel_set_feature() helper
io: Use qio_channel_has_feature() where applicable
io: Fix double shift usages on QIOChannel features
Conflicts:
qemu-char.c
Signed-off-by: Peter Maydell <peter.maydell@xxxxxxxxxx>
Makefile.objs | 3 +-
Makefile.target | 1 +
atomic_template.h | 215 ++++++
backends/baum.c | 5 +-
backends/msmouse.c | 7 +-
backends/rng-egd.c | 29 +-
backends/testdev.c | 5 +-
block/backup.c | 14 +-
block/block-backend.c | 94 ++-
block/dirty-bitmap.c | 160 +++-
block/io.c | 111 +--
block/iscsi.c | 89 ++-
block/mirror.c | 24 +-
block/nbd.c | 234 +++---
block/qapi.c | 5 +-
block/qcow2-cluster.c | 9 +-
block/qcow2.c | 3 +-
block/qcow2.h | 3 +-
block/quorum.c | 93 ++-
block/raw-posix.c | 17 +-
block/raw-win32.c | 1 +
block/raw_bsd.c | 9 +-
block/rbd.c | 4 +-
block/replication.c | 5 +
block/throttle-groups.c | 27 +-
block/trace-events | 1 -
blockdev.c | 4 +-
bsd-user/main.c | 2 +-
configure | 98 ++-
cpu-exec-common.c | 6 +
cpu-exec.c | 36 +-
cpus.c | 2 +
cputlb.c | 203 +++++-
default-configs/unicore32-linux-user.mak | 1 -
dma-helpers.c | 21 +-
docs/atomics.txt | 84 ++-
docs/qapi-code-gen.txt | 4 +-
docs/qmp-commands.txt | 84 +--
exec.c | 70 +-
gdbstub.c | 31 +-
hmp.c | 2 +-
hw/acpi/cpu.c | 5 +
hw/acpi/cpu_hotplug.c | 17 +-
hw/alpha/dp264.c | 2 +-
hw/arm/fsl-imx25.c | 2 +-
hw/arm/fsl-imx31.c | 2 +-
hw/arm/fsl-imx6.c | 2 +-
hw/arm/musicpal.c | 88 +--
hw/arm/omap2.c | 16 +-
hw/arm/pxa2xx.c | 19 +-
hw/arm/pxa2xx_gpio.c | 25 +-
hw/arm/strongarm.c | 37 +-
hw/arm/virt-acpi-build.c | 71 +-
hw/arm/virt.c | 6 +-
hw/audio/intel-hda.c | 3 +-
hw/block/fdc.c | 271 +++++--
hw/block/nvme.c | 6 +-
hw/bt/hci-csr.c | 13 +-
hw/char/bcm2835_aux.c | 18 +-
hw/char/cadence_uart.c | 30 +-
hw/char/debugcon.c | 8 +-
hw/char/digic-uart.c | 13 +-
hw/char/escc.c | 22 +-
hw/char/etraxfs_ser.c | 12 +-
hw/char/exynos4210_uart.c | 15 +-
hw/char/grlib_apbuart.c | 17 +-
hw/char/imx_serial.c | 29 +-
hw/char/ipoctal232.c | 23 +-
hw/char/lm32_juart.c | 15 +-
hw/char/lm32_uart.c | 17 +-
hw/char/mcf_uart.c | 20 +-
hw/char/milkymist-uart.c | 13 +-
hw/char/omap_uart.c | 4 +-
hw/char/parallel.c | 46 +-
hw/char/pl011.c | 19 +-
hw/char/sclpconsole-lm.c | 13 +-
hw/char/sclpconsole.c | 12 +-
hw/char/serial-isa.c | 7 +-
hw/char/serial.c | 39 +-
hw/char/sh_serial.c | 16 +-
hw/char/spapr_vty.c | 12 +-
hw/char/stm32f2xx_usart.c | 22 +-
hw/char/virtio-console.c | 29 +-
hw/char/xen_console.c | 43 +-
hw/char/xilinx_uartlite.c | 16 +-
hw/core/ptimer.c | 130 +++-
hw/core/qdev-properties-system.c | 80 +-
hw/display/pl110.c | 8 +-
hw/display/virtio-gpu.c | 1 +
hw/i2c/core.c | 39 +-
hw/i2c/smbus.c | 12 +-
hw/i386/acpi-build.c | 112 ++-
hw/i386/kvm/apic.c | 12 +-
hw/i386/pc.c | 84 ++-
hw/i386/pc_q35.c | 2 +
hw/i386/xen/xen_platform.c | 31 +-
hw/ide/ahci.c | 2 +
hw/ide/core.c | 6 +-
hw/ide/macio.c | 213 +-----
hw/intc/apic_common.c | 52 +-
hw/ipmi/ipmi_bmc_extern.c | 9 +-
hw/isa/pc87312.c | 4 +-
hw/mips/mips_fulong2e.c | 2 +-
hw/mips/mips_malta.c | 44 +-
hw/mips/mips_r4k.c | 2 +-
hw/misc/ivshmem.c | 23 +-
hw/net/e1000e_core.c | 8 +-
hw/net/eepro100.c | 1 +
hw/net/pcnet.c | 133 ++--
hw/net/rocker/rocker.c | 2 +-
hw/net/rtl8139.c | 2 +-
hw/net/vmxnet3.c | 1 +
hw/ppc/spapr.c | 2 +-
hw/scsi/scsi-disk.c | 2 +
hw/sparc64/sun4u.c | 2 +-
hw/ssi/xilinx_spips.c | 7 +-
hw/timer/a9gtimer.c | 14 +-
hw/timer/arm_mptimer.c | 149 ++--
hw/timer/stm32f2xx_timer.c | 2 +-
hw/usb/ccid-card-passthru.c | 21 +-
hw/usb/dev-serial.c | 31 +-
hw/usb/redirect.c | 22 +-
hw/usb/xen-usb.c | 4 +-
hw/virtio/vhost-user.c | 4 +-
hw/xtensa/xtfpga.c | 2 +-
include/block/block.h | 8 +-
include/block/block_int.h | 2 +
include/block/dirty-bitmap.h | 35 +-
include/exec/cpu-all.h | 10 +
include/exec/exec-all.h | 2 +-
include/exec/memory.h | 5 +-
include/hw/acpi/acpi-defs.h | 97 +++
include/hw/boards.h | 7 +
include/hw/char/bcm2835_aux.h | 2 +-
include/hw/char/cadence_uart.h | 2 +-
include/hw/char/digic-uart.h | 3 +-
include/hw/char/imx_serial.h | 3 +-
include/hw/char/serial.h | 6 +-
include/hw/char/stm32f2xx_usart.h | 2 +-
include/hw/i386/apic_internal.h | 3 +-
include/hw/i386/pc.h | 2 +
include/hw/ptimer.h | 20 +
include/hw/qdev-properties.h | 2 +-
include/hw/timer/arm_mptimer.h | 5 +-
include/qapi/qmp-input-visitor.h | 30 -
include/qapi/qmp-output-visitor.h | 30 -
include/qapi/qmp/qdict.h | 1 +
include/qapi/qobject-input-visitor.h | 30 +
include/qapi/qobject-output-visitor.h | 30 +
include/qapi/visitor.h | 6 +-
include/qemu-common.h | 13 +
include/qemu/atomic.h | 208 +++---
include/qemu/hbitmap.h | 100 +++
include/qemu/int128.h | 171 ++++-
include/qemu/typedefs.h | 1 +
include/qom/cpu.h | 4 +-
include/sysemu/block-backend.h | 1 +
include/sysemu/char.h | 230 +++---
include/sysemu/dma.h | 6 +-
include/sysemu/sysemu.h | 2 +-
kvm-all.c | 5 +-
linux-user/main.c | 341 ++-------
linux-user/mips/syscall_nr.h | 2 +-
linux-user/mips/termbits.h | 12 +
linux-user/mips64/termbits.h | 245 +------
linux-user/mmap.c | 14 +-
linux-user/sparc64/target_syscall.h | 7 +
linux-user/strace.c | 233 +++++-
linux-user/strace.list | 13 +-
linux-user/syscall.c | 364 ++++++++--
linux-user/syscall_defs.h | 111 ++-
memory.c | 95 +--
migration/ram.c | 4 +-
migration/savevm.c | 49 ++
monitor.c | 31 +-
net/colo-compare.c | 93 ++-
net/filter-mirror.c | 64 +-
net/filter-rewriter.c | 17 +-
net/slirp.c | 25 +-
net/tap-bsd.c | 6 +-
net/trace-events | 1 +
net/vhost-user.c | 49 +-
pc-bios/bios-256k.bin | Bin 262144 -> 262144 bytes
pc-bios/bios.bin | Bin 131072 -> 131072 bytes
pc-bios/vgabios-cirrus.bin | Bin 38400 -> 38400 bytes
pc-bios/vgabios-qxl.bin | Bin 38912 -> 38912 bytes
pc-bios/vgabios-stdvga.bin | Bin 38912 -> 38912 bytes
pc-bios/vgabios-virtio.bin | Bin 38912 -> 38912 bytes
pc-bios/vgabios-vmware.bin | Bin 38912 -> 38912 bytes
pc-bios/vgabios.bin | Bin 38400 -> 38400 bytes
qapi-schema.json | 1 +
qapi/Makefile.objs | 4 +-
qapi/block-core.json | 34 +-
qapi/qapi-clone-visitor.c | 2 +-
qapi/qapi-visit-core.c | 51 +-
qapi/qmp-input-visitor.c | 455 ------------
qapi/qmp-output-visitor.c | 256 -------
qapi/qobject-input-visitor.c | 457 ++++++++++++
qapi/qobject-output-visitor.c | 254 +++++++
qapi/trace-events | 33 +
qemu-char.c | 616 ++++++++++------
qemu-img.c | 12 +-
qemu-nbd.c | 17 +-
qemu-nbd.texi | 2 +
qmp.c | 4 +-
qobject/qdict.c | 277 +++++++
qom/cpu.c | 10 +-
qom/object_interfaces.c | 2 +-
qom/qom-qobject.c | 8 +-
qtest.c | 29 +-
roms/seabios | 2 +-
scripts/qapi-commands.py | 8 +-
scripts/qapi-event.py | 4 +-
scripts/tracetool/backend/simple.py | 3 +-
softmmu_template.h | 104 +--
spice-qemu-char.c | 19 +-
target-alpha/cpu.c | 15 +-
target-alpha/cpu.h | 22 +-
target-alpha/helper.c | 14 +-
target-alpha/helper.h | 9 -
target-alpha/machine.c | 2 -
target-alpha/mem_helper.c | 73 --
target-alpha/translate.c | 148 ++--
target-arm/cpu-qom.h | 2 +
target-arm/cpu.c | 69 +-
target-arm/cpu.h | 16 +-
target-arm/helper-a64.c | 113 +++
target-arm/helper-a64.h | 2 +
target-arm/helper.c | 11 +-
target-arm/internals.h | 4 +-
target-arm/translate-a64.c | 106 ++-
target-arm/translate.c | 397 +++++-----
target-arm/translate.h | 4 -
target-cris/cpu.c | 15 +-
target-i386/cpu-qom.h | 1 +
target-i386/cpu.c | 17 +-
target-i386/cpu.h | 1 +
target-i386/helper.h | 4 +-
target-i386/kvm.c | 13 +-
target-i386/kvm_i386.h | 1 +
target-i386/mem_helper.c | 153 ++--
target-i386/translate.c | 400 ++++++----
target-lm32/cpu.c | 15 +-
target-m68k/cpu.c | 82 ++-
target-m68k/cpu.h | 72 +-
target-m68k/helper.c | 319 ++++----
target-m68k/helper.h | 5 +-
target-m68k/op_helper.c | 35 +-
target-m68k/qregs.def | 6 +-
target-m68k/translate.c | 1028 +++++++++++++++-----------
target-microblaze/cpu.c | 14 +-
target-mips/cpu.c | 15 +-
target-moxie/cpu.c | 15 +-
target-openrisc/cpu.c | 15 +-
target-ppc/cpu-qom.h | 1 +
target-ppc/translate_init.c | 11 +-
target-s390x/cpu.c | 8 +-
target-s390x/cpu_models.c | 4 +-
target-sh4/cpu.c | 15 +-
target-sparc/cpu.c | 18 +-
target-tilegx/cpu.c | 15 +-
target-tricore/cpu.c | 15 +-
target-unicore32/cpu.c | 18 +-
target-xtensa/cpu.c | 15 +-
tcg-runtime.c | 74 +-
tcg/tcg-op.c | 354 ++++++++-
tcg/tcg-op.h | 44 ++
tcg/tcg-runtime.h | 109 +++
tcg/tcg.c | 56 +-
tcg/tcg.h | 85 +++
tests/.gitignore | 7 +-
tests/Makefile.include | 31 +-
tests/atomic_add-bench.c | 163 +++++
tests/check-qdict.c | 158 +++-
tests/check-qnull.c | 8 +-
tests/ptimer-test-stubs.c | 2 +-
tests/ptimer-test.c | 362 +++++++--
tests/ptimer-test.h | 2 +-
tests/qemu-iotests/041 | 11 +-
tests/qemu-iotests/051.out | 4 +-
tests/qemu-iotests/051.pc.out | 4 +-
tests/qemu-iotests/067 | 12 +-
tests/qemu-iotests/071 | 118 ++-
tests/qemu-iotests/081 | 52 +-
tests/qemu-iotests/085 | 9 +-
tests/qemu-iotests/087 | 76 +-
tests/qemu-iotests/093 | 33 +-
tests/qemu-iotests/093.out | 4 +-
tests/qemu-iotests/117 | 12 +-
tests/qemu-iotests/118 | 42 +-
tests/qemu-iotests/124 | 20 +-
tests/qemu-iotests/139 | 10 +-
tests/qemu-iotests/141 | 13 +-
tests/qemu-iotests/147 | 195 +++++
tests/qemu-iotests/147.out | 5 +
tests/qemu-iotests/155 | 10 +-
tests/qemu-iotests/162 | 22 +-
tests/qemu-iotests/162.out | 2 +-
tests/qemu-iotests/172 | 246 +++++++
tests/qemu-iotests/172.out | 1170 ++++++++++++++++++++++++++++++
tests/qemu-iotests/common.rc | 2 +-
tests/qemu-iotests/group | 2 +
tests/qemu-iotests/iotests.py | 34 +-
tests/qemu-iotests/socket_scm_helper.c | 29 +-
tests/qht-bench.c | 6 +-
tests/tcg/test-i386.c | 4 +-
tests/test-arm-mptimer.c | 1105 ++++++++++++++++++++++++++++
tests/test-char.c | 253 +++++++
tests/test-hbitmap.c | 272 +++++++
tests/test-int128.c | 22 +-
tests/test-qmp-commands.c | 4 +-
tests/test-qmp-input-strict.c | 381 ----------
tests/test-qmp-input-visitor.c | 911 -----------------------
tests/test-qmp-output-visitor.c | 876 ----------------------
tests/test-qobject-input-strict.c | 381 ++++++++++
tests/test-qobject-input-visitor.c | 899 +++++++++++++++++++++++
tests/test-qobject-output-visitor.c | 876 ++++++++++++++++++++++
tests/test-string-input-visitor.c | 2 +-
tests/test-string-output-visitor.c | 2 +-
tests/test-visitor-serialization.c | 8 +-
tests/vhost-user-test.c | 27 +-
translate-all.c | 72 +-
ui/console.c | 17 +-
ui/gtk.c | 6 -
util/hbitmap.c | 206 +++++-
util/qemu-sockets.c | 4 +-
util/qemu-thread-posix.c | 15 +-
util/qemu-thread-win32.c | 15 +-
util/rcu.c | 11 +-
vl.c | 26 +-
330 files changed, 15192 insertions(+), 7886 deletions(-)
diff --git a/Makefile.objs b/Makefile.objs
index 69fdd48..06f74b8 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -89,7 +89,7 @@ endif
#######################################################################
# Target-independent parts used in system and user emulation
-common-obj-y += tcg-runtime.o cpus-common.o
+common-obj-y += cpus-common.o
common-obj-y += hw/
common-obj-y += qom/
common-obj-y += disas/
@@ -162,3 +162,4 @@ trace-events-y += target-s390x/trace-events
trace-events-y += target-ppc/trace-events
trace-events-y += qom/trace-events
trace-events-y += linux-user/trace-events
+trace-events-y += qapi/trace-events
diff --git a/Makefile.target b/Makefile.target
index 2c46091..7a5080e 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -94,6 +94,7 @@ obj-$(CONFIG_TCG_INTERPRETER) += disas/tci.o
obj-y += fpu/softfloat.o
obj-y += target-$(TARGET_BASE_ARCH)/
obj-y += disas.o
+obj-y += tcg-runtime.o
obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
diff --git a/atomic_template.h b/atomic_template.h
new file mode 100644
index 0000000..b400b2a
--- /dev/null
+++ b/atomic_template.h
@@ -0,0 +1,215 @@
+/*
+ * Atomic helper templates
+ * Included from tcg-runtime.c and cputlb.c.
+ *
+ * Copyright (c) 2016 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if DATA_SIZE == 16
+# define SUFFIX o
+# define DATA_TYPE Int128
+# define BSWAP bswap128
+#elif DATA_SIZE == 8
+# define SUFFIX q
+# define DATA_TYPE uint64_t
+# define BSWAP bswap64
+#elif DATA_SIZE == 4
+# define SUFFIX l
+# define DATA_TYPE uint32_t
+# define BSWAP bswap32
+#elif DATA_SIZE == 2
+# define SUFFIX w
+# define DATA_TYPE uint16_t
+# define BSWAP bswap16
+#elif DATA_SIZE == 1
+# define SUFFIX b
+# define DATA_TYPE uint8_t
+# define BSWAP
+#else
+# error unsupported data size
+#endif
+
+#if DATA_SIZE >= 4
+# define ABI_TYPE DATA_TYPE
+#else
+# define ABI_TYPE uint32_t
+#endif
+
+/* Define host-endian atomic operations. Note that END is used within
+ the ATOMIC_NAME macro, and redefined below. */
+#if DATA_SIZE == 1
+# define END
+#elif defined(HOST_WORDS_BIGENDIAN)
+# define END _be
+#else
+# define END _le
+#endif
+
+ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
+ ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
+{
+ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
+ return atomic_cmpxchg__nocheck(haddr, cmpv, newv);
+}
+
+#if DATA_SIZE >= 16
+ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
+{
+ DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
+ __atomic_load(haddr, &val, __ATOMIC_RELAXED);
+ return val;
+}
+
+void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
+ ABI_TYPE val EXTRA_ARGS)
+{
+ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
+ __atomic_store(haddr, &val, __ATOMIC_RELAXED);
+}
+#else
+ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
+ ABI_TYPE val EXTRA_ARGS)
+{
+ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
+ return atomic_xchg__nocheck(haddr, val);
+}
+
+#define GEN_ATOMIC_HELPER(X) \
+ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
+ ABI_TYPE val EXTRA_ARGS) \
+{ \
+ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
+ return atomic_##X(haddr, val); \
+} \
+
+GEN_ATOMIC_HELPER(fetch_add)
+GEN_ATOMIC_HELPER(fetch_and)
+GEN_ATOMIC_HELPER(fetch_or)
+GEN_ATOMIC_HELPER(fetch_xor)
+GEN_ATOMIC_HELPER(add_fetch)
+GEN_ATOMIC_HELPER(and_fetch)
+GEN_ATOMIC_HELPER(or_fetch)
+GEN_ATOMIC_HELPER(xor_fetch)
+
+#undef GEN_ATOMIC_HELPER
+#endif /* DATA SIZE >= 16 */
+
+#undef END
+
+#if DATA_SIZE > 1
+
+/* Define reverse-host-endian atomic operations. Note that END is used
+ within the ATOMIC_NAME macro. */
+#ifdef HOST_WORDS_BIGENDIAN
+# define END _le
+#else
+# define END _be
+#endif
+
+ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
+ ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
+{
+ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
+ return BSWAP(atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)));
+}
+
+#if DATA_SIZE >= 16
+ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
+{
+ DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
+ __atomic_load(haddr, &val, __ATOMIC_RELAXED);
+ return BSWAP(val);
+}
+
+void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
+ ABI_TYPE val EXTRA_ARGS)
+{
+ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
+ val = BSWAP(val);
+ __atomic_store(haddr, &val, __ATOMIC_RELAXED);
+}
+#else
+ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
+ ABI_TYPE val EXTRA_ARGS)
+{
+ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
+ return BSWAP(atomic_xchg__nocheck(haddr, BSWAP(val)));
+}
+
+#define GEN_ATOMIC_HELPER(X) \
+ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
+ ABI_TYPE val EXTRA_ARGS) \
+{ \
+ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
+ return BSWAP(atomic_##X(haddr, BSWAP(val))); \
+}
+
+GEN_ATOMIC_HELPER(fetch_and)
+GEN_ATOMIC_HELPER(fetch_or)
+GEN_ATOMIC_HELPER(fetch_xor)
+GEN_ATOMIC_HELPER(and_fetch)
+GEN_ATOMIC_HELPER(or_fetch)
+GEN_ATOMIC_HELPER(xor_fetch)
+
+#undef GEN_ATOMIC_HELPER
+
+/* Note that for addition, we need to use a separate cmpxchg loop instead
+ of bswaps for the reverse-host-endian helpers. */
+ABI_TYPE ATOMIC_NAME(fetch_add)(CPUArchState *env, target_ulong addr,
+ ABI_TYPE val EXTRA_ARGS)
+{
+ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
+ DATA_TYPE ldo, ldn, ret, sto;
+
+ ldo = atomic_read__nocheck(haddr);
+ while (1) {
+ ret = BSWAP(ldo);
+ sto = BSWAP(ret + val);
+ ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto);
+ if (ldn == ldo) {
+ return ret;
+ }
+ ldo = ldn;
+ }
+}
+
+ABI_TYPE ATOMIC_NAME(add_fetch)(CPUArchState *env, target_ulong addr,
+ ABI_TYPE val EXTRA_ARGS)
+{
+ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
+ DATA_TYPE ldo, ldn, ret, sto;
+
+ ldo = atomic_read__nocheck(haddr);
+ while (1) {
+ ret = BSWAP(ldo) + val;
+ sto = BSWAP(ret);
+ ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto);
+ if (ldn == ldo) {
+ return ret;
+ }
+ ldo = ldn;
+ }
+}
+#endif /* DATA_SIZE >= 16 */
+
+#undef END
+#endif /* DATA_SIZE > 1 */
+
+#undef BSWAP
+#undef ABI_TYPE
+#undef DATA_TYPE
+#undef SUFFIX
+#undef DATA_SIZE
diff --git a/backends/baum.c b/backends/baum.c
index c537141..919844e 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -551,7 +551,7 @@ static void baum_chr_read(void *opaque)
}
}
-static void baum_close(struct CharDriverState *chr)
+static void baum_free(struct CharDriverState *chr)
{
BaumDriverState *baum = chr->opaque;
@@ -566,6 +566,7 @@ static void baum_close(struct CharDriverState *chr)
static CharDriverState *chr_baum_init(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
ChardevCommon *common = backend->u.braille.data;
@@ -589,7 +590,7 @@ static CharDriverState *chr_baum_init(const char *id,
chr->opaque = baum;
chr->chr_write = baum_write;
chr->chr_accept_input = baum_accept_input;
- chr->chr_close = baum_close;
+ chr->chr_free = baum_free;
handle = g_malloc0(brlapi_getHandleSize());
baum->brlapi = handle;
diff --git a/backends/msmouse.c b/backends/msmouse.c
index 85d08f7..733ca80 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -133,7 +133,7 @@ static int msmouse_chr_write (struct CharDriverState *s,
const uint8_t *buf, int
return len;
}
-static void msmouse_chr_close (struct CharDriverState *chr)
+static void msmouse_chr_free(struct CharDriverState *chr)
{
MouseState *mouse = chr->opaque;
@@ -151,6 +151,7 @@ static QemuInputHandler msmouse_handler = {
static CharDriverState *qemu_chr_open_msmouse(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
ChardevCommon *common = backend->u.msmouse.data;
@@ -162,9 +163,9 @@ static CharDriverState *qemu_chr_open_msmouse(const char
*id,
return NULL;
}
chr->chr_write = msmouse_chr_write;
- chr->chr_close = msmouse_chr_close;
+ chr->chr_free = msmouse_chr_free;
chr->chr_accept_input = msmouse_chr_accept_input;
- chr->explicit_be_open = true;
+ *be_opened = false;
mouse = g_new0(MouseState, 1);
mouse->hs = qemu_input_handler_register((DeviceState *)mouse,
diff --git a/backends/rng-egd.c b/backends/rng-egd.c
index ba17c07..69c04b1 100644
--- a/backends/rng-egd.c
+++ b/backends/rng-egd.c
@@ -15,7 +15,6 @@
#include "sysemu/char.h"
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
-#include "hw/qdev.h" /* just for DEFINE_PROP_CHR */
#define TYPE_RNG_EGD "rng-egd"
#define RNG_EGD(obj) OBJECT_CHECK(RngEgd, (obj), TYPE_RNG_EGD)
@@ -24,7 +23,7 @@ typedef struct RngEgd
{
RngBackend parent;
- CharDriverState *chr;
+ CharBackend chr;
char *chr_name;
} RngEgd;
@@ -43,7 +42,7 @@ static void rng_egd_request_entropy(RngBackend *b, RngRequest
*req)
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(s->chr, header, sizeof(header));
+ qemu_chr_fe_write_all(&s->chr, header, sizeof(header));
size -= len;
}
@@ -87,6 +86,7 @@ static void rng_egd_chr_read(void *opaque, const uint8_t
*buf, int size)
static void rng_egd_opened(RngBackend *b, Error **errp)
{
RngEgd *s = RNG_EGD(b);
+ CharDriverState *chr;
if (s->chr_name == NULL) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
@@ -94,21 +94,19 @@ static void rng_egd_opened(RngBackend *b, Error **errp)
return;
}
- s->chr = qemu_chr_find(s->chr_name);
- if (s->chr == NULL) {
+ chr = qemu_chr_find(s->chr_name);
+ if (chr == NULL) {
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
"Device '%s' not found", s->chr_name);
return;
}
-
- if (qemu_chr_fe_claim(s->chr) != 0) {
- error_setg(errp, QERR_DEVICE_IN_USE, s->chr_name);
+ if (!qemu_chr_fe_init(&s->chr, chr, errp)) {
return;
}
/* FIXME we should resubmit pending requests when the CDS reconnects. */
- qemu_chr_add_handlers(s->chr, rng_egd_chr_can_read, rng_egd_chr_read,
- NULL, s);
+ qemu_chr_fe_set_handlers(&s->chr, rng_egd_chr_can_read,
+ rng_egd_chr_read, NULL, s, NULL, true);
}
static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
@@ -127,9 +125,10 @@ static void rng_egd_set_chardev(Object *obj, const char
*value, Error **errp)
static char *rng_egd_get_chardev(Object *obj, Error **errp)
{
RngEgd *s = RNG_EGD(obj);
+ CharDriverState *chr = qemu_chr_fe_get_driver(&s->chr);
- if (s->chr && s->chr->label) {
- return g_strdup(s->chr->label);
+ if (chr && chr->label) {
+ return g_strdup(chr->label);
}
return NULL;
@@ -146,11 +145,7 @@ static void rng_egd_finalize(Object *obj)
{
RngEgd *s = RNG_EGD(obj);
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
- qemu_chr_fe_release(s->chr);
- }
-
+ qemu_chr_fe_deinit(&s->chr);
g_free(s->chr_name);
}
diff --git a/backends/testdev.c b/backends/testdev.c
index 3ab1c90..60156e3 100644
--- a/backends/testdev.c
+++ b/backends/testdev.c
@@ -102,7 +102,7 @@ static int testdev_write(CharDriverState *chr, const
uint8_t *buf, int len)
return orig_len;
}
-static void testdev_close(struct CharDriverState *chr)
+static void testdev_free(struct CharDriverState *chr)
{
TestdevCharState *testdev = chr->opaque;
@@ -112,6 +112,7 @@ static void testdev_close(struct CharDriverState *chr)
static CharDriverState *chr_testdev_init(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
TestdevCharState *testdev;
@@ -122,7 +123,7 @@ static CharDriverState *chr_testdev_init(const char *id,
chr->opaque = testdev;
chr->chr_write = testdev_write;
- chr->chr_close = testdev_close;
+ chr->chr_free = testdev_free;
return chr;
}
diff --git a/block/backup.c b/block/backup.c
index 582bd0f..02dbe48 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -372,14 +372,14 @@ static int coroutine_fn
backup_run_incremental(BackupBlockJob *job)
int64_t end;
int64_t last_cluster = -1;
int64_t sectors_per_cluster = cluster_size_sectors(job);
- HBitmapIter hbi;
+ BdrvDirtyBitmapIter *dbi;
granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap);
clusters_per_iter = MAX((granularity / job->cluster_size), 1);
- bdrv_dirty_iter_init(job->sync_bitmap, &hbi);
+ dbi = bdrv_dirty_iter_new(job->sync_bitmap, 0);
/* Find the next dirty sector(s) */
- while ((sector = hbitmap_iter_next(&hbi)) != -1) {
+ while ((sector = bdrv_dirty_iter_next(dbi)) != -1) {
cluster = sector / sectors_per_cluster;
/* Fake progress updates for any clusters we skipped */
@@ -391,7 +391,7 @@ static int coroutine_fn
backup_run_incremental(BackupBlockJob *job)
for (end = cluster + clusters_per_iter; cluster < end; cluster++) {
do {
if (yield_and_check(job)) {
- return ret;
+ goto out;
}
ret = backup_do_cow(job, cluster * sectors_per_cluster,
sectors_per_cluster, &error_is_read,
@@ -399,7 +399,7 @@ static int coroutine_fn
backup_run_incremental(BackupBlockJob *job)
if ((ret < 0) &&
backup_error_action(job, error_is_read, -ret) ==
BLOCK_ERROR_ACTION_REPORT) {
- return ret;
+ goto out;
}
} while (ret < 0);
}
@@ -407,7 +407,7 @@ static int coroutine_fn
backup_run_incremental(BackupBlockJob *job)
/* If the bitmap granularity is smaller than the backup granularity,
* we need to advance the iterator pointer to the next cluster. */
if (granularity < job->cluster_size) {
- bdrv_set_dirty_iter(&hbi, cluster * sectors_per_cluster);
+ bdrv_set_dirty_iter(dbi, cluster * sectors_per_cluster);
}
last_cluster = cluster - 1;
@@ -419,6 +419,8 @@ static int coroutine_fn
backup_run_incremental(BackupBlockJob *job)
job->common.offset += ((end - last_cluster - 1) * job->cluster_size);
}
+out:
+ bdrv_dirty_iter_free(dbi);
return ret;
}
diff --git a/block/block-backend.c b/block/block-backend.c
index 1a724a8..c53ca30 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1099,26 +1099,36 @@ BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t
offset,
blk_aio_write_entry, flags, cb, opaque);
}
+static void blk_aio_flush_entry(void *opaque)
+{
+ BlkAioEmAIOCB *acb = opaque;
+ BlkRwCo *rwco = &acb->rwco;
+
+ rwco->ret = blk_co_flush(rwco->blk);
+ blk_aio_complete(acb);
+}
+
BlockAIOCB *blk_aio_flush(BlockBackend *blk,
BlockCompletionFunc *cb, void *opaque)
{
- if (!blk_is_available(blk)) {
- return blk_abort_aio_request(blk, cb, opaque, -ENOMEDIUM);
- }
+ return blk_aio_prwv(blk, 0, 0, NULL, blk_aio_flush_entry, 0, cb, opaque);
+}
+
+static void blk_aio_pdiscard_entry(void *opaque)
+{
+ BlkAioEmAIOCB *acb = opaque;
+ BlkRwCo *rwco = &acb->rwco;
- return bdrv_aio_flush(blk_bs(blk), cb, opaque);
+ rwco->ret = blk_co_pdiscard(rwco->blk, rwco->offset, acb->bytes);
+ blk_aio_complete(acb);
}
BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk,
int64_t offset, int count,
BlockCompletionFunc *cb, void *opaque)
{
- int ret = blk_check_byte_request(blk, offset, count);
- if (ret < 0) {
- return blk_abort_aio_request(blk, cb, opaque, ret);
- }
-
- return bdrv_aio_pdiscard(blk_bs(blk), offset, count, cb, opaque);
+ return blk_aio_prwv(blk, offset, count, NULL, blk_aio_pdiscard_entry, 0,
+ cb, opaque);
}
void blk_aio_cancel(BlockAIOCB *acb)
@@ -1131,23 +1141,50 @@ void blk_aio_cancel_async(BlockAIOCB *acb)
bdrv_aio_cancel_async(acb);
}
-int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
+int blk_co_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
{
if (!blk_is_available(blk)) {
return -ENOMEDIUM;
}
- return bdrv_ioctl(blk_bs(blk), req, buf);
+ return bdrv_co_ioctl(blk_bs(blk), req, buf);
+}
+
+static void blk_ioctl_entry(void *opaque)
+{
+ BlkRwCo *rwco = opaque;
+ rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset,
+ rwco->qiov->iov[0].iov_base);
+}
+
+int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
+{
+ return blk_prw(blk, req, buf, 0, blk_ioctl_entry, 0);
+}
+
+static void blk_aio_ioctl_entry(void *opaque)
+{
+ BlkAioEmAIOCB *acb = opaque;
+ BlkRwCo *rwco = &acb->rwco;
+
+ rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset,
+ rwco->qiov->iov[0].iov_base);
+ blk_aio_complete(acb);
}
BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
BlockCompletionFunc *cb, void *opaque)
{
- if (!blk_is_available(blk)) {
- return blk_abort_aio_request(blk, cb, opaque, -ENOMEDIUM);
- }
+ QEMUIOVector qiov;
+ struct iovec iov;
- return bdrv_aio_ioctl(blk_bs(blk), req, buf, cb, opaque);
+ iov = (struct iovec) {
+ .iov_base = buf,
+ .iov_len = 0,
+ };
+ qemu_iovec_init_external(&qiov, &iov, 1);
+
+ return blk_aio_prwv(blk, req, 0, &qiov, blk_aio_ioctl_entry, 0, cb,
opaque);
}
int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int count)
@@ -1169,13 +1206,15 @@ int blk_co_flush(BlockBackend *blk)
return bdrv_co_flush(blk_bs(blk));
}
-int blk_flush(BlockBackend *blk)
+static void blk_flush_entry(void *opaque)
{
- if (!blk_is_available(blk)) {
- return -ENOMEDIUM;
- }
+ BlkRwCo *rwco = opaque;
+ rwco->ret = blk_co_flush(rwco->blk);
+}
- return bdrv_flush(blk_bs(blk));
+int blk_flush(BlockBackend *blk)
+{
+ return blk_prw(blk, 0, NULL, 0, blk_flush_entry, 0);
}
void blk_drain(BlockBackend *blk)
@@ -1555,14 +1594,15 @@ int blk_truncate(BlockBackend *blk, int64_t offset)
return bdrv_truncate(blk_bs(blk), offset);
}
-int blk_pdiscard(BlockBackend *blk, int64_t offset, int count)
+static void blk_pdiscard_entry(void *opaque)
{
- int ret = blk_check_byte_request(blk, offset, count);
- if (ret < 0) {
- return ret;
- }
+ BlkRwCo *rwco = opaque;
+ rwco->ret = blk_co_pdiscard(rwco->blk, rwco->offset, rwco->qiov->size);
+}
- return bdrv_pdiscard(blk_bs(blk), offset, count);
+int blk_pdiscard(BlockBackend *blk, int64_t offset, int count)
+{
+ return blk_prw(blk, offset, NULL, count, blk_pdiscard_entry, 0);
}
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index f2bfdcf..519737c 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -38,13 +38,20 @@
*/
struct BdrvDirtyBitmap {
HBitmap *bitmap; /* Dirty sector bitmap implementation */
+ HBitmap *meta; /* Meta dirty bitmap */
BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
char *name; /* Optional non-empty unique ID */
int64_t size; /* Size of the bitmap (Number of sectors) */
bool disabled; /* Bitmap is read-only */
+ int active_iterators; /* How many iterators are active */
QLIST_ENTRY(BdrvDirtyBitmap) list;
};
+struct BdrvDirtyBitmapIter {
+ HBitmapIter hbi;
+ BdrvDirtyBitmap *bitmap;
+};
+
BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
{
BdrvDirtyBitmap *bm;
@@ -97,6 +104,66 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState
*bs,
return bitmap;
}
+/* bdrv_create_meta_dirty_bitmap
+ *
+ * Create a meta dirty bitmap that tracks the changes of bits in @bitmap. I.e.
+ * when a dirty status bit in @bitmap is changed (either from reset to set or
+ * the other way around), its respective meta dirty bitmap bit will be marked
+ * dirty as well.
+ *
+ * @bitmap: the block dirty bitmap for which to create a meta dirty bitmap.
+ * @chunk_size: how many bytes of bitmap data does each bit in the meta bitmap
+ * track.
+ */
+void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
+ int chunk_size)
+{
+ assert(!bitmap->meta);
+ bitmap->meta = hbitmap_create_meta(bitmap->bitmap,
+ chunk_size * BITS_PER_BYTE);
+}
+
+void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
+{
+ assert(bitmap->meta);
+ hbitmap_free_meta(bitmap->bitmap);
+ bitmap->meta = NULL;
+}
+
+int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
+ BdrvDirtyBitmap *bitmap, int64_t sector,
+ int nb_sectors)
+{
+ uint64_t i;
+ int sectors_per_bit = 1 << hbitmap_granularity(bitmap->meta);
+
+ /* To optimize: we can make hbitmap to internally check the range in a
+ * coarse level, or at least do it word by word. */
+ for (i = sector; i < sector + nb_sectors; i += sectors_per_bit) {
+ if (hbitmap_get(bitmap->meta, i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
+ BdrvDirtyBitmap *bitmap, int64_t sector,
+ int nb_sectors)
+{
+ hbitmap_reset(bitmap->meta, sector, nb_sectors);
+}
+
+int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap)
+{
+ return bitmap->size;
+}
+
+const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap)
+{
+ return bitmap->name;
+}
+
bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
{
return bitmap->successor;
@@ -212,6 +279,7 @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
assert(!bdrv_dirty_bitmap_frozen(bitmap));
+ assert(!bitmap->active_iterators);
hbitmap_truncate(bitmap->bitmap, size);
bitmap->size = size;
}
@@ -224,7 +292,9 @@ static void
bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
BdrvDirtyBitmap *bm, *next;
QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
if ((!bitmap || bm == bitmap) && (!only_named || bm->name)) {
+ assert(!bm->active_iterators);
assert(!bdrv_dirty_bitmap_frozen(bm));
+ assert(!bm->meta);
QLIST_REMOVE(bm, list);
hbitmap_free(bm->bitmap);
g_free(bm->name);
@@ -235,6 +305,9 @@ static void
bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
}
}
}
+ if (bitmap) {
+ abort();
+ }
}
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
@@ -320,9 +393,43 @@ uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap
*bitmap)
return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
}
-void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
+uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap)
+{
+ return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->meta);
+}
+
+BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
+ uint64_t first_sector)
{
- hbitmap_iter_init(hbi, bitmap->bitmap, 0);
+ BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
+ hbitmap_iter_init(&iter->hbi, bitmap->bitmap, first_sector);
+ iter->bitmap = bitmap;
+ bitmap->active_iterators++;
+ return iter;
+}
+
+BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap)
+{
+ BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
+ hbitmap_iter_init(&iter->hbi, bitmap->meta, 0);
+ iter->bitmap = bitmap;
+ bitmap->active_iterators++;
+ return iter;
+}
+
+void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter)
+{
+ if (!iter) {
+ return;
+ }
+ assert(iter->bitmap->active_iterators > 0);
+ iter->bitmap->active_iterators--;
+ g_free(iter);
+}
+
+int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
+{
+ return hbitmap_iter_next(&iter->hbi);
}
void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
@@ -360,6 +467,43 @@ void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap,
HBitmap *in)
hbitmap_free(tmp);
}
+uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
+ uint64_t start, uint64_t count)
+{
+ return hbitmap_serialization_size(bitmap->bitmap, start, count);
+}
+
+uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap)
+{
+ return hbitmap_serialization_granularity(bitmap->bitmap);
+}
+
+void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
+ uint8_t *buf, uint64_t start,
+ uint64_t count)
+{
+ hbitmap_serialize_part(bitmap->bitmap, buf, start, count);
+}
+
+void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
+ uint8_t *buf, uint64_t start,
+ uint64_t count, bool finish)
+{
+ hbitmap_deserialize_part(bitmap->bitmap, buf, start, count, finish);
+}
+
+void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
+ uint64_t start, uint64_t count,
+ bool finish)
+{
+ hbitmap_deserialize_zeroes(bitmap->bitmap, start, count, finish);
+}
+
+void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
+{
+ hbitmap_deserialize_finish(bitmap->bitmap);
+}
+
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
int64_t nr_sectors)
{
@@ -373,15 +517,19 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t
cur_sector,
}
/**
- * Advance an HBitmapIter to an arbitrary offset.
+ * Advance a BdrvDirtyBitmapIter to an arbitrary offset.
*/
-void bdrv_set_dirty_iter(HBitmapIter *hbi, int64_t offset)
+void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *iter, int64_t sector_num)
{
- assert(hbi->hb);
- hbitmap_iter_init(hbi, hbi->hb, offset);
+ hbitmap_iter_init(&iter->hbi, iter->hbi.hb, sector_num);
}
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
{
return hbitmap_count(bitmap->bitmap);
}
+
+int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap)
+{
+ return hbitmap_count(bitmap->meta);
+}
diff --git a/block/io.c b/block/io.c
index b136c89..79cbbdf 100644
--- a/block/io.c
+++ b/block/io.c
@@ -2196,35 +2196,6 @@ BlockAIOCB *bdrv_aio_flush(BlockDriverState *bs,
return &acb->common;
}
-static void coroutine_fn bdrv_aio_pdiscard_co_entry(void *opaque)
-{
- BlockAIOCBCoroutine *acb = opaque;
- BlockDriverState *bs = acb->common.bs;
-
- acb->req.error = bdrv_co_pdiscard(bs, acb->req.offset, acb->req.bytes);
- bdrv_co_complete(acb);
-}
-
-BlockAIOCB *bdrv_aio_pdiscard(BlockDriverState *bs, int64_t offset, int count,
- BlockCompletionFunc *cb, void *opaque)
-{
- Coroutine *co;
- BlockAIOCBCoroutine *acb;
-
- trace_bdrv_aio_pdiscard(bs, offset, count, opaque);
-
- acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
- acb->need_bh = true;
- acb->req.error = -EINPROGRESS;
- acb->req.offset = offset;
- acb->req.bytes = count;
- co = qemu_coroutine_create(bdrv_aio_pdiscard_co_entry, acb);
- qemu_coroutine_enter(co);
-
- bdrv_co_maybe_schedule_bh(acb);
- return &acb->common;
-}
-
void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs,
BlockCompletionFunc *cb, void *opaque)
{
@@ -2521,7 +2492,7 @@ int bdrv_pdiscard(BlockDriverState *bs, int64_t offset,
int count)
return rwco.ret;
}
-static int bdrv_co_do_ioctl(BlockDriverState *bs, int req, void *buf)
+int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf)
{
BlockDriver *drv = bs->drv;
BdrvTrackedRequest tracked_req;
@@ -2531,86 +2502,26 @@ static int bdrv_co_do_ioctl(BlockDriverState *bs, int
req, void *buf)
BlockAIOCB *acb;
tracked_request_begin(&tracked_req, bs, 0, 0, BDRV_TRACKED_IOCTL);
- if (!drv || !drv->bdrv_aio_ioctl) {
+ if (!drv || (!drv->bdrv_aio_ioctl && !drv->bdrv_co_ioctl)) {
co.ret = -ENOTSUP;
goto out;
}
- acb = drv->bdrv_aio_ioctl(bs, req, buf, bdrv_co_io_em_complete, &co);
- if (!acb) {
- co.ret = -ENOTSUP;
- goto out;
+ if (drv->bdrv_co_ioctl) {
+ co.ret = drv->bdrv_co_ioctl(bs, req, buf);
+ } else {
+ acb = drv->bdrv_aio_ioctl(bs, req, buf, bdrv_co_io_em_complete, &co);
+ if (!acb) {
+ co.ret = -ENOTSUP;
+ goto out;
+ }
+ qemu_coroutine_yield();
}
- qemu_coroutine_yield();
out:
tracked_request_end(&tracked_req);
return co.ret;
}
-typedef struct {
- BlockDriverState *bs;
- int req;
- void *buf;
- int ret;
-} BdrvIoctlCoData;
-
-static void coroutine_fn bdrv_co_ioctl_entry(void *opaque)
-{
- BdrvIoctlCoData *data = opaque;
- data->ret = bdrv_co_do_ioctl(data->bs, data->req, data->buf);
-}
-
-/* needed for generic scsi interface */
-int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
-{
- BdrvIoctlCoData data = {
- .bs = bs,
- .req = req,
- .buf = buf,
- .ret = -EINPROGRESS,
- };
-
- if (qemu_in_coroutine()) {
- /* Fast-path if already in coroutine context */
- bdrv_co_ioctl_entry(&data);
- } else {
- Coroutine *co = qemu_coroutine_create(bdrv_co_ioctl_entry, &data);
-
- qemu_coroutine_enter(co);
- while (data.ret == -EINPROGRESS) {
- aio_poll(bdrv_get_aio_context(bs), true);
- }
- }
- return data.ret;
-}
-
-static void coroutine_fn bdrv_co_aio_ioctl_entry(void *opaque)
-{
- BlockAIOCBCoroutine *acb = opaque;
- acb->req.error = bdrv_co_do_ioctl(acb->common.bs,
- acb->req.req, acb->req.buf);
- bdrv_co_complete(acb);
-}
-
-BlockAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
- unsigned long int req, void *buf,
- BlockCompletionFunc *cb, void *opaque)
-{
- BlockAIOCBCoroutine *acb = qemu_aio_get(&bdrv_em_co_aiocb_info,
- bs, cb, opaque);
- Coroutine *co;
-
- acb->need_bh = true;
- acb->req.error = -EINPROGRESS;
- acb->req.req = req;
- acb->req.buf = buf;
- co = qemu_coroutine_create(bdrv_co_aio_ioctl_entry, acb);
- qemu_coroutine_enter(co);
-
- bdrv_co_maybe_schedule_bh(acb);
- return &acb->common;
-}
-
void *qemu_blockalign(BlockDriverState *bs, size_t size)
{
return qemu_memalign(bdrv_opt_mem_align(bs), size);
diff --git a/block/iscsi.c b/block/iscsi.c
index 46ddc35..71bd523 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -202,6 +202,10 @@ static inline unsigned exp_random(double mean)
#define SCSI_SENSE_ASCQ_PARAMETER_LIST_LENGTH_ERROR 0x1a00
#endif
+#ifndef LIBISCSI_API_VERSION
+#define LIBISCSI_API_VERSION 20130701
+#endif
+
static int iscsi_translate_sense(struct scsi_sense *sense)
{
int ret;
@@ -592,6 +596,20 @@ iscsi_co_writev_flags(BlockDriverState *bs, int64_t
sector_num, int nb_sectors,
iscsi_co_init_iscsitask(iscsilun, &iTask);
retry:
if (iscsilun->use_16_for_rw) {
+#if LIBISCSI_API_VERSION >= (20160603)
+ iTask.task = iscsi_write16_iov_task(iscsilun->iscsi, iscsilun->lun,
lba,
+ NULL, num_sectors *
iscsilun->block_size,
+ iscsilun->block_size, 0, 0, fua,
0, 0,
+ iscsi_co_generic_cb, &iTask,
+ (struct scsi_iovec *)iov->iov,
iov->niov);
+ } else {
+ iTask.task = iscsi_write10_iov_task(iscsilun->iscsi, iscsilun->lun,
lba,
+ NULL, num_sectors *
iscsilun->block_size,
+ iscsilun->block_size, 0, 0, fua,
0, 0,
+ iscsi_co_generic_cb, &iTask,
+ (struct scsi_iovec *)iov->iov,
iov->niov);
+ }
+#else
iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba,
NULL, num_sectors *
iscsilun->block_size,
iscsilun->block_size, 0, 0, fua, 0, 0,
@@ -602,11 +620,14 @@ retry:
iscsilun->block_size, 0, 0, fua, 0, 0,
iscsi_co_generic_cb, &iTask);
}
+#endif
if (iTask.task == NULL) {
return -ENOMEM;
}
+#if LIBISCSI_API_VERSION < (20160603)
scsi_task_set_iov_out(iTask.task, (struct scsi_iovec *) iov->iov,
iov->niov);
+#endif
while (!iTask.complete) {
iscsi_set_events(iscsilun);
qemu_coroutine_yield();
@@ -789,6 +810,21 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState
*bs,
iscsi_co_init_iscsitask(iscsilun, &iTask);
retry:
if (iscsilun->use_16_for_rw) {
+#if LIBISCSI_API_VERSION >= (20160603)
+ iTask.task = iscsi_read16_iov_task(iscsilun->iscsi, iscsilun->lun, lba,
+ num_sectors * iscsilun->block_size,
+ iscsilun->block_size, 0, 0, 0, 0, 0,
+ iscsi_co_generic_cb, &iTask,
+ (struct scsi_iovec *)iov->iov,
iov->niov);
+ } else {
+ iTask.task = iscsi_read10_iov_task(iscsilun->iscsi, iscsilun->lun, lba,
+ num_sectors * iscsilun->block_size,
+ iscsilun->block_size,
+ 0, 0, 0, 0, 0,
+ iscsi_co_generic_cb, &iTask,
+ (struct scsi_iovec *)iov->iov,
iov->niov);
+ }
+#else
iTask.task = iscsi_read16_task(iscsilun->iscsi, iscsilun->lun, lba,
num_sectors * iscsilun->block_size,
iscsilun->block_size, 0, 0, 0, 0, 0,
@@ -800,11 +836,13 @@ retry:
0, 0, 0, 0, 0,
iscsi_co_generic_cb, &iTask);
}
+#endif
if (iTask.task == NULL) {
return -ENOMEM;
}
+#if LIBISCSI_API_VERSION < (20160603)
scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *) iov->iov,
iov->niov);
-
+#endif
while (!iTask.complete) {
iscsi_set_events(iscsilun);
qemu_coroutine_yield();
@@ -1606,7 +1644,13 @@ static int iscsi_open(BlockDriverState *bs, QDict
*options, int flags,
ret = -ENOMEM;
goto out;
}
-
+#if LIBISCSI_API_VERSION >= (20160603)
+ if (iscsi_init_transport(iscsi, iscsi_url->transport)) {
+ error_setg(errp, ("Error initializing transport."));
+ ret = -EINVAL;
+ goto out;
+ }
+#endif
if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
error_setg(errp, "iSCSI: Failed to set target name.");
ret = -EINVAL;
@@ -1649,7 +1693,7 @@ static int iscsi_open(BlockDriverState *bs, QDict
*options, int flags,
/* timeout handling is broken in libiscsi before 1.15.0 */
timeout = parse_timeout(iscsi_url->target);
-#if defined(LIBISCSI_API_VERSION) && LIBISCSI_API_VERSION >= 20150621
+#if LIBISCSI_API_VERSION >= 20150621
iscsi_set_timeout(iscsi, timeout);
#else
if (timeout) {
@@ -2010,9 +2054,48 @@ static BlockDriver bdrv_iscsi = {
.bdrv_attach_aio_context = iscsi_attach_aio_context,
};
+#if LIBISCSI_API_VERSION >= (20160603)
+static BlockDriver bdrv_iser = {
+ .format_name = "iser",
+ .protocol_name = "iser",
+
+ .instance_size = sizeof(IscsiLun),
+ .bdrv_needs_filename = true,
+ .bdrv_file_open = iscsi_open,
+ .bdrv_close = iscsi_close,
+ .bdrv_create = iscsi_create,
+ .create_opts = &iscsi_create_opts,
+ .bdrv_reopen_prepare = iscsi_reopen_prepare,
+ .bdrv_reopen_commit = iscsi_reopen_commit,
+ .bdrv_invalidate_cache = iscsi_invalidate_cache,
+
+ .bdrv_getlength = iscsi_getlength,
+ .bdrv_get_info = iscsi_get_info,
+ .bdrv_truncate = iscsi_truncate,
+ .bdrv_refresh_limits = iscsi_refresh_limits,
+
+ .bdrv_co_get_block_status = iscsi_co_get_block_status,
+ .bdrv_co_pdiscard = iscsi_co_pdiscard,
+ .bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes,
+ .bdrv_co_readv = iscsi_co_readv,
+ .bdrv_co_writev_flags = iscsi_co_writev_flags,
+ .bdrv_co_flush_to_disk = iscsi_co_flush,
+
+#ifdef __linux__
+ .bdrv_aio_ioctl = iscsi_aio_ioctl,
+#endif
+
+ .bdrv_detach_aio_context = iscsi_detach_aio_context,
+ .bdrv_attach_aio_context = iscsi_attach_aio_context,
+};
+#endif
+
static void iscsi_block_init(void)
{
bdrv_register(&bdrv_iscsi);
+#if LIBISCSI_API_VERSION >= (20160603)
+ bdrv_register(&bdrv_iser);
+#endif
}
block_init(iscsi_block_init);
diff --git a/block/mirror.c b/block/mirror.c
index f9d1fec..a433e68 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -55,7 +55,7 @@ typedef struct MirrorBlockJob {
int64_t bdev_length;
unsigned long *cow_bitmap;
BdrvDirtyBitmap *dirty_bitmap;
- HBitmapIter hbi;
+ BdrvDirtyBitmapIter *dbi;
uint8_t *buf;
QSIMPLEQ_HEAD(, MirrorBuffer) buf_free;
int buf_free_count;
@@ -330,10 +330,10 @@ static uint64_t coroutine_fn
mirror_iteration(MirrorBlockJob *s)
int max_io_sectors = MAX((s->buf_size >> BDRV_SECTOR_BITS) / MAX_IN_FLIGHT,
MAX_IO_SECTORS);
- sector_num = hbitmap_iter_next(&s->hbi);
+ sector_num = bdrv_dirty_iter_next(s->dbi);
if (sector_num < 0) {
- bdrv_dirty_iter_init(s->dirty_bitmap, &s->hbi);
- sector_num = hbitmap_iter_next(&s->hbi);
+ bdrv_set_dirty_iter(s->dbi, 0);
+ sector_num = bdrv_dirty_iter_next(s->dbi);
trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap));
assert(sector_num >= 0);
}
@@ -349,7 +349,7 @@ static uint64_t coroutine_fn
mirror_iteration(MirrorBlockJob *s)
/* Find the number of consective dirty chunks following the first dirty
* one, and wait for in flight requests in them. */
while (nb_chunks * sectors_per_chunk < (s->buf_size >> BDRV_SECTOR_BITS)) {
- int64_t hbitmap_next;
+ int64_t next_dirty;
int64_t next_sector = sector_num + nb_chunks * sectors_per_chunk;
int64_t next_chunk = next_sector / sectors_per_chunk;
if (next_sector >= end ||
@@ -360,13 +360,13 @@ static uint64_t coroutine_fn
mirror_iteration(MirrorBlockJob *s)
break;
}
- hbitmap_next = hbitmap_iter_next(&s->hbi);
- if (hbitmap_next > next_sector || hbitmap_next < 0) {
+ next_dirty = bdrv_dirty_iter_next(s->dbi);
+ if (next_dirty > next_sector || next_dirty < 0) {
/* The bitmap iterator's cache is stale, refresh it */
- bdrv_set_dirty_iter(&s->hbi, next_sector);
- hbitmap_next = hbitmap_iter_next(&s->hbi);
+ bdrv_set_dirty_iter(s->dbi, next_sector);
+ next_dirty = bdrv_dirty_iter_next(s->dbi);
}
- assert(hbitmap_next == next_sector);
+ assert(next_dirty == next_sector);
nb_chunks++;
}
@@ -679,7 +679,8 @@ static void coroutine_fn mirror_run(void *opaque)
}
}
- bdrv_dirty_iter_init(s->dirty_bitmap, &s->hbi);
+ assert(!s->dbi);
+ s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap, 0);
for (;;) {
uint64_t delay_ns = 0;
int64_t cnt, delta;
@@ -793,6 +794,7 @@ immediate_exit:
qemu_vfree(s->buf);
g_free(s->cow_bitmap);
g_free(s->in_flight_bitmap);
+ bdrv_dirty_iter_free(s->dbi);
bdrv_release_dirty_bitmap(bs, s->dirty_bitmap);
data = g_malloc(sizeof(*data));
diff --git a/block/nbd.c b/block/nbd.c
index 1ec64ab..6e837f8 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -32,6 +32,9 @@
#include "qemu/uri.h"
#include "block/block_int.h"
#include "qemu/module.h"
+#include "qapi-visit.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/qobject-output-visitor.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qint.h"
@@ -44,7 +47,8 @@ typedef struct BDRVNBDState {
NbdClientSession client;
/* For nbd_refresh_filename() */
- char *path, *host, *port, *export, *tlscredsid;
+ SocketAddress *saddr;
+ char *export, *tlscredsid;
} BDRVNBDState;
static int nbd_parse_uri(const char *filename, QDict *options)
@@ -90,9 +94,13 @@ static int nbd_parse_uri(const char *filename, QDict
*options)
ret = -EINVAL;
goto out;
}
- qdict_put(options, "path", qstring_from_str(qp->p[0].value));
+ qdict_put(options, "server.type", qstring_from_str("unix"));
+ qdict_put(options, "server.data.path",
+ qstring_from_str(qp->p[0].value));
} else {
QString *host;
+ char *port_str;
+
/* nbd[+tcp]://host[:port]/export */
if (!uri->server) {
ret = -EINVAL;
@@ -107,12 +115,12 @@ static int nbd_parse_uri(const char *filename, QDict
*options)
host = qstring_from_str(uri->server);
}
- qdict_put(options, "host", host);
- if (uri->port) {
- char* port_str = g_strdup_printf("%d", uri->port);
- qdict_put(options, "port", qstring_from_str(port_str));
- g_free(port_str);
- }
+ qdict_put(options, "server.type", qstring_from_str("inet"));
+ qdict_put(options, "server.data.host", host);
+
+ port_str = g_strdup_printf("%d", uri->port ?: NBD_DEFAULT_PORT);
+ qdict_put(options, "server.data.port", qstring_from_str(port_str));
+ g_free(port_str);
}
out:
@@ -123,6 +131,26 @@ out:
return ret;
}
+static bool nbd_has_filename_options_conflict(QDict *options, Error **errp)
+{
+ const QDictEntry *e;
+
+ for (e = qdict_first(options); e; e = qdict_next(options, e)) {
+ if (!strcmp(e->key, "host") ||
+ !strcmp(e->key, "port") ||
+ !strcmp(e->key, "path") ||
+ !strcmp(e->key, "export") ||
+ strstart(e->key, "server.", NULL))
+ {
+ error_setg(errp, "Option '%s' cannot be used with a file name",
+ e->key);
+ return true;
+ }
+ }
+
+ return false;
+}
+
static void nbd_parse_filename(const char *filename, QDict *options,
Error **errp)
{
@@ -131,12 +159,7 @@ static void nbd_parse_filename(const char *filename, QDict
*options,
const char *host_spec;
const char *unixpath;
- if (qdict_haskey(options, "host")
- || qdict_haskey(options, "port")
- || qdict_haskey(options, "path"))
- {
- error_setg(errp, "host/port/path and a file name may not be specified "
- "at the same time");
+ if (nbd_has_filename_options_conflict(options, errp)) {
return;
}
@@ -173,7 +196,8 @@ static void nbd_parse_filename(const char *filename, QDict
*options,
/* are we a UNIX or TCP socket? */
if (strstart(host_spec, "unix:", &unixpath)) {
- qdict_put(options, "path", qstring_from_str(unixpath));
+ qdict_put(options, "server.type", qstring_from_str("unix"));
+ qdict_put(options, "server.data.path", qstring_from_str(unixpath));
} else {
InetSocketAddress *addr = NULL;
@@ -182,8 +206,9 @@ static void nbd_parse_filename(const char *filename, QDict
*options,
goto out;
}
- qdict_put(options, "host", qstring_from_str(addr->host));
- qdict_put(options, "port", qstring_from_str(addr->port));
+ qdict_put(options, "server.type", qstring_from_str("inet"));
+ qdict_put(options, "server.data.host", qstring_from_str(addr->host));
+ qdict_put(options, "server.data.port", qstring_from_str(addr->port));
qapi_free_InetSocketAddress(addr);
}
@@ -191,47 +216,81 @@ out:
g_free(file);
}
-static SocketAddress *nbd_config(BDRVNBDState *s, QemuOpts *opts, Error **errp)
+static bool nbd_process_legacy_socket_options(QDict *output_options,
+ QemuOpts *legacy_opts,
+ Error **errp)
{
- SocketAddress *saddr;
+ const char *path = qemu_opt_get(legacy_opts, "path");
+ const char *host = qemu_opt_get(legacy_opts, "host");
+ const char *port = qemu_opt_get(legacy_opts, "port");
+ const QDictEntry *e;
- s->path = g_strdup(qemu_opt_get(opts, "path"));
- s->host = g_strdup(qemu_opt_get(opts, "host"));
+ if (!path && !host && !port) {
+ return true;
+ }
- if (!s->path == !s->host) {
- if (s->path) {
- error_setg(errp, "path and host may not be used at the same
time.");
- } else {
- error_setg(errp, "one of path and host must be specified.");
+ for (e = qdict_first(output_options); e; e = qdict_next(output_options, e))
+ {
+ if (strstart(e->key, "server.", NULL)) {
+ error_setg(errp, "Cannot use 'server' and path/host/port at the "
+ "same time");
+ return false;
}
- return NULL;
}
- saddr = g_new0(SocketAddress, 1);
+ if (path && host) {
+ error_setg(errp, "path and host may not be used at the same time");
+ return false;
+ } else if (path) {
+ if (port) {
+ error_setg(errp, "port may not be used without host");
+ return false;
+ }
- if (s->path) {
- UnixSocketAddress *q_unix;
- saddr->type = SOCKET_ADDRESS_KIND_UNIX;
- q_unix = saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
- q_unix->path = g_strdup(s->path);
- } else {
- InetSocketAddress *inet;
+ qdict_put(output_options, "server.type", qstring_from_str("unix"));
+ qdict_put(output_options, "server.data.path", qstring_from_str(path));
+ } else if (host) {
+ qdict_put(output_options, "server.type", qstring_from_str("inet"));
+ qdict_put(output_options, "server.data.host", qstring_from_str(host));
+ qdict_put(output_options, "server.data.port",
+ qstring_from_str(port ?: stringify(NBD_DEFAULT_PORT)));
+ }
- s->port = g_strdup(qemu_opt_get(opts, "port"));
+ return true;
+}
- saddr->type = SOCKET_ADDRESS_KIND_INET;
- inet = saddr->u.inet.data = g_new0(InetSocketAddress, 1);
- inet->host = g_strdup(s->host);
- inet->port = g_strdup(s->port);
- if (!inet->port) {
- inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT);
- }
+static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, Error **errp)
+{
+ SocketAddress *saddr = NULL;
+ QDict *addr = NULL;
+ QObject *crumpled_addr = NULL;
+ Visitor *iv = NULL;
+ Error *local_err = NULL;
+
+ qdict_extract_subqdict(options, &addr, "server.");
+ if (!qdict_size(addr)) {
+ error_setg(errp, "NBD server address missing");
+ goto done;
}
- s->client.is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
+ crumpled_addr = qdict_crumple(addr, errp);
+ if (!crumpled_addr) {
+ goto done;
+ }
- s->export = g_strdup(qemu_opt_get(opts, "export"));
+ iv = qobject_input_visitor_new(crumpled_addr, true);
+ visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto done;
+ }
+
+ s->client.is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
+done:
+ QDECREF(addr);
+ qobject_decref(crumpled_addr);
+ visit_free(iv);
return saddr;
}
@@ -333,7 +392,6 @@ static int nbd_open(BlockDriverState *bs, QDict *options,
int flags,
QemuOpts *opts = NULL;
Error *local_err = NULL;
QIOChannelSocket *sioc = NULL;
- SocketAddress *saddr = NULL;
QCryptoTLSCreds *tlscreds = NULL;
const char *hostname = NULL;
int ret = -EINVAL;
@@ -345,12 +403,19 @@ static int nbd_open(BlockDriverState *bs, QDict *options,
int flags,
goto error;
}
+ /* Translate @host, @port, and @path to a SocketAddress */
+ if (!nbd_process_legacy_socket_options(options, opts, errp)) {
+ goto error;
+ }
+
/* Pop the config into our state object. Exit if invalid. */
- saddr = nbd_config(s, opts, errp);
- if (!saddr) {
+ s->saddr = nbd_config(s, options, errp);
+ if (!s->saddr) {
goto error;
}
+ s->export = g_strdup(qemu_opt_get(opts, "export"));
+
s->tlscredsid = g_strdup(qemu_opt_get(opts, "tls-creds"));
if (s->tlscredsid) {
tlscreds = nbd_get_tls_creds(s->tlscredsid, errp);
@@ -358,17 +423,17 @@ static int nbd_open(BlockDriverState *bs, QDict *options,
int flags,
goto error;
}
- if (saddr->type != SOCKET_ADDRESS_KIND_INET) {
+ if (s->saddr->type != SOCKET_ADDRESS_KIND_INET) {
error_setg(errp, "TLS only supported over IP sockets");
goto error;
}
- hostname = saddr->u.inet.data->host;
+ hostname = s->saddr->u.inet.data->host;
}
/* establish TCP connection, return error if it fails
* TODO: Configurable retry-until-timeout behaviour.
*/
- sioc = nbd_establish_connection(saddr, errp);
+ sioc = nbd_establish_connection(s->saddr, errp);
if (!sioc) {
ret = -ECONNREFUSED;
goto error;
@@ -385,13 +450,10 @@ static int nbd_open(BlockDriverState *bs, QDict *options,
int flags,
object_unref(OBJECT(tlscreds));
}
if (ret < 0) {
- g_free(s->path);
- g_free(s->host);
- g_free(s->port);
+ qapi_free_SocketAddress(s->saddr);
g_free(s->export);
g_free(s->tlscredsid);
}
- qapi_free_SocketAddress(saddr);
qemu_opts_del(opts);
return ret;
}
@@ -413,9 +475,7 @@ static void nbd_close(BlockDriverState *bs)
nbd_client_close(bs);
- g_free(s->path);
- g_free(s->host);
- g_free(s->port);
+ qapi_free_SocketAddress(s->saddr);
g_free(s->export);
g_free(s->tlscredsid);
}
@@ -442,45 +502,51 @@ static void nbd_refresh_filename(BlockDriverState *bs,
QDict *options)
{
BDRVNBDState *s = bs->opaque;
QDict *opts = qdict_new();
+ QObject *saddr_qdict;
+ Visitor *ov;
+ const char *host = NULL, *port = NULL, *path = NULL;
+
+ if (s->saddr->type == SOCKET_ADDRESS_KIND_INET) {
+ const InetSocketAddress *inet = s->saddr->u.inet.data;
+ if (!inet->has_ipv4 && !inet->has_ipv6 && !inet->has_to) {
+ host = inet->host;
+ port = inet->port;
+ }
+ } else if (s->saddr->type == SOCKET_ADDRESS_KIND_UNIX) {
+ path = s->saddr->u.q_unix.data->path;
+ }
- qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("nbd")));
+ qdict_put(opts, "driver", qstring_from_str("nbd"));
- if (s->path && s->export) {
+ if (path && s->export) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
- "nbd+unix:///%s?socket=%s", s->export, s->path);
- } else if (s->path && !s->export) {
+ "nbd+unix:///%s?socket=%s", s->export, path);
+ } else if (path && !s->export) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
- "nbd+unix://?socket=%s", s->path);
- } else if (!s->path && s->export && s->port) {
+ "nbd+unix://?socket=%s", path);
+ } else if (host && s->export) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
- "nbd://%s:%s/%s", s->host, s->port, s->export);
- } else if (!s->path && s->export && !s->port) {
+ "nbd://%s:%s/%s", host, port, s->export);
+ } else if (host && !s->export) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
- "nbd://%s/%s", s->host, s->export);
- } else if (!s->path && !s->export && s->port) {
- snprintf(bs->exact_filename, sizeof(bs->exact_filename),
- "nbd://%s:%s", s->host, s->port);
- } else if (!s->path && !s->export && !s->port) {
- snprintf(bs->exact_filename, sizeof(bs->exact_filename),
- "nbd://%s", s->host);
+ "nbd://%s:%s", host, port);
}
- if (s->path) {
- qdict_put_obj(opts, "path", QOBJECT(qstring_from_str(s->path)));
- } else if (s->port) {
- qdict_put_obj(opts, "host", QOBJECT(qstring_from_str(s->host)));
- qdict_put_obj(opts, "port", QOBJECT(qstring_from_str(s->port)));
- } else {
- qdict_put_obj(opts, "host", QOBJECT(qstring_from_str(s->host)));
- }
+ ov = qobject_output_visitor_new(&saddr_qdict);
+ visit_type_SocketAddress(ov, NULL, &s->saddr, &error_abort);
+ visit_complete(ov, &saddr_qdict);
+ assert(qobject_type(saddr_qdict) == QTYPE_QDICT);
+
+ qdict_put_obj(opts, "server", saddr_qdict);
+
if (s->export) {
- qdict_put_obj(opts, "export", QOBJECT(qstring_from_str(s->export)));
+ qdict_put(opts, "export", qstring_from_str(s->export));
}
if (s->tlscredsid) {
- qdict_put_obj(opts, "tls-creds",
- QOBJECT(qstring_from_str(s->tlscredsid)));
+ qdict_put(opts, "tls-creds", qstring_from_str(s->tlscredsid));
}
+ qdict_flatten(opts);
bs->full_open_options = opts;
}
diff --git a/block/qapi.c b/block/qapi.c
index 6f947e3..a62e862 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -29,7 +29,7 @@
#include "block/write-threshold.h"
#include "qmp-commands.h"
#include "qapi-visit.h"
-#include "qapi/qmp-output-visitor.h"
+#include "qapi/qobject-output-visitor.h"
#include "qapi/qmp/types.h"
#include "sysemu/block-backend.h"
#include "qemu/cutils.h"
@@ -691,13 +691,14 @@ void bdrv_image_info_specific_dump(fprintf_function
func_fprintf, void *f,
ImageInfoSpecific *info_spec)
{
QObject *obj, *data;
- Visitor *v = qmp_output_visitor_new(&obj);
+ Visitor *v = qobject_output_visitor_new(&obj);
visit_type_ImageInfoSpecific(v, NULL, &info_spec, &error_abort);
visit_complete(v, &obj);
assert(qobject_type(obj) == QTYPE_QDICT);
data = qdict_get(qobject_to_qdict(obj), "data");
dump_qobject(func_fprintf, f, 1, data);
+ qobject_decref(obj);
visit_free(v);
}
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 61d1ffd..928c1e2 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1558,7 +1558,7 @@ fail:
* clusters.
*/
static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
- uint64_t nb_clusters)
+ uint64_t nb_clusters, int flags)
{
BDRVQcow2State *s = bs->opaque;
uint64_t *l2_table;
@@ -1582,7 +1582,7 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t
offset,
/* Update L2 entries */
qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
- if (old_offset & QCOW_OFLAG_COMPRESSED) {
+ if (old_offset & QCOW_OFLAG_COMPRESSED || flags & BDRV_REQ_MAY_UNMAP) {
l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
} else {
@@ -1595,7 +1595,8 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t
offset,
return nb_clusters;
}
-int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors)
+int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors,
+ int flags)
{
BDRVQcow2State *s = bs->opaque;
uint64_t nb_clusters;
@@ -1612,7 +1613,7 @@ int qcow2_zero_clusters(BlockDriverState *bs, uint64_t
offset, int nb_sectors)
s->cache_discards = true;
while (nb_clusters > 0) {
- ret = zero_single_l2(bs, offset, nb_clusters);
+ ret = zero_single_l2(bs, offset, nb_clusters, flags);
if (ret < 0) {
goto fail;
}
diff --git a/block/qcow2.c b/block/qcow2.c
index e11c7c9..6d5689a 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1155,6 +1155,7 @@ static int qcow2_open(BlockDriverState *bs, QDict
*options, int flags,
/* Initialise locks */
qemu_co_mutex_init(&s->lock);
+ bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP;
/* Repair image if dirty */
if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
@@ -2477,7 +2478,7 @@ static coroutine_fn int
qcow2_co_pwrite_zeroes(BlockDriverState *bs,
trace_qcow2_pwrite_zeroes(qemu_coroutine_self(), offset, count);
/* Whatever is left can use real zero clusters */
- ret = qcow2_zero_clusters(bs, offset, count >> BDRV_SECTOR_BITS);
+ ret = qcow2_zero_clusters(bs, offset, count >> BDRV_SECTOR_BITS, flags);
qemu_co_mutex_unlock(&s->lock);
return ret;
diff --git a/block/qcow2.h b/block/qcow2.h
index 9ce5a37..92203a8 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -547,7 +547,8 @@ uint64_t
qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
int nb_sectors, enum qcow2_discard_type type, bool full_discard);
-int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors);
+int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors,
+ int flags);
int qcow2_expand_zero_clusters(BlockDriverState *bs,
BlockDriverAmendStatusCB *status_cb,
diff --git a/block/quorum.c b/block/quorum.c
index 9cf876f..d122299 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -130,7 +130,7 @@ struct QuorumAIOCB {
bool is_read;
int vote_ret;
- int child_iter; /* which child to read in fifo pattern */
+ int children_read; /* how many children have been read from */
};
static bool quorum_vote(QuorumAIOCB *acb);
@@ -156,22 +156,7 @@ static AIOCBInfo quorum_aiocb_info = {
static void quorum_aio_finalize(QuorumAIOCB *acb)
{
- int i, ret = 0;
-
- if (acb->vote_ret) {
- ret = acb->vote_ret;
- }
-
- acb->common.cb(acb->common.opaque, ret);
-
- if (acb->is_read) {
- /* on the quorum case acb->child_iter == s->num_children - 1 */
- for (i = 0; i <= acb->child_iter; i++) {
- qemu_vfree(acb->qcrs[i].buf);
- qemu_iovec_destroy(&acb->qcrs[i].qiov);
- }
- }
-
+ acb->common.cb(acb->common.opaque, acb->vote_ret);
g_free(acb->qcrs);
qemu_aio_unref(acb);
}
@@ -283,39 +268,52 @@ static void quorum_copy_qiov(QEMUIOVector *dest,
QEMUIOVector *source)
}
}
-static void quorum_aio_cb(void *opaque, int ret)
+static void quorum_report_bad_acb(QuorumChildRequest *sacb, int ret)
+{
+ QuorumAIOCB *acb = sacb->parent;
+ QuorumOpType type = acb->is_read ? QUORUM_OP_TYPE_READ :
QUORUM_OP_TYPE_WRITE;
+ quorum_report_bad(type, acb->sector_num, acb->nb_sectors,
+ sacb->aiocb->bs->node_name, ret);
+}
+
+static void quorum_fifo_aio_cb(void *opaque, int ret)
{
QuorumChildRequest *sacb = opaque;
QuorumAIOCB *acb = sacb->parent;
BDRVQuorumState *s = acb->common.bs->opaque;
- bool rewrite = false;
- if (ret == 0) {
- acb->success_count++;
- } else {
- QuorumOpType type;
- type = acb->is_read ? QUORUM_OP_TYPE_READ : QUORUM_OP_TYPE_WRITE;
- quorum_report_bad(type, acb->sector_num, acb->nb_sectors,
- sacb->aiocb->bs->node_name, ret);
- }
+ assert(acb->is_read && s->read_pattern == QUORUM_READ_PATTERN_FIFO);
+
+ if (ret < 0) {
+ quorum_report_bad_acb(sacb, ret);
- if (acb->is_read && s->read_pattern == QUORUM_READ_PATTERN_FIFO) {
/* We try to read next child in FIFO order if we fail to read */
- if (ret < 0 && (acb->child_iter + 1) < s->num_children) {
- acb->child_iter++;
+ if (acb->children_read < s->num_children) {
read_fifo_child(acb);
return;
}
-
- if (ret == 0) {
- quorum_copy_qiov(acb->qiov, &acb->qcrs[acb->child_iter].qiov);
- }
- acb->vote_ret = ret;
- quorum_aio_finalize(acb);
- return;
}
+ acb->vote_ret = ret;
+
+ /* FIXME: rewrite failed children if acb->children_read > 1? */
+ quorum_aio_finalize(acb);
+}
+
+static void quorum_aio_cb(void *opaque, int ret)
+{
+ QuorumChildRequest *sacb = opaque;
+ QuorumAIOCB *acb = sacb->parent;
+ BDRVQuorumState *s = acb->common.bs->opaque;
+ bool rewrite = false;
+ int i;
+
sacb->ret = ret;
+ if (ret == 0) {
+ acb->success_count++;
+ } else {
+ quorum_report_bad_acb(sacb, ret);
+ }
acb->count++;
assert(acb->count <= s->num_children);
assert(acb->success_count <= s->num_children);
@@ -326,6 +324,10 @@ static void quorum_aio_cb(void *opaque, int ret)
/* Do the vote on read */
if (acb->is_read) {
rewrite = quorum_vote(acb);
+ for (i = 0; i < s->num_children; i++) {
+ qemu_vfree(acb->qcrs[i].buf);
+ qemu_iovec_destroy(&acb->qcrs[i].qiov);
+ }
} else {
quorum_has_too_much_io_failed(acb);
}
@@ -653,6 +655,7 @@ static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb)
BDRVQuorumState *s = acb->common.bs->opaque;
int i;
+ acb->children_read = s->num_children;
for (i = 0; i < s->num_children; i++) {
acb->qcrs[i].buf = qemu_blockalign(s->children[i]->bs,
acb->qiov->size);
qemu_iovec_init(&acb->qcrs[i].qiov, acb->qiov->niov);
@@ -671,16 +674,11 @@ static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb)
static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb)
{
BDRVQuorumState *s = acb->common.bs->opaque;
+ int n = acb->children_read++;
- acb->qcrs[acb->child_iter].buf =
- qemu_blockalign(s->children[acb->child_iter]->bs, acb->qiov->size);
- qemu_iovec_init(&acb->qcrs[acb->child_iter].qiov, acb->qiov->niov);
- qemu_iovec_clone(&acb->qcrs[acb->child_iter].qiov, acb->qiov,
- acb->qcrs[acb->child_iter].buf);
- acb->qcrs[acb->child_iter].aiocb =
- bdrv_aio_readv(s->children[acb->child_iter], acb->sector_num,
- &acb->qcrs[acb->child_iter].qiov, acb->nb_sectors,
- quorum_aio_cb, &acb->qcrs[acb->child_iter]);
+ acb->qcrs[n].aiocb = bdrv_aio_readv(s->children[n], acb->sector_num,
+ acb->qiov, acb->nb_sectors,
+ quorum_fifo_aio_cb, &acb->qcrs[n]);
return &acb->common;
}
@@ -696,13 +694,12 @@ static BlockAIOCB *quorum_aio_readv(BlockDriverState *bs,
QuorumAIOCB *acb = quorum_aio_get(s, bs, qiov, sector_num,
nb_sectors, cb, opaque);
acb->is_read = true;
+ acb->children_read = 0;
if (s->read_pattern == QUORUM_READ_PATTERN_QUORUM) {
- acb->child_iter = s->num_children - 1;
return read_quorum_children(acb);
}
- acb->child_iter = 0;
return read_fifo_child(acb);
}
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 166e9d1..247e47b 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -443,6 +443,7 @@ static int raw_open_common(BlockDriverState *bs, QDict
*options,
fd = qemu_open(filename, s->open_flags, 0644);
if (fd < 0) {
ret = -errno;
+ error_setg_errno(errp, errno, "Could not open '%s'", filename);
if (ret == -EROFS) {
ret = -EACCES;
}
@@ -2068,13 +2069,23 @@ static bool hdev_is_sg(BlockDriverState *bs)
#if defined(__linux__)
+ BDRVRawState *s = bs->opaque;
struct stat st;
struct sg_scsi_id scsiid;
int sg_version;
+ int ret;
+
+ if (stat(bs->filename, &st) < 0 || !S_ISCHR(st.st_mode)) {
+ return false;
+ }
- if (stat(bs->filename, &st) >= 0 && S_ISCHR(st.st_mode) &&
- !bdrv_ioctl(bs, SG_GET_VERSION_NUM, &sg_version) &&
- !bdrv_ioctl(bs, SG_GET_SCSI_ID, &scsiid)) {
+ ret = ioctl(s->fd, SG_GET_VERSION_NUM, &sg_version);
+ if (ret < 0) {
+ return false;
+ }
+
+ ret = ioctl(s->fd, SG_GET_SCSI_ID, &scsiid);
+ if (ret >= 0) {
DPRINTF("SG device found: type=%d, version=%d\n",
scsiid.scsi_type, sg_version);
return true;
diff --git a/block/raw-win32.c b/block/raw-win32.c
index 734bb10..800fabd 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -373,6 +373,7 @@ static int raw_open(BlockDriverState *bs, QDict *options,
int flags,
if (s->hfile == INVALID_HANDLE_VALUE) {
int err = GetLastError();
+ error_setg_win32(errp, err, "Could not open '%s'", filename);
if (err == ERROR_ACCESS_DENIED) {
ret = -EACCES;
} else {
diff --git a/block/raw_bsd.c b/block/raw_bsd.c
index 588d408..fc16ec1 100644
--- a/block/raw_bsd.c
+++ b/block/raw_bsd.c
@@ -176,12 +176,9 @@ static void raw_lock_medium(BlockDriverState *bs, bool
locked)
bdrv_lock_medium(bs->file->bs, locked);
}
-static BlockAIOCB *raw_aio_ioctl(BlockDriverState *bs,
- unsigned long int req, void *buf,
- BlockCompletionFunc *cb,
- void *opaque)
+static int raw_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
{
- return bdrv_aio_ioctl(bs->file->bs, req, buf, cb, opaque);
+ return bdrv_co_ioctl(bs->file->bs, req, buf);
}
static int raw_has_zero_init(BlockDriverState *bs)
@@ -261,7 +258,7 @@ BlockDriver bdrv_raw = {
.bdrv_media_changed = &raw_media_changed,
.bdrv_eject = &raw_eject,
.bdrv_lock_medium = &raw_lock_medium,
- .bdrv_aio_ioctl = &raw_aio_ioctl,
+ .bdrv_co_ioctl = &raw_co_ioctl,
.create_opts = &raw_create_opts,
.bdrv_has_zero_init = &raw_has_zero_init
};
diff --git a/block/rbd.c b/block/rbd.c
index 6f9eb6f..f6e1d4b 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -733,7 +733,7 @@ static BlockAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
void *opaque)
{
return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov,
- nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
+ (int64_t) nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
RBD_AIO_READ);
}
@@ -745,7 +745,7 @@ static BlockAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
void *opaque)
{
return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov,
- nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
+ (int64_t) nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
RBD_AIO_WRITE);
}
diff --git a/block/replication.c b/block/replication.c
index 3bd1cf1..8bbfc8f 100644
--- a/block/replication.c
+++ b/block/replication.c
@@ -101,6 +101,11 @@ static int replication_open(BlockDriverState *bs, QDict
*options,
if (!strcmp(mode, "primary")) {
s->mode = REPLICATION_MODE_PRIMARY;
+ top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
+ if (top_id) {
+ error_setg(&local_err, "The primary side does not support option
top-id");
+ goto fail;
+ }
} else if (!strcmp(mode, "secondary")) {
s->mode = REPLICATION_MODE_SECONDARY;
top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index 59545e2..17b2efb 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -168,6 +168,22 @@ static BlockBackend *throttle_group_next_blk(BlockBackend
*blk)
return blk_by_public(next);
}
+/*
+ * Return whether a BlockBackend has pending requests.
+ *
+ * This assumes that tg->lock is held.
+ *
+ * @blk: the BlockBackend
+ * @is_write: the type of operation (read/write)
+ * @ret: whether the BlockBackend has pending requests.
+ */
+static inline bool blk_has_pending_reqs(BlockBackend *blk,
+ bool is_write)
+{
+ const BlockBackendPublic *blkp = blk_get_public(blk);
+ return blkp->pending_reqs[is_write];
+}
+
/* Return the next BlockBackend in the round-robin sequence with pending I/O
* requests.
*
@@ -188,7 +204,7 @@ static BlockBackend *next_throttle_token(BlockBackend *blk,
bool is_write)
/* get next bs round in round robin style */
token = throttle_group_next_blk(token);
- while (token != start && !blkp->pending_reqs[is_write]) {
+ while (token != start && !blk_has_pending_reqs(token, is_write)) {
token = throttle_group_next_blk(token);
}
@@ -196,10 +212,13 @@ static BlockBackend *next_throttle_token(BlockBackend
*blk, bool is_write)
* then decide the token is the current bs because chances are
* the current bs get the current request queued.
*/
- if (token == start && !blkp->pending_reqs[is_write]) {
+ if (token == start && !blk_has_pending_reqs(token, is_write)) {
token = blk;
}
+ /* Either we return the original BB, or one with pending requests */
+ assert(token == blk || blk_has_pending_reqs(token, is_write));
+
return token;
}
@@ -257,7 +276,7 @@ static void schedule_next_request(BlockBackend *blk, bool
is_write)
/* Check if there's any pending request to schedule next */
token = next_throttle_token(blk, is_write);
- if (!blkp->pending_reqs[is_write]) {
+ if (!blk_has_pending_reqs(token, is_write)) {
return;
}
@@ -271,7 +290,7 @@ static void schedule_next_request(BlockBackend *blk, bool
is_write)
qemu_co_queue_next(&blkp->throttled_reqs[is_write])) {
token = blk;
} else {
- ThrottleTimers *tt = &blkp->throttle_timers;
+ ThrottleTimers *tt = &blk_get_public(token)->throttle_timers;
int64_t now = qemu_clock_get_ns(tt->clock_type);
timer_mod(tt->timers[is_write], now + 1);
tg->any_timer_armed[is_write] = true;
diff --git a/block/trace-events b/block/trace-events
index 05fa13c..aff8a96 100644
--- a/block/trace-events
+++ b/block/trace-events
@@ -9,7 +9,6 @@ blk_co_preadv(void *blk, void *bs, int64_t offset, unsigned int
bytes, int flags
blk_co_pwritev(void *blk, void *bs, int64_t offset, unsigned int bytes, int
flags) "blk %p bs %p offset %"PRId64" bytes %u flags %x"
# block/io.c
-bdrv_aio_pdiscard(void *bs, int64_t offset, int count, void *opaque) "bs %p
offset %"PRId64" count %d opaque %p"
bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs
%p sector_num %"PRId64" nb_sectors %d opaque %p"
bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque)
"bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
diff --git a/blockdev.c b/blockdev.c
index 07ec733..d11a74f 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -43,7 +43,7 @@
#include "qapi/qmp/types.h"
#include "qapi-visit.h"
#include "qapi/qmp/qerror.h"
-#include "qapi/qmp-output-visitor.h"
+#include "qapi/qobject-output-visitor.h"
#include "qapi/util.h"
#include "sysemu/sysemu.h"
#include "block/block_int.h"
@@ -3776,7 +3776,7 @@ void qmp_blockdev_add(BlockdevOptions *options, Error
**errp)
{
BlockDriverState *bs;
QObject *obj;
- Visitor *v = qmp_output_visitor_new(&obj);
+ Visitor *v = qobject_output_visitor_new(&obj);
QDict *qdict;
Error *local_err = NULL;
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 4fd7b63..714a692 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -651,7 +651,7 @@ void cpu_loop(CPUSPARCState *env)
static void usage(void)
{
printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION
- ", " QEMU_COPYRIGHT "\n"
+ "\n" QEMU_COPYRIGHT "\n"
"usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
"BSD CPU emulator (compiled for %s emulation)\n"
"\n"
diff --git a/configure b/configure
index dd9e679..8e10059 100755
--- a/configure
+++ b/configure
@@ -1216,7 +1216,10 @@ case "$cpu" in
cc_i386='$(CC) -m32'
;;
x86_64)
- CPU_CFLAGS="-m64"
+ # ??? Only extremely old AMD cpus do not have cmpxchg16b.
+ # If we truly care, we should simply detect this case at
+ # runtime and generate the fallback to serial emulation.
+ CPU_CFLAGS="-m64 -mcx16"
LDFLAGS="-m64 $LDFLAGS"
cc_i386='$(CC) -m32'
;;
@@ -3911,6 +3914,36 @@ if compile_prog "" "" ; then
setns=yes
fi
+# clock_adjtime probe
+clock_adjtime=no
+cat > $TMPC <<EOF
+#include <time.h>
+
+int main(void)
+{
+ return clock_adjtime(0, 0);
+}
+EOF
+clock_adjtime=no
+if compile_prog "" "" ; then
+ clock_adjtime=yes
+fi
+
+# syncfs probe
+syncfs=no
+cat > $TMPC <<EOF
+#include <unistd.h>
+
+int main(void)
+{
+ return syncfs(0);
+}
+EOF
+syncfs=no
+if compile_prog "" "" ; then
+ syncfs=yes
+fi
+
# Check if tools are available to build documentation.
if test "$docs" != "no" ; then
if has makeinfo && has pod2man; then
@@ -4491,6 +4524,55 @@ if compile_prog "" "" ; then
int128=yes
fi
+#########################################
+# See if 128-bit atomic operations are supported.
+
+atomic128=no
+if test "$int128" = "yes"; then
+ cat > $TMPC << EOF
+int main(void)
+{
+ unsigned __int128 x = 0, y = 0;
+ y = __atomic_load_16(&x, 0);
+ __atomic_store_16(&x, y, 0);
+ __atomic_compare_exchange_16(&x, &y, x, 0, 0, 0);
+ return 0;
+}
+EOF
+ if compile_prog "" "" ; then
+ atomic128=yes
+ fi
+fi
+
+#########################################
+# See if 64-bit atomic operations are supported.
+# Note that without __atomic builtins, we can only
+# assume atomic loads/stores max at pointer size.
+
+cat > $TMPC << EOF
+#include <stdint.h>
+int main(void)
+{
+ uint64_t x = 0, y = 0;
+#ifdef __ATOMIC_RELAXED
+ y = __atomic_load_8(&x, 0);
+ __atomic_store_8(&x, y, 0);
+ __atomic_compare_exchange_8(&x, &y, x, 0, 0, 0);
+ __atomic_exchange_8(&x, y, 0);
+ __atomic_fetch_add_8(&x, y, 0);
+#else
+ typedef char is_host64[sizeof(void *) >= sizeof(uint64_t) ? 1 : -1];
+ __sync_lock_test_and_set(&x, y);
+ __sync_val_compare_and_swap(&x, y, 0);
+ __sync_fetch_and_add(&x, y);
+#endif
+ return 0;
+}
+EOF
+if compile_prog "" "" ; then
+ atomic64=yes
+fi
+
########################################
# check if getauxval is available.
@@ -5196,6 +5278,12 @@ fi
if test "$setns" = "yes" ; then
echo "CONFIG_SETNS=y" >> $config_host_mak
fi
+if test "$clock_adjtime" = "yes" ; then
+ echo "CONFIG_CLOCK_ADJTIME=y" >> $config_host_mak
+fi
+if test "$syncfs" = "yes" ; then
+ echo "CONFIG_SYNCFS=y" >> $config_host_mak
+fi
if test "$inotify" = "yes" ; then
echo "CONFIG_INOTIFY=y" >> $config_host_mak
fi
@@ -5447,6 +5535,14 @@ if test "$int128" = "yes" ; then
echo "CONFIG_INT128=y" >> $config_host_mak
fi
+if test "$atomic128" = "yes" ; then
+ echo "CONFIG_ATOMIC128=y" >> $config_host_mak
+fi
+
+if test "$atomic64" = "yes" ; then
+ echo "CONFIG_ATOMIC64=y" >> $config_host_mak
+fi
+
if test "$getauxval" = "yes" ; then
echo "CONFIG_GETAUXVAL=y" >> $config_host_mak
fi
diff --git a/cpu-exec-common.c b/cpu-exec-common.c
index 0cb4ae6..767d9c6 100644
--- a/cpu-exec-common.c
+++ b/cpu-exec-common.c
@@ -77,3 +77,9 @@ void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc)
}
siglongjmp(cpu->jmp_env, 1);
}
+
+void cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc)
+{
+ cpu->exception_index = EXCP_ATOMIC;
+ cpu_loop_exit_restore(cpu, pc);
+}
diff --git a/cpu-exec.c b/cpu-exec.c
index e114fcd..9400732 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -151,12 +151,6 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu,
TranslationBlock *itb)
&& qemu_log_in_addr_range(itb->pc)) {
#if defined(TARGET_I386)
log_cpu_state(cpu, CPU_DUMP_CCOP);
-#elif defined(TARGET_M68K)
- /* ??? Should not modify env state for dumping. */
- cpu_m68k_flush_flags(env, env->cc_op);
- env->cc_op = CC_OP_FLAGS;
- env->sr = (env->sr & 0xffe0) | env->cc_dest | (env->cc_x << 4);
- log_cpu_state(cpu, 0);
#else
log_cpu_state(cpu, 0);
#endif
@@ -222,6 +216,36 @@ static void cpu_exec_nocache(CPUState *cpu, int max_cycles,
}
#endif
+static void cpu_exec_step(CPUState *cpu)
+{
+ CPUArchState *env = (CPUArchState *)cpu->env_ptr;
+ TranslationBlock *tb;
+ target_ulong cs_base, pc;
+ uint32_t flags;
+
+ cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
+ tb = tb_gen_code(cpu, pc, cs_base, flags,
+ 1 | CF_NOCACHE | CF_IGNORE_ICOUNT);
+ tb->orig_tb = NULL;
+ /* execute the generated code */
+ trace_exec_tb_nocache(tb, pc);
+ cpu_tb_exec(cpu, tb);
+ tb_phys_invalidate(tb, -1);
+ tb_free(tb);
+}
+
+void cpu_exec_step_atomic(CPUState *cpu)
+{
+ start_exclusive();
+
+ /* Since we got here, we know that parallel_cpus must be true. */
+ parallel_cpus = false;
+ cpu_exec_step(cpu);
+ parallel_cpus = true;
+
+ end_exclusive();
+}
+
struct tb_desc {
target_ulong pc;
target_ulong cs_base;
diff --git a/cpus.c b/cpus.c
index 31204bb..cfd5cdc 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1497,6 +1497,8 @@ static void tcg_exec_all(void)
if (r == EXCP_DEBUG) {
cpu_handle_guest_debug(cpu);
break;
+ } else if (r == EXCP_ATOMIC) {
+ cpu_exec_step_atomic(cpu);
}
} else if (cpu->stop || cpu->stopped) {
if (cpu->unplug) {
diff --git a/cputlb.c b/cputlb.c
index 3c99c34..cc4da4d 100644
--- a/cputlb.c
+++ b/cputlb.c
@@ -23,15 +23,15 @@
#include "exec/memory.h"
#include "exec/address-spaces.h"
#include "exec/cpu_ldst.h"
-
#include "exec/cputlb.h"
-
#include "exec/memory-internal.h"
#include "exec/ram_addr.h"
#include "exec/exec-all.h"
#include "tcg/tcg.h"
#include "qemu/error-report.h"
#include "exec/log.h"
+#include "exec/helper-proto.h"
+#include "qemu/atomic.h"
/* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */
/* #define DEBUG_TLB */
@@ -498,6 +498,43 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1,
target_ulong addr)
return qemu_ram_addr_from_host_nofail(p);
}
+static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
+ target_ulong addr, uintptr_t retaddr, int size)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ hwaddr physaddr = iotlbentry->addr;
+ MemoryRegion *mr = iotlb_to_region(cpu, physaddr, iotlbentry->attrs);
+ uint64_t val;
+
+ physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
+ cpu->mem_io_pc = retaddr;
+ if (mr != &io_mem_rom && mr != &io_mem_notdirty && !cpu->can_do_io) {
+ cpu_io_recompile(cpu, retaddr);
+ }
+
+ cpu->mem_io_vaddr = addr;
+ memory_region_dispatch_read(mr, physaddr, &val, size, iotlbentry->attrs);
+ return val;
+}
+
+static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
+ uint64_t val, target_ulong addr,
+ uintptr_t retaddr, int size)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ hwaddr physaddr = iotlbentry->addr;
+ MemoryRegion *mr = iotlb_to_region(cpu, physaddr, iotlbentry->attrs);
+
+ physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
+ if (mr != &io_mem_rom && mr != &io_mem_notdirty && !cpu->can_do_io) {
+ cpu_io_recompile(cpu, retaddr);
+ }
+
+ cpu->mem_io_vaddr = addr;
+ cpu->mem_io_pc = retaddr;
+ memory_region_dispatch_write(mr, physaddr, val, size, iotlbentry->attrs);
+}
+
/* Return true if ADDR is present in the victim tlb, and has been copied
back to the main tlb. */
static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index,
@@ -527,34 +564,178 @@ static bool victim_tlb_hit(CPUArchState *env, size_t
mmu_idx, size_t index,
victim_tlb_hit(env, mmu_idx, index, offsetof(CPUTLBEntry, TY), \
(ADDR) & TARGET_PAGE_MASK)
+/* Probe for whether the specified guest write access is permitted.
+ * If it is not permitted then an exception will be taken in the same
+ * way as if this were a real write access (and we will not return).
+ * Otherwise the function will return, and there will be a valid
+ * entry in the TLB for this access.
+ */
+void probe_write(CPUArchState *env, target_ulong addr, int mmu_idx,
+ uintptr_t retaddr)
+{
+ int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+ target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
+
+ if ((addr & TARGET_PAGE_MASK)
+ != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+ /* TLB entry is for a different page */
+ if (!VICTIM_TLB_HIT(addr_write, addr)) {
+ tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr);
+ }
+ }
+}
+
+/* Probe for a read-modify-write atomic operation. Do not allow unaligned
+ * operations, or io operations to proceed. Return the host address. */
+static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
+ TCGMemOpIdx oi, uintptr_t retaddr)
+{
+ size_t mmu_idx = get_mmuidx(oi);
+ size_t index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+ CPUTLBEntry *tlbe = &env->tlb_table[mmu_idx][index];
+ target_ulong tlb_addr = tlbe->addr_write;
+ TCGMemOp mop = get_memop(oi);
+ int a_bits = get_alignment_bits(mop);
+ int s_bits = mop & MO_SIZE;
+
+ /* Adjust the given return address. */
+ retaddr -= GETPC_ADJ;
+
+ /* Enforce guest required alignment. */
+ if (unlikely(a_bits > 0 && (addr & ((1 << a_bits) - 1)))) {
+ /* ??? Maybe indicate atomic op to cpu_unaligned_access */
+ cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
+ mmu_idx, retaddr);
+ }
+
+ /* Enforce qemu required alignment. */
+ if (unlikely(addr & ((1 << s_bits) - 1))) {
+ /* We get here if guest alignment was not requested,
+ or was not enforced by cpu_unaligned_access above.
+ We might widen the access and emulate, but for now
+ mark an exception and exit the cpu loop. */
+ goto stop_the_world;
+ }
+
+ /* Check TLB entry and enforce page permissions. */
+ if ((addr & TARGET_PAGE_MASK)
+ != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+ if (!VICTIM_TLB_HIT(addr_write, addr)) {
+ tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr);
+ }
+ tlb_addr = tlbe->addr_write;
+ }
+
+ /* Notice an IO access, or a notdirty page. */
+ if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) {
+ /* There's really nothing that can be done to
+ support this apart from stop-the-world. */
+ goto stop_the_world;
+ }
+
+ /* Let the guest notice RMW on a write-only page. */
+ if (unlikely(tlbe->addr_read != tlb_addr)) {
+ tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_LOAD, mmu_idx, retaddr);
+ /* Since we don't support reads and writes to different addresses,
+ and we do have the proper page loaded for write, this shouldn't
+ ever return. But just in case, handle via stop-the-world. */
+ goto stop_the_world;
+ }
+
+ return (void *)((uintptr_t)addr + tlbe->addend);
+
+ stop_the_world:
+ cpu_loop_exit_atomic(ENV_GET_CPU(env), retaddr);
+}
+
+#ifdef TARGET_WORDS_BIGENDIAN
+# define TGT_BE(X) (X)
+# define TGT_LE(X) BSWAP(X)
+#else
+# define TGT_BE(X) BSWAP(X)
+# define TGT_LE(X) (X)
+#endif
+
#define MMUSUFFIX _mmu
-#define SHIFT 0
+#define DATA_SIZE 1
#include "softmmu_template.h"
-#define SHIFT 1
+#define DATA_SIZE 2
#include "softmmu_template.h"
-#define SHIFT 2
+#define DATA_SIZE 4
#include "softmmu_template.h"
-#define SHIFT 3
+#define DATA_SIZE 8
#include "softmmu_template.h"
-#undef MMUSUFFIX
+/* First set of helpers allows passing in of OI and RETADDR. This makes
+ them callable from other helpers. */
+
+#define EXTRA_ARGS , TCGMemOpIdx oi, uintptr_t retaddr
+#define ATOMIC_NAME(X) \
+ HELPER(glue(glue(glue(atomic_ ## X, SUFFIX), END), _mmu))
+#define ATOMIC_MMU_LOOKUP atomic_mmu_lookup(env, addr, oi, retaddr)
+
+#define DATA_SIZE 1
+#include "atomic_template.h"
+
+#define DATA_SIZE 2
+#include "atomic_template.h"
+
+#define DATA_SIZE 4
+#include "atomic_template.h"
+
+#ifdef CONFIG_ATOMIC64
+#define DATA_SIZE 8
+#include "atomic_template.h"
+#endif
+
+#ifdef CONFIG_ATOMIC128
+#define DATA_SIZE 16
+#include "atomic_template.h"
+#endif
+
+/* Second set of helpers are directly callable from TCG as helpers. */
+
+#undef EXTRA_ARGS
+#undef ATOMIC_NAME
+#undef ATOMIC_MMU_LOOKUP
+#define EXTRA_ARGS , TCGMemOpIdx oi
+#define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END))
+#define ATOMIC_MMU_LOOKUP atomic_mmu_lookup(env, addr, oi, GETPC())
+
+#define DATA_SIZE 1
+#include "atomic_template.h"
+
+#define DATA_SIZE 2
+#include "atomic_template.h"
+
+#define DATA_SIZE 4
+#include "atomic_template.h"
+
+#ifdef CONFIG_ATOMIC64
+#define DATA_SIZE 8
+#include "atomic_template.h"
+#endif
+
+/* Code access functions. */
+
+#undef MMUSUFFIX
#define MMUSUFFIX _cmmu
#undef GETPC
#define GETPC() ((uintptr_t)0)
#define SOFTMMU_CODE_ACCESS
-#define SHIFT 0
+#define DATA_SIZE 1
#include "softmmu_template.h"
-#define SHIFT 1
+#define DATA_SIZE 2
#include "softmmu_template.h"
-#define SHIFT 2
+#define DATA_SIZE 4
#include "softmmu_template.h"
-#define SHIFT 3
+#define DATA_SIZE 8
#include "softmmu_template.h"
diff --git a/default-configs/unicore32-linux-user.mak
b/default-configs/unicore32-linux-user.mak
deleted file mode 100644
index 6aafd21..0000000
--- a/default-configs/unicore32-linux-user.mak
+++ /dev/null
@@ -1 +0,0 @@
-# Default configuration for unicore32-linux-user
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |