aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--MAINTAINERS18
-rw-r--r--Makefile2
-rw-r--r--accel/tcg/translate-all.c5
-rw-r--r--audio/rate_template.h6
-rw-r--r--backends/hostmem-ram.c2
-rw-r--r--backends/rng-egd.c2
-rw-r--r--block.c191
-rw-r--r--block/Makefile.objs2
-rw-r--r--block/backup.c12
-rw-r--r--block/blkdebug.c5
-rw-r--r--block/block-backend.c5
-rw-r--r--block/commit.c4
-rw-r--r--block/crypto.c101
-rw-r--r--block/crypto.h101
-rw-r--r--block/dirty-bitmap.c154
-rw-r--r--block/file-posix.c201
-rw-r--r--block/file-win32.c9
-rw-r--r--block/gluster.c11
-rw-r--r--block/io.c50
-rw-r--r--block/iscsi.c15
-rw-r--r--block/mirror.c3
-rw-r--r--block/nbd-client.c22
-rw-r--r--block/nbd-client.h3
-rw-r--r--block/nbd.c16
-rw-r--r--block/nfs.c21
-rw-r--r--block/parallels.c13
-rw-r--r--block/qapi.c2
-rw-r--r--block/qcow.c277
-rw-r--r--block/qcow2-bitmap.c1482
-rw-r--r--block/qcow2-cluster.c66
-rw-r--r--block/qcow2-refcount.c346
-rw-r--r--block/qcow2.c1235
-rw-r--r--block/qcow2.h69
-rw-r--r--block/qed-cluster.c4
-rw-r--r--block/qed-l2-cache.c6
-rw-r--r--block/qed-table.c24
-rw-r--r--block/qed.c229
-rw-r--r--block/qed.h11
-rw-r--r--block/raw-format.c31
-rw-r--r--block/rbd.c15
-rw-r--r--block/sheepdog.c32
-rw-r--r--block/ssh.c28
-rw-r--r--block/vdi.c51
-rw-r--r--block/vhdx-log.c2
-rw-r--r--block/vhdx.c8
-rw-r--r--block/vmdk.c7
-rw-r--r--block/vpc.c22
-rw-r--r--block/vvfat.c8
-rw-r--r--blockdev.c114
-rw-r--r--bsd-user/qemu.h2
-rw-r--r--chardev/char-fe.c16
-rw-r--r--chardev/char-mux.c1
-rw-r--r--chardev/char-socket.c6
-rw-r--r--chardev/char.c164
-rwxr-xr-xconfigure12
-rw-r--r--cpus.c2
-rw-r--r--crypto/block-luks.c8
-rw-r--r--crypto/block-qcow.c8
-rw-r--r--crypto/block.c6
-rw-r--r--crypto/blockpriv.h2
-rw-r--r--docs/devel/memory.txt31
-rw-r--r--docs/interop/qcow2.txt111
-rw-r--r--exec.c70
-rw-r--r--gdb-xml/s390-gs.xml14
-rw-r--r--gdbstub.c119
-rw-r--r--hmp-commands-info.hx16
-rw-r--r--hmp-commands.hx36
-rw-r--r--hmp.c65
-rw-r--r--hmp.h1
-rw-r--r--hw/9pfs/9p.c2
-rw-r--r--hw/alpha/typhoon.c31
-rw-r--r--hw/arm/aspeed.c2
-rw-r--r--hw/arm/aspeed_soc.c2
-rw-r--r--hw/arm/exynos4210.c2
-rw-r--r--hw/arm/exynos4_boards.c2
-rw-r--r--hw/arm/fsl-imx25.c5
-rw-r--r--hw/arm/fsl-imx31.c5
-rw-r--r--hw/arm/fsl-imx6.c5
-rw-r--r--hw/arm/highbank.c8
-rw-r--r--hw/arm/imx25_pdk.c6
-rw-r--r--hw/arm/integratorcp.c2
-rw-r--r--hw/arm/kzm.c6
-rw-r--r--hw/arm/mainstone.c1
-rw-r--r--hw/arm/musicpal.c1
-rw-r--r--hw/arm/omap1.c1
-rw-r--r--hw/arm/omap2.c1
-rw-r--r--hw/arm/omap_sx1.c6
-rw-r--r--hw/arm/palm.c1
-rw-r--r--hw/arm/pxa2xx.c7
-rw-r--r--hw/arm/realview.c3
-rw-r--r--hw/arm/spitz.c1
-rw-r--r--hw/arm/stellaris.c2
-rw-r--r--hw/arm/stm32f205_soc.c3
-rw-r--r--hw/arm/strongarm.c4
-rw-r--r--hw/arm/tosa.c1
-rw-r--r--hw/arm/vexpress.c3
-rw-r--r--hw/arm/virt.c4
-rw-r--r--hw/arm/xilinx_zynq.c1
-rw-r--r--hw/arm/xlnx-zynqmp.c1
-rw-r--r--hw/audio/adlib.c14
-rw-r--r--hw/audio/fmopl.c18
-rw-r--r--hw/audio/fmopl.h7
-rw-r--r--hw/block/onenand.c2
-rw-r--r--hw/block/pflash_cfi01.c1
-rw-r--r--hw/block/pflash_cfi02.c1
-rw-r--r--hw/block/virtio-blk.c6
-rw-r--r--hw/char/bcm2835_aux.c2
-rw-r--r--hw/char/cadence_uart.c4
-rw-r--r--hw/char/debugcon.c4
-rw-r--r--hw/char/digic-uart.c2
-rw-r--r--hw/char/escc.c8
-rw-r--r--hw/char/etraxfs_ser.c2
-rw-r--r--hw/char/exynos4210_uart.c4
-rw-r--r--hw/char/grlib_apbuart.c4
-rw-r--r--hw/char/imx_serial.c2
-rw-r--r--hw/char/ipoctal232.c4
-rw-r--r--hw/char/lm32_juart.c2
-rw-r--r--hw/char/lm32_uart.c2
-rw-r--r--hw/char/mcf_uart.c2
-rw-r--r--hw/char/milkymist-uart.c2
-rw-r--r--hw/char/parallel.c8
-rw-r--r--hw/char/pl011.c2
-rw-r--r--hw/char/sclpconsole-lm.c4
-rw-r--r--hw/char/sclpconsole.c4
-rw-r--r--hw/char/serial.c63
-rw-r--r--hw/char/sh_serial.c4
-rw-r--r--hw/char/spapr_vty.c4
-rw-r--r--hw/char/stm32f2xx_usart.c3
-rw-r--r--hw/char/terminal3270.c4
-rw-r--r--hw/char/virtio-console.c35
-rw-r--r--hw/char/xen_console.c4
-rw-r--r--hw/char/xilinx_uartlite.c2
-rw-r--r--hw/core/loader.c5
-rw-r--r--hw/core/machine.c10
-rw-r--r--hw/core/qdev-properties-system.c8
-rw-r--r--hw/core/qdev-properties.c73
-rw-r--r--hw/core/qdev.c31
-rw-r--r--hw/cris/axis_dev88.c5
-rw-r--r--hw/display/cg3.c3
-rw-r--r--hw/display/qxl.c3
-rw-r--r--hw/display/sm501.c2
-rw-r--r--hw/display/tc6393xb.c1
-rw-r--r--hw/display/tcx.c4
-rw-r--r--hw/display/vga.c2
-rw-r--r--hw/display/vmware_vga.c1
-rw-r--r--hw/display/xlnx_dp.c2
-rw-r--r--hw/dma/rc4030.c34
-rw-r--r--hw/dma/xilinx_axidma.c4
-rw-r--r--hw/i386/acpi-build.c10
-rw-r--r--hw/i386/amd_iommu.c33
-rw-r--r--hw/i386/amd_iommu.h5
-rw-r--r--hw/i386/intel_iommu.c42
-rw-r--r--hw/i386/kvm/pci-assign.c6
-rw-r--r--hw/i386/kvmvapic.c85
-rw-r--r--hw/i386/pc.c14
-rw-r--r--hw/i386/pc_piix.c8
-rw-r--r--hw/i386/pc_q35.c6
-rw-r--r--hw/i386/pc_sysfw.c2
-rw-r--r--hw/i386/pci-assign-load-rom.c2
-rw-r--r--hw/i386/xen/xen-hvm.c1
-rw-r--r--hw/input/milkymist-softusb.c4
-rw-r--r--hw/intc/s390_flic.c107
-rw-r--r--hw/intc/s390_flic_kvm.c137
-rw-r--r--hw/intc/trace-events4
-rw-r--r--hw/ipmi/ipmi.c2
-rw-r--r--hw/ipmi/ipmi_bmc_extern.c4
-rw-r--r--hw/m68k/an5206.c1
-rw-r--r--hw/m68k/mcf5208.c1
-rw-r--r--hw/mem/pc-dimm.c30
-rw-r--r--hw/microblaze/petalogix_ml605_mmu.c2
-rw-r--r--hw/microblaze/petalogix_s3adsp1800_mmu.c2
-rw-r--r--hw/mips/boston.c4
-rw-r--r--hw/mips/mips_fulong2e.c1
-rw-r--r--hw/mips/mips_jazz.c4
-rw-r--r--hw/mips/mips_malta.c9
-rw-r--r--hw/mips/mips_mipssim.c1
-rw-r--r--hw/mips/mips_r4k.c1
-rw-r--r--hw/misc/aspeed_sdmc.c8
-rw-r--r--hw/misc/ivshmem.c30
-rw-r--r--hw/misc/mips_cmgcr.c16
-rw-r--r--hw/moxie/moxiesim.c4
-rw-r--r--hw/net/dp8393x.c2
-rw-r--r--hw/net/milkymist-minimac2.c2
-rw-r--r--hw/net/xilinx_axienet.c4
-rw-r--r--hw/nios2/10m50_devboard.c8
-rw-r--r--hw/nvram/fw_cfg.c2
-rw-r--r--hw/openrisc/openrisc_sim.c1
-rw-r--r--hw/pci-host/apb.c29
-rw-r--r--hw/pci-host/piix.c2
-rw-r--r--hw/pci-host/prep.c2
-rw-r--r--hw/pci-host/xilinx-pcie.c2
-rw-r--r--hw/pci/pci-stub.c3
-rw-r--r--hw/pci/pci.c1
-rw-r--r--hw/ppc/mac_newworld.c1
-rw-r--r--hw/ppc/mac_oldworld.c1
-rw-r--r--hw/ppc/pnv.c6
-rw-r--r--hw/ppc/ppc405_boards.c3
-rw-r--r--hw/ppc/ppc405_uc.c1
-rw-r--r--hw/ppc/spapr.c243
-rw-r--r--hw/ppc/spapr_drc.c405
-rw-r--r--hw/ppc/spapr_events.c98
-rw-r--r--hw/ppc/spapr_hcall.c439
-rw-r--r--hw/ppc/spapr_iommu.c44
-rw-r--r--hw/ppc/spapr_pci.c17
-rw-r--r--hw/ppc/spapr_rng.c8
-rw-r--r--hw/ppc/trace-events5
-rw-r--r--hw/s390x/Makefile.objs2
-rw-r--r--hw/s390x/css-bridge.c2
-rw-r--r--hw/s390x/css.c200
-rw-r--r--hw/s390x/s390-pci-bus.c36
-rw-r--r--hw/s390x/s390-pci-bus.h3
-rw-r--r--hw/s390x/s390-pci-inst.c11
-rw-r--r--hw/s390x/s390-stattrib-kvm.c190
-rw-r--r--hw/s390x/s390-stattrib.c404
-rw-r--r--hw/s390x/s390-virtio-ccw.c90
-rw-r--r--hw/s390x/sclp.c1
-rw-r--r--hw/s390x/trace-events1
-rw-r--r--hw/s390x/virtio-ccw.c11
-rw-r--r--hw/scsi/scsi-bus.c6
-rw-r--r--hw/scsi/virtio-scsi.c13
-rw-r--r--hw/sh4/r2d.c1
-rw-r--r--hw/sh4/shix.c3
-rw-r--r--hw/sparc/leon3.c1
-rw-r--r--hw/sparc/sun4m.c6
-rw-r--r--hw/sparc64/sun4u.c4
-rw-r--r--hw/tricore/tricore_testboard.c26
-rw-r--r--hw/unicore32/puv3.c1
-rw-r--r--hw/usb/ccid-card-passthru.c6
-rw-r--r--hw/usb/dev-serial.c7
-rw-r--r--hw/usb/dev-smartcard-reader.c6
-rw-r--r--hw/usb/redirect.c9
-rw-r--r--hw/vfio/common.c12
-rw-r--r--hw/vfio/spapr.c3
-rw-r--r--hw/virtio/virtio-crypto-pci.c2
-rw-r--r--hw/virtio/virtio-crypto.c27
-rw-r--r--hw/virtio/virtio-pci.c6
-rw-r--r--hw/virtio/virtio-rng.c12
-rw-r--r--hw/xtensa/sim.c4
-rw-r--r--hw/xtensa/xtfpga.c4
-rw-r--r--include/block/block.h11
-rw-r--r--include/block/block_int.h24
-rw-r--r--include/block/dirty-bitmap.h22
-rw-r--r--include/block/nbd.h58
-rw-r--r--include/chardev/char-fe.h22
-rw-r--r--include/chardev/char.h19
-rw-r--r--include/crypto/block.h6
-rw-r--r--include/elf.h1
-rw-r--r--include/exec/exec-all.h3
-rw-r--r--include/exec/gdbstub.h9
-rw-r--r--include/exec/memory.h256
-rw-r--r--include/hw/boards.h29
-rw-r--r--include/hw/i386/intel_iommu.h5
-rw-r--r--include/hw/mips/mips.h2
-rw-r--r--include/hw/misc/unimp.h2
-rw-r--r--include/hw/ppc/pnv_psi.h2
-rw-r--r--include/hw/ppc/spapr.h31
-rw-r--r--include/hw/ppc/spapr_drc.h74
-rw-r--r--include/hw/ppc/spapr_ovec.h1
-rw-r--r--include/hw/ptimer.h120
-rw-r--r--include/hw/qdev-core.h6
-rw-r--r--include/hw/qdev-properties.h62
-rw-r--r--include/hw/s390x/css.h27
-rw-r--r--include/hw/s390x/s390-virtio-ccw.h10
-rw-r--r--include/hw/s390x/s390_flic.h14
-rw-r--r--include/hw/s390x/sclp.h3
-rw-r--r--include/hw/s390x/storage-attributes.h81
-rw-r--r--include/hw/vfio/vfio-common.h2
-rw-r--r--include/monitor/monitor.h7
-rw-r--r--include/qapi/error.h12
-rw-r--r--include/qemu/coroutine.h18
-rw-r--r--include/qemu/error-report.h7
-rw-r--r--include/qemu/hbitmap.h49
-rw-r--r--include/qemu/osdep.h2
-rw-r--r--include/qemu/sockets.h15
-rw-r--r--include/qemu/typedefs.h1
-rw-r--r--include/qom/cpu.h3
-rw-r--r--include/qom/object.h6
-rw-r--r--include/standard-headers/asm-x86/hyperv.h21
-rw-r--r--include/standard-headers/linux/input-event-codes.h1
-rw-r--r--include/standard-headers/linux/pci_regs.h1
-rw-r--r--include/sysemu/block-backend.h3
-rw-r--r--io/channel-websock.c4
-rw-r--r--io/dns-resolver.c6
-rw-r--r--linux-headers/asm-arm/kvm.h8
-rw-r--r--linux-headers/asm-arm64/kvm.h3
-rw-r--r--linux-headers/asm-powerpc/kvm.h6
-rw-r--r--linux-headers/asm-s390/kvm.h12
-rw-r--r--linux-headers/linux/kvm.h35
-rw-r--r--linux-user/syscall.c1
-rw-r--r--memory.c223
-rw-r--r--monitor.c75
-rw-r--r--nbd/client.c283
-rw-r--r--nbd/common.c92
-rw-r--r--nbd/nbd-internal.h13
-rw-r--r--nbd/server.c304
-rw-r--r--nbd/trace-events25
-rw-r--r--net/colo-compare.c10
-rw-r--r--net/filter-mirror.c8
-rw-r--r--net/slirp.c2
-rw-r--r--net/tap-linux.c2
-rw-r--r--net/vhost-user.c7
-rw-r--r--numa.c4
-rw-r--r--pc-bios/efi-e1000.rombin209920 -> 240128 bytes
-rw-r--r--pc-bios/efi-e1000e.rombin209920 -> 240128 bytes
-rw-r--r--pc-bios/efi-eepro100.rombin209920 -> 240128 bytes
-rw-r--r--pc-bios/efi-ne2k_pci.rombin208896 -> 238080 bytes
-rw-r--r--pc-bios/efi-pcnet.rombin208896 -> 238080 bytes
-rw-r--r--pc-bios/efi-rtl8139.rombin212480 -> 241664 bytes
-rw-r--r--pc-bios/efi-virtio.rombin212480 -> 242176 bytes
-rw-r--r--pc-bios/efi-vmxnet3.rombin206848 -> 236032 bytes
-rw-r--r--pc-bios/openbios-ppcbin750840 -> 754936 bytes
-rw-r--r--pc-bios/openbios-sparc32bin382048 -> 382048 bytes
-rw-r--r--pc-bios/openbios-sparc64bin1593408 -> 1593408 bytes
-rw-r--r--pc-bios/s390-ccw.imgbin26480 -> 30520 bytes
-rw-r--r--pc-bios/s390-ccw/Makefile13
-rw-r--r--pc-bios/s390-ccw/bootmap.c2
-rw-r--r--pc-bios/s390-ccw/bootmap.h26
-rw-r--r--pc-bios/s390-ccw/bswap.h30
-rw-r--r--pc-bios/s390-ccw/libc.h45
-rw-r--r--pc-bios/s390-ccw/main.c14
-rw-r--r--pc-bios/s390-ccw/netboot.mak59
-rw-r--r--pc-bios/s390-ccw/netmain.c361
-rw-r--r--pc-bios/s390-ccw/s390-ccw.h33
-rw-r--r--pc-bios/s390-ccw/sclp.c37
-rw-r--r--pc-bios/s390-ccw/virtio-blkdev.c296
-rw-r--r--pc-bios/s390-ccw/virtio-net.c135
-rw-r--r--pc-bios/s390-ccw/virtio-scsi.c1
-rw-r--r--pc-bios/s390-ccw/virtio.c306
-rw-r--r--pc-bios/s390-ccw/virtio.h46
-rwxr-xr-xpc-bios/s390-netboot.imgbin0 -> 83864 bytes
-rwxr-xr-xpc-bios/u-boot.e500bin347788 -> 388672 bytes
-rw-r--r--qapi-schema.json50
-rw-r--r--qapi/block-core.json197
-rw-r--r--qapi/common.json5
-rw-r--r--qemu-doc.texi123
-rw-r--r--qemu-img-cmds.hx6
-rw-r--r--qemu-img.c304
-rw-r--r--qemu-img.texi56
-rw-r--r--qemu-io-cmds.c2
-rw-r--r--qemu-io.c20
-rw-r--r--qemu-nbd.c10
-rw-r--r--qemu-options.hx4
-rw-r--r--qga/commands-win32.c5
-rw-r--r--qmp.c17
-rw-r--r--qom/cpu.c1
-rw-r--r--qom/object.c8
-rw-r--r--qtest.c2
m---------roms/SLOF0
m---------roms/ipxe0
m---------roms/openbios0
m---------roms/u-boot0
-rwxr-xr-xscripts/checkpatch.pl7
-rw-r--r--scripts/coccinelle/memory-region-init-ram.cocci38
-rw-r--r--scripts/coccinelle/qobject.cocci6
-rw-r--r--scripts/hxtool46
-rw-r--r--scripts/qapi-commands.py8
-rw-r--r--scripts/qapi-event.py12
-rw-r--r--scripts/qapi.py2
-rw-r--r--slirp/ip6.h6
-rw-r--r--slirp/misc.c4
-rw-r--r--slirp/sbuf.c2
-rw-r--r--slirp/socket.c52
-rw-r--r--target/i386/cpu.c24
-rw-r--r--target/i386/kvm.c12
-rw-r--r--target/mips/translate.c8
-rw-r--r--target/ppc/kvm.c76
-rw-r--r--target/ppc/kvm_ppc.h26
-rw-r--r--target/ppc/mmu-hash64.h4
-rw-r--r--target/ppc/translate_init.c12
-rw-r--r--target/s390x/arch_dump.c18
-rw-r--r--target/s390x/cpu.h8
-rw-r--r--target/s390x/cpu_features.c54
-rw-r--r--target/s390x/cpu_features.h4
-rw-r--r--target/s390x/cpu_features_def.h77
-rw-r--r--target/s390x/cpu_models.c57
-rw-r--r--target/s390x/cpu_models.h2
-rw-r--r--target/s390x/gdbstub.c24
-rw-r--r--target/s390x/gen-features.c105
-rw-r--r--target/s390x/kvm.c169
-rw-r--r--target/s390x/machine.c17
-rw-r--r--target/xtensa/gdbstub.c1
-rw-r--r--target/xtensa/xtensa-semi.c2
-rw-r--r--tests/Makefile.include4
-rw-r--r--tests/docker/Makefile.include5
-rwxr-xr-xtests/docker/docker.py23
-rwxr-xr-xtests/multiboot/run_test.sh10
-rwxr-xr-xtests/qemu-iotests/03312
-rwxr-xr-xtests/qemu-iotests/0422
-rw-r--r--tests/qemu-iotests/044.out2
-rwxr-xr-xtests/qemu-iotests/0482
-rwxr-xr-xtests/qemu-iotests/0492
-rw-r--r--tests/qemu-iotests/049.out102
-rwxr-xr-xtests/qemu-iotests/0517
-rwxr-xr-xtests/qemu-iotests/0682
-rw-r--r--tests/qemu-iotests/082.out284
-rw-r--r--tests/qemu-iotests/085.out38
-rwxr-xr-xtests/qemu-iotests/08739
-rw-r--r--tests/qemu-iotests/087.out16
-rwxr-xr-xtests/qemu-iotests/10692
-rw-r--r--tests/qemu-iotests/106.out50
-rwxr-xr-xtests/qemu-iotests/1201
-rwxr-xr-xtests/qemu-iotests/125130
-rw-r--r--tests/qemu-iotests/125.out386
-rwxr-xr-xtests/qemu-iotests/126105
-rw-r--r--tests/qemu-iotests/126.out23
-rwxr-xr-xtests/qemu-iotests/13420
-rw-r--r--tests/qemu-iotests/134.out10
-rwxr-xr-xtests/qemu-iotests/1409
-rwxr-xr-xtests/qemu-iotests/14248
-rw-r--r--tests/qemu-iotests/144.out4
-rwxr-xr-xtests/qemu-iotests/14519
-rwxr-xr-xtests/qemu-iotests/14925
-rw-r--r--tests/qemu-iotests/149.out880
-rwxr-xr-xtests/qemu-iotests/15717
-rw-r--r--tests/qemu-iotests/157.out16
-rwxr-xr-xtests/qemu-iotests/15821
-rw-r--r--tests/qemu-iotests/158.out14
-rwxr-xr-xtests/qemu-iotests/1591
-rwxr-xr-xtests/qemu-iotests/165105
-rw-r--r--tests/qemu-iotests/165.out5
-rwxr-xr-xtests/qemu-iotests/1701
-rwxr-xr-xtests/qemu-iotests/17114
-rwxr-xr-xtests/qemu-iotests/1742
-rwxr-xr-xtests/qemu-iotests/178170
-rw-r--r--tests/qemu-iotests/178.out.qcow2286
-rw-r--r--tests/qemu-iotests/178.out.raw158
-rwxr-xr-xtests/qemu-iotests/18123
-rw-r--r--tests/qemu-iotests/185.out8
-rwxr-xr-xtests/qemu-iotests/18876
-rw-r--r--tests/qemu-iotests/188.out18
-rwxr-xr-xtests/qemu-iotests/18986
-rw-r--r--tests/qemu-iotests/189.out26
-rwxr-xr-xtests/qemu-iotests/check23
-rw-r--r--tests/qemu-iotests/common10
-rw-r--r--tests/qemu-iotests/common.config11
-rw-r--r--tests/qemu-iotests/common.filter3
-rw-r--r--tests/qemu-iotests/common.qemu9
-rw-r--r--tests/qemu-iotests/common.rc3
-rw-r--r--tests/qemu-iotests/group7
-rwxr-xr-xtests/rocker/all10
-rw-r--r--tests/tcg/cris/Makefile8
-rw-r--r--tests/test-char.c275
-rw-r--r--tests/test-crypto-block.c8
-rw-r--r--tests/test-hbitmap.c19
-rw-r--r--tests/test-hmp.c1
-rw-r--r--tests/test-qdev-global-props.c6
-rw-r--r--tests/vhost-user-test.c2
-rw-r--r--tests/vmgenid-test.c46
-rw-r--r--trace/control.c8
-rw-r--r--util/error.c20
-rw-r--r--util/hbitmap.c51
-rw-r--r--util/oslib-posix.c66
-rw-r--r--util/oslib-win32.c24
-rw-r--r--util/qemu-coroutine-lock.c35
-rw-r--r--util/qemu-error.c106
-rw-r--r--util/qemu-sockets.c105
-rw-r--r--vl.c28
458 files changed, 14798 insertions, 4051 deletions
diff --git a/.travis.yml b/.travis.yml
index 27a2d9cfb3..3c7a5cbe25 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -86,6 +86,9 @@ matrix:
- env: CONFIG="--enable-trace-backends=ust"
TEST_CMD=""
compiler: gcc
+ - env: CONFIG="--disable-tcg"
+ TEST_CMD=""
+ compiler: gcc
- env: CONFIG=""
os: osx
compiler: clang
diff --git a/MAINTAINERS b/MAINTAINERS
index 9529c9484c..b9aa878b84 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -84,14 +84,10 @@ M: Paolo Bonzini <pbonzini@redhat.com>
M: Peter Crosthwaite <crosthwaite.peter@gmail.com>
M: Richard Henderson <rth@twiddle.net>
S: Maintained
-F: cpu-exec.c
-F: cpu-exec-common.c
F: cpus.c
-F: cputlb.c
F: exec.c
F: softmmu_template.h
-F: translate-all.*
-F: translate-common.c
+F: accel/tcg/
F: include/exec/cpu*.h
F: include/exec/exec-all.h
F: include/exec/helper*.h
@@ -277,8 +273,8 @@ Overall
M: Paolo Bonzini <pbonzini@redhat.com>
L: kvm@vger.kernel.org
S: Supported
-F: kvm-*
F: */kvm.*
+F: accel/kvm/
F: include/sysemu/kvm*.h
ARM
@@ -327,7 +323,6 @@ M: Stefano Stabellini <sstabellini@kernel.org>
M: Anthony Perard <anthony.perard@citrix.com>
L: xen-devel@lists.xenproject.org
S: Supported
-F: xen-*
F: */xen*
F: hw/9pfs/xen-9p-backend.c
F: hw/char/xen_console.c
@@ -1160,6 +1155,13 @@ F: docs/specs/vmgenid.txt
F: tests/vmgenid-test.c
F: stubs/vmgenid.c
+Unimplemented device
+M: Peter Maydell <peter.maydell@linaro.org>
+R: Philippe Mathieu-Daudé <f4bug@amsat.org>
+S: Maintained
+F: include/hw/misc/unimp.h
+F: hw/misc/unimp.c
+
Subsystems
----------
Audio
@@ -1650,7 +1652,7 @@ TCI target
M: Stefan Weil <sw@weilnetz.de>
S: Maintained
F: tcg/tci/
-F: tci.c
+F: tcg/tci.c
F: disas/tci.c
Block drivers
diff --git a/Makefile b/Makefile
index 16a0430c6c..38814f9a61 100644
--- a/Makefile
+++ b/Makefile
@@ -553,7 +553,7 @@ efi-e1000e.rom efi-vmxnet3.rom \
qemu-icon.bmp qemu_logo_no_text.svg \
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin \
-s390-ccw.img \
+s390-ccw.img s390-netboot.img \
spapr-rtas.bin slof.bin skiboot.lid \
palcode-clipper \
u-boot.e500 \
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 0caf80db75..4e1831cbb9 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1851,11 +1851,6 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
tb_lock();
- if (!tcg_enabled()) {
- cpu_fprintf(f, "TCG not enabled\n");
- return;
- }
-
target_code_size = 0;
max_target_code_size = 0;
cross_page = 0;
diff --git a/audio/rate_template.h b/audio/rate_template.h
index bd4b1c7685..6e93588877 100644
--- a/audio/rate_template.h
+++ b/audio/rate_template.h
@@ -71,6 +71,12 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
while (rate->ipos <= (rate->opos >> 32)) {
ilast = *ibuf++;
rate->ipos++;
+
+ /* if ipos overflow, there is a infinite loop */
+ if (rate->ipos == 0xffffffff) {
+ rate->ipos = 1;
+ rate->opos = rate->opos & 0xffffffff;
+ }
/* See if we finished the input buffer yet */
if (ibuf >= iend) {
goto the_end;
diff --git a/backends/hostmem-ram.c b/backends/hostmem-ram.c
index 04a7ac362b..38977be73e 100644
--- a/backends/hostmem-ram.c
+++ b/backends/hostmem-ram.c
@@ -28,7 +28,7 @@ ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
}
path = object_get_canonical_path_component(OBJECT(backend));
- memory_region_init_ram(&backend->mr, OBJECT(backend), path,
+ memory_region_init_ram_nomigrate(&backend->mr, OBJECT(backend), path,
backend->size, errp);
g_free(path);
}
diff --git a/backends/rng-egd.c b/backends/rng-egd.c
index e7ce2cac80..d2b9ce6cbf 100644
--- a/backends/rng-egd.c
+++ b/backends/rng-egd.c
@@ -106,7 +106,7 @@ static void rng_egd_opened(RngBackend *b, Error **errp)
/* FIXME we should resubmit pending requests when the CDS reconnects. */
qemu_chr_fe_set_handlers(&s->chr, rng_egd_chr_can_read,
- rng_egd_chr_read, NULL, s, NULL, true);
+ rng_egd_chr_read, NULL, NULL, s, NULL, true);
}
static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
diff --git a/block.c b/block.c
index 694396281b..98a9209371 100644
--- a/block.c
+++ b/block.c
@@ -2185,6 +2185,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
ret = -EINVAL;
goto free_exit;
}
+ bdrv_set_aio_context(backing_hd, bdrv_get_aio_context(bs));
/* Hook up the backing file link; drop our reference, bs owns the
* backing_hd reference now */
@@ -2573,15 +2574,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
goto close_and_fail;
}
- if (!bdrv_key_required(bs)) {
- bdrv_parent_cb_change_media(bs, true);
- } else if (!runstate_check(RUN_STATE_PRELAUNCH)
- && !runstate_check(RUN_STATE_INMIGRATE)
- && !runstate_check(RUN_STATE_PAUSED)) { /* HACK */
- error_setg(errp,
- "Guest must be stopped for opening of encrypted image");
- goto close_and_fail;
- }
+ bdrv_parent_cb_change_media(bs, true);
QDECREF(options);
@@ -2989,24 +2982,45 @@ error:
void bdrv_reopen_commit(BDRVReopenState *reopen_state)
{
BlockDriver *drv;
+ BlockDriverState *bs;
+ bool old_can_write, new_can_write;
assert(reopen_state != NULL);
- drv = reopen_state->bs->drv;
+ bs = reopen_state->bs;
+ drv = bs->drv;
assert(drv != NULL);
+ old_can_write =
+ !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE);
+
/* If there are any driver level actions to take */
if (drv->bdrv_reopen_commit) {
drv->bdrv_reopen_commit(reopen_state);
}
/* set BDS specific flags now */
- QDECREF(reopen_state->bs->explicit_options);
+ QDECREF(bs->explicit_options);
- reopen_state->bs->explicit_options = reopen_state->explicit_options;
- reopen_state->bs->open_flags = reopen_state->flags;
- reopen_state->bs->read_only = !(reopen_state->flags & BDRV_O_RDWR);
+ bs->explicit_options = reopen_state->explicit_options;
+ bs->open_flags = reopen_state->flags;
+ bs->read_only = !(reopen_state->flags & BDRV_O_RDWR);
- bdrv_refresh_limits(reopen_state->bs, NULL);
+ bdrv_refresh_limits(bs, NULL);
+
+ new_can_write =
+ !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE);
+ if (!old_can_write && new_can_write && drv->bdrv_reopen_bitmaps_rw) {
+ Error *local_err = NULL;
+ if (drv->bdrv_reopen_bitmaps_rw(bs, &local_err) < 0) {
+ /* This is not fatal, bitmaps just left read-only, so all following
+ * writes will fail. User can remove read-only bitmaps to unblock
+ * writes.
+ */
+ error_reportf_err(local_err,
+ "%s: Failed to make dirty bitmaps writable: ",
+ bdrv_get_node_name(bs));
+ }
+ }
}
/*
@@ -3040,9 +3054,6 @@ static void bdrv_close(BlockDriverState *bs)
bdrv_flush(bs);
bdrv_drain(bs); /* in case flush left pending I/O */
- bdrv_release_named_dirty_bitmaps(bs);
- assert(QLIST_EMPTY(&bs->dirty_bitmaps));
-
if (bs->drv) {
BdrvChild *child, *next;
@@ -3072,7 +3083,6 @@ static void bdrv_close(BlockDriverState *bs)
bs->backing_format[0] = '\0';
bs->total_sectors = 0;
bs->encrypted = false;
- bs->valid_key = false;
bs->sg = false;
QDECREF(bs->options);
QDECREF(bs->explicit_options);
@@ -3081,6 +3091,9 @@ static void bdrv_close(BlockDriverState *bs)
bs->full_open_options = NULL;
}
+ bdrv_release_named_dirty_bitmaps(bs);
+ assert(QLIST_EMPTY(&bs->dirty_bitmaps));
+
QLIST_FOREACH_SAFE(ban, &bs->aio_notifiers, list, ban_next) {
g_free(ban);
}
@@ -3398,7 +3411,8 @@ exit:
/**
* Truncate file to 'offset' bytes (needed only for file protocols)
*/
-int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp)
+int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
+ Error **errp)
{
BlockDriverState *bs = child->bs;
BlockDriver *drv = bs->drv;
@@ -3421,7 +3435,7 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp)
assert(!(bs->open_flags & BDRV_O_INACTIVE));
- ret = drv->bdrv_truncate(bs, offset, errp);
+ ret = drv->bdrv_truncate(bs, offset, prealloc, errp);
if (ret == 0) {
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
bdrv_dirty_bitmap_truncate(bs);
@@ -3450,6 +3464,41 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
return -ENOTSUP;
}
+/*
+ * bdrv_measure:
+ * @drv: Format driver
+ * @opts: Creation options for new image
+ * @in_bs: Existing image containing data for new image (may be NULL)
+ * @errp: Error object
+ * Returns: A #BlockMeasureInfo (free using qapi_free_BlockMeasureInfo())
+ * or NULL on error
+ *
+ * Calculate file size required to create a new image.
+ *
+ * If @in_bs is given then space for allocated clusters and zero clusters
+ * from that image are included in the calculation. If @opts contains a
+ * backing file that is shared by @in_bs then backing clusters may be omitted
+ * from the calculation.
+ *
+ * If @in_bs is NULL then the calculation includes no allocated clusters
+ * unless a preallocation option is given in @opts.
+ *
+ * Note that @in_bs may use a different BlockDriver from @drv.
+ *
+ * If an error occurs the @errp pointer is set.
+ */
+BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts,
+ BlockDriverState *in_bs, Error **errp)
+{
+ if (!drv->bdrv_measure) {
+ error_setg(errp, "Block driver '%s' does not support size measurement",
+ drv->format_name);
+ return NULL;
+ }
+
+ return drv->bdrv_measure(opts, in_bs, errp);
+}
+
/**
* Return number of sectors on success, -errno on error.
*/
@@ -3502,72 +3551,6 @@ bool bdrv_is_encrypted(BlockDriverState *bs)
return bs->encrypted;
}
-bool bdrv_key_required(BlockDriverState *bs)
-{
- BdrvChild *backing = bs->backing;
-
- if (backing && backing->bs->encrypted && !backing->bs->valid_key) {
- return true;
- }
- return (bs->encrypted && !bs->valid_key);
-}
-
-int bdrv_set_key(BlockDriverState *bs, const char *key)
-{
- int ret;
- if (bs->backing && bs->backing->bs->encrypted) {
- ret = bdrv_set_key(bs->backing->bs, key);
- if (ret < 0)
- return ret;
- if (!bs->encrypted)
- return 0;
- }
- if (!bs->encrypted) {
- return -EINVAL;
- } else if (!bs->drv || !bs->drv->bdrv_set_key) {
- return -ENOMEDIUM;
- }
- ret = bs->drv->bdrv_set_key(bs, key);
- if (ret < 0) {
- bs->valid_key = false;
- } else if (!bs->valid_key) {
- /* call the change callback now, we skipped it on open */
- bs->valid_key = true;
- bdrv_parent_cb_change_media(bs, true);
- }
- return ret;
-}
-
-/*
- * Provide an encryption key for @bs.
- * If @key is non-null:
- * If @bs is not encrypted, fail.
- * Else if the key is invalid, fail.
- * Else set @bs's key to @key, replacing the existing key, if any.
- * If @key is null:
- * If @bs is encrypted and still lacks a key, fail.
- * Else do nothing.
- * On failure, store an error object through @errp if non-null.
- */
-void bdrv_add_key(BlockDriverState *bs, const char *key, Error **errp)
-{
- if (key) {
- if (!bdrv_is_encrypted(bs)) {
- error_setg(errp, "Node '%s' is not encrypted",
- bdrv_get_device_or_node_name(bs));
- } else if (bdrv_set_key(bs, key) < 0) {
- error_setg(errp, QERR_INVALID_PASSWORD);
- }
- } else {
- if (bdrv_key_required(bs)) {
- error_set(errp, ERROR_CLASS_DEVICE_ENCRYPTED,
- "'%s' (%s) is encrypted",
- bdrv_get_device_or_node_name(bs),
- bdrv_get_encrypted_filename(bs));
- }
- }
-}
-
const char *bdrv_get_format_name(BlockDriverState *bs)
{
return bs->drv ? bs->drv->format_name : NULL;
@@ -4135,6 +4118,10 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs,
}
}
+ /* At this point persistent bitmaps should be already stored by the format
+ * driver */
+ bdrv_release_persistent_dirty_bitmaps(bs);
+
return 0;
}
@@ -4267,11 +4254,9 @@ bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp)
assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
if (!QLIST_EMPTY(&bs->op_blockers[op])) {
blocker = QLIST_FIRST(&bs->op_blockers[op]);
- if (errp) {
- *errp = error_copy(blocker->reason);
- error_prepend(errp, "Node '%s' is busy: ",
- bdrv_get_device_or_node_name(bs));
- }
+ error_propagate(errp, error_copy(blocker->reason));
+ error_prepend(errp, "Node '%s' is busy: ",
+ bdrv_get_device_or_node_name(bs));
return true;
}
return false;
@@ -4933,3 +4918,25 @@ void bdrv_del_child(BlockDriverState *parent_bs, BdrvChild *child, Error **errp)
parent_bs->drv->bdrv_del_child(parent_bs, child, errp);
}
+
+bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
+ uint32_t granularity, Error **errp)
+{
+ BlockDriver *drv = bs->drv;
+
+ if (!drv) {
+ error_setg_errno(errp, ENOMEDIUM,
+ "Can't store persistent bitmaps to %s",
+ bdrv_get_device_or_node_name(bs));
+ return false;
+ }
+
+ if (!drv->bdrv_can_store_new_dirty_bitmap) {
+ error_setg_errno(errp, ENOTSUP,
+ "Can't store persistent bitmaps to %s",
+ bdrv_get_device_or_node_name(bs));
+ return false;
+ }
+
+ return drv->bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp);
+}
diff --git a/block/Makefile.objs b/block/Makefile.objs
index f9368b52b8..2aaede4ae1 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -1,5 +1,5 @@
block-obj-y += raw-format.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o
-block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
+block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o qcow2-bitmap.o
block-obj-y += qed.o qed-l2-cache.o qed-table.o qed-cluster.o
block-obj-y += qed-check.o
block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
diff --git a/block/backup.c b/block/backup.c
index b69184eac5..504a089150 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -639,12 +639,12 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
ret = bdrv_get_info(target, &bdi);
if (ret == -ENOTSUP && !target->backing) {
/* Cluster size is not defined */
- error_report("WARNING: The target block device doesn't provide "
- "information about the block size and it doesn't have a "
- "backing file. The default block size of %u bytes is "
- "used. If the actual block size of the target exceeds "
- "this default, the backup may be unusable",
- BACKUP_CLUSTER_SIZE_DEFAULT);
+ warn_report("The target block device doesn't provide "
+ "information about the block size and it doesn't have a "
+ "backing file. The default block size of %u bytes is "
+ "used. If the actual block size of the target exceeds "
+ "this default, the backup may be unusable",
+ BACKUP_CLUSTER_SIZE_DEFAULT);
job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
} else if (ret < 0 && !target->backing) {
error_setg_errno(errp, -ret,
diff --git a/block/blkdebug.c b/block/blkdebug.c
index b25856c49c..c19ab28f07 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -821,9 +821,10 @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
return bdrv_getlength(bs->file->bs);
}
-static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
+static int blkdebug_truncate(BlockDriverState *bs, int64_t offset,
+ PreallocMode prealloc, Error **errp)
{
- return bdrv_truncate(bs->file, offset, errp);
+ return bdrv_truncate(bs->file, offset, prealloc, errp);
}
static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
diff --git a/block/block-backend.c b/block/block-backend.c
index 0df3457a09..fe3542b3f8 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1773,14 +1773,15 @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
BDRV_REQ_WRITE_COMPRESSED);
}
-int blk_truncate(BlockBackend *blk, int64_t offset, Error **errp)
+int blk_truncate(BlockBackend *blk, int64_t offset, PreallocMode prealloc,
+ Error **errp)
{
if (!blk_is_available(blk)) {
error_setg(errp, "No medium inserted");
return -ENOMEDIUM;
}
- return bdrv_truncate(blk->root, offset, errp);
+ return bdrv_truncate(blk->root, offset, prealloc, errp);
}
static void blk_pdiscard_entry(void *opaque)
diff --git a/block/commit.c b/block/commit.c
index 774a8a599c..13143608f8 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -163,7 +163,7 @@ static void coroutine_fn commit_run(void *opaque)
}
if (base_len < s->common.len) {
- ret = blk_truncate(s->base, s->common.len, NULL);
+ ret = blk_truncate(s->base, s->common.len, PREALLOC_MODE_OFF, NULL);
if (ret) {
goto out;
}
@@ -521,7 +521,7 @@ int bdrv_commit(BlockDriverState *bs)
* grow the backing file image if possible. If not possible,
* we must return an error */
if (length > backing_length) {
- ret = blk_truncate(backing, length, &local_err);
+ ret = blk_truncate(backing, length, PREALLOC_MODE_OFF, &local_err);
if (ret < 0) {
error_report_err(local_err);
goto ro_cleanup;
diff --git a/block/crypto.c b/block/crypto.c
index 10e5ddccaa..58ef6f2f52 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -24,16 +24,10 @@
#include "sysemu/block-backend.h"
#include "crypto/block.h"
#include "qapi/opts-visitor.h"
+#include "qapi/qobject-input-visitor.h"
#include "qapi-visit.h"
#include "qapi/error.h"
-
-#define BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET "key-secret"
-#define BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG "cipher-alg"
-#define BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE "cipher-mode"
-#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG "ivgen-alg"
-#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg"
-#define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg"
-#define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time"
+#include "block/crypto.h"
typedef struct BlockCrypto BlockCrypto;
@@ -135,11 +129,7 @@ static QemuOptsList block_crypto_runtime_opts_luks = {
.name = "crypto",
.head = QTAILQ_HEAD_INITIALIZER(block_crypto_runtime_opts_luks.head),
.desc = {
- {
- .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
- .type = QEMU_OPT_STRING,
- .help = "ID of the secret that provides the encryption key",
- },
+ BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""),
{ /* end of list */ }
},
};
@@ -154,49 +144,21 @@ static QemuOptsList block_crypto_create_opts_luks = {
.type = QEMU_OPT_SIZE,
.help = "Virtual disk size"
},
- {
- .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
- .type = QEMU_OPT_STRING,
- .help = "ID of the secret that provides the encryption key",
- },
- {
- .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG,
- .type = QEMU_OPT_STRING,
- .help = "Name of encryption cipher algorithm",
- },
- {
- .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE,
- .type = QEMU_OPT_STRING,
- .help = "Name of encryption cipher mode",
- },
- {
- .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG,
- .type = QEMU_OPT_STRING,
- .help = "Name of IV generator algorithm",
- },
- {
- .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG,
- .type = QEMU_OPT_STRING,
- .help = "Name of IV generator hash algorithm",
- },
- {
- .name = BLOCK_CRYPTO_OPT_LUKS_HASH_ALG,
- .type = QEMU_OPT_STRING,
- .help = "Name of encryption hash algorithm",
- },
- {
- .name = BLOCK_CRYPTO_OPT_LUKS_ITER_TIME,
- .type = QEMU_OPT_NUMBER,
- .help = "Time to spend in PBKDF in milliseconds",
- },
+ BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""),
+ BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG(""),
+ BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE(""),
+ BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG(""),
+ BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG(""),
+ BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG(""),
+ BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""),
{ /* end of list */ }
},
};
-static QCryptoBlockOpenOptions *
+QCryptoBlockOpenOptions *
block_crypto_open_opts_init(QCryptoBlockFormat format,
- QemuOpts *opts,
+ QDict *opts,
Error **errp)
{
Visitor *v;
@@ -206,7 +168,7 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
ret = g_new0(QCryptoBlockOpenOptions, 1);
ret->format = format;
- v = opts_visitor_new(opts);
+ v = qobject_input_visitor_new_keyval(QOBJECT(opts));
visit_start_struct(v, NULL, NULL, 0, &local_err);
if (local_err) {
@@ -219,6 +181,11 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
v, &ret->u.luks, &local_err);
break;
+ case Q_CRYPTO_BLOCK_FORMAT_QCOW:
+ visit_type_QCryptoBlockOptionsQCow_members(
+ v, &ret->u.qcow, &local_err);
+ break;
+
default:
error_setg(&local_err, "Unsupported block format %d", format);
break;
@@ -240,9 +207,9 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
}
-static QCryptoBlockCreateOptions *
+QCryptoBlockCreateOptions *
block_crypto_create_opts_init(QCryptoBlockFormat format,
- QemuOpts *opts,
+ QDict *opts,
Error **errp)
{
Visitor *v;
@@ -252,7 +219,7 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
ret = g_new0(QCryptoBlockCreateOptions, 1);
ret->format = format;
- v = opts_visitor_new(opts);
+ v = qobject_input_visitor_new_keyval(QOBJECT(opts));
visit_start_struct(v, NULL, NULL, 0, &local_err);
if (local_err) {
@@ -265,6 +232,11 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
v, &ret->u.luks, &local_err);
break;
+ case Q_CRYPTO_BLOCK_FORMAT_QCOW:
+ visit_type_QCryptoBlockOptionsQCow_members(
+ v, &ret->u.qcow, &local_err);
+ break;
+
default:
error_setg(&local_err, "Unsupported block format %d", format);
break;
@@ -299,6 +271,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
int ret = -EINVAL;
QCryptoBlockOpenOptions *open_opts = NULL;
unsigned int cflags = 0;
+ QDict *cryptoopts = NULL;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
false, errp);
@@ -313,7 +286,9 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
goto cleanup;
}
- open_opts = block_crypto_open_opts_init(format, opts, errp);
+ cryptoopts = qemu_opts_to_qdict(opts, NULL);
+
+ open_opts = block_crypto_open_opts_init(format, cryptoopts, errp);
if (!open_opts) {
goto cleanup;
}
@@ -321,7 +296,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
if (flags & BDRV_O_NO_IO) {
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
}
- crypto->block = qcrypto_block_open(open_opts,
+ crypto->block = qcrypto_block_open(open_opts, NULL,
block_crypto_read_func,
bs,
cflags,
@@ -333,10 +308,10 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
}
bs->encrypted = true;
- bs->valid_key = true;
ret = 0;
cleanup:
+ QDECREF(cryptoopts);
qapi_free_QCryptoBlockOpenOptions(open_opts);
return ret;
}
@@ -356,13 +331,16 @@ static int block_crypto_create_generic(QCryptoBlockFormat format,
.opts = opts,
.filename = filename,
};
+ QDict *cryptoopts;
+
+ cryptoopts = qemu_opts_to_qdict(opts, NULL);
- create_opts = block_crypto_create_opts_init(format, opts, errp);
+ create_opts = block_crypto_create_opts_init(format, cryptoopts, errp);
if (!create_opts) {
return -1;
}
- crypto = qcrypto_block_create(create_opts,
+ crypto = qcrypto_block_create(create_opts, NULL,
block_crypto_init_func,
block_crypto_write_func,
&data,
@@ -375,6 +353,7 @@ static int block_crypto_create_generic(QCryptoBlockFormat format,
ret = 0;
cleanup:
+ QDECREF(cryptoopts);
qcrypto_block_free(crypto);
blk_unref(data.blk);
qapi_free_QCryptoBlockCreateOptions(create_opts);
@@ -382,7 +361,7 @@ static int block_crypto_create_generic(QCryptoBlockFormat format,
}
static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
- Error **errp)
+ PreallocMode prealloc, Error **errp)
{
BlockCrypto *crypto = bs->opaque;
size_t payload_offset =
@@ -390,7 +369,7 @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
offset += payload_offset;
- return bdrv_truncate(bs->file, offset, errp);
+ return bdrv_truncate(bs->file, offset, prealloc, errp);
}
static void block_crypto_close(BlockDriverState *bs)
diff --git a/block/crypto.h b/block/crypto.h
new file mode 100644
index 0000000000..0f985ea4e2
--- /dev/null
+++ b/block/crypto.h
@@ -0,0 +1,101 @@
+/*
+ * QEMU block full disk encryption
+ *
+ * Copyright (c) 2015-2017 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/>.
+ *
+ */
+
+#ifndef BLOCK_CRYPTO_H__
+#define BLOCK_CRYPTO_H__
+
+#define BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, helpstr) \
+ { \
+ .name = prefix BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET, \
+ .type = QEMU_OPT_STRING, \
+ .help = helpstr, \
+ }
+
+#define BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET "key-secret"
+
+#define BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET(prefix) \
+ BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, \
+ "ID of the secret that provides the AES encryption key")
+
+#define BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET "key-secret"
+#define BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG "cipher-alg"
+#define BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE "cipher-mode"
+#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG "ivgen-alg"
+#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg"
+#define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg"
+#define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time"
+
+#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(prefix) \
+ BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, \
+ "ID of the secret that provides the keyslot passphrase")
+
+#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG(prefix) \
+ { \
+ .name = prefix BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG, \
+ .type = QEMU_OPT_STRING, \
+ .help = "Name of encryption cipher algorithm", \
+ }
+
+#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE(prefix) \
+ { \
+ .name = prefix BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE, \
+ .type = QEMU_OPT_STRING, \
+ .help = "Name of encryption cipher mode", \
+ }
+
+#define BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG(prefix) \
+ { \
+ .name = prefix BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG, \
+ .type = QEMU_OPT_STRING, \
+ .help = "Name of IV generator algorithm", \
+ }
+
+#define BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG(prefix) \
+ { \
+ .name = prefix BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG, \
+ .type = QEMU_OPT_STRING, \
+ .help = "Name of IV generator hash algorithm", \
+ }
+
+#define BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG(prefix) \
+ { \
+ .name = prefix BLOCK_CRYPTO_OPT_LUKS_HASH_ALG, \
+ .type = QEMU_OPT_STRING, \
+ .help = "Name of encryption hash algorithm", \
+ }
+
+#define BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(prefix) \
+ { \
+ .name = prefix BLOCK_CRYPTO_OPT_LUKS_ITER_TIME, \
+ .type = QEMU_OPT_NUMBER, \
+ .help = "Time to spend in PBKDF in milliseconds", \
+ }
+
+QCryptoBlockCreateOptions *
+block_crypto_create_opts_init(QCryptoBlockFormat format,
+ QDict *opts,
+ Error **errp);
+
+QCryptoBlockOpenOptions *
+block_crypto_open_opts_init(QCryptoBlockFormat format,
+ QDict *opts,
+ Error **errp);
+
+#endif /* BLOCK_CRYPTO_H__ */
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index a04c6e4154..543bddb9b5 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -43,8 +43,18 @@ struct BdrvDirtyBitmap {
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 */
+ bool disabled; /* Bitmap is disabled. It ignores all writes to
+ the device */
int active_iterators; /* How many iterators are active */
+ bool readonly; /* Bitmap is read-only. This field also
+ prevents the respective image from being
+ modified (i.e. blocks writes and discards).
+ Such operations must fail and both the image
+ and this bitmap must remain unchanged while
+ this flag is set. */
+ bool autoload; /* For persistent bitmaps: bitmap must be
+ autoloaded on image opening */
+ bool persistent; /* bitmap must be saved to owner disk image */
QLIST_ENTRY(BdrvDirtyBitmap) list;
};
@@ -93,6 +103,8 @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
assert(!bdrv_dirty_bitmap_frozen(bitmap));
g_free(bitmap->name);
bitmap->name = NULL;
+ bitmap->persistent = false;
+ bitmap->autoload = false;
}
/* Called with BQL taken. */
@@ -289,6 +301,10 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
bitmap->name = NULL;
successor->name = name;
bitmap->successor = NULL;
+ successor->persistent = bitmap->persistent;
+ bitmap->persistent = false;
+ successor->autoload = bitmap->autoload;
+ bitmap->autoload = false;
bdrv_release_dirty_bitmap(bs, bitmap);
return successor;
@@ -340,15 +356,20 @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
bdrv_dirty_bitmaps_unlock(bs);
}
+static bool bdrv_dirty_bitmap_has_name(BdrvDirtyBitmap *bitmap)
+{
+ return !!bdrv_dirty_bitmap_name(bitmap);
+}
+
/* Called with BQL taken. */
-static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
- BdrvDirtyBitmap *bitmap,
- bool only_named)
+static void bdrv_do_release_matching_dirty_bitmap(
+ BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
+ bool (*cond)(BdrvDirtyBitmap *bitmap))
{
BdrvDirtyBitmap *bm, *next;
bdrv_dirty_bitmaps_lock(bs);
QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
- if ((!bitmap || bm == bitmap) && (!only_named || bm->name)) {
+ if ((!bitmap || bm == bitmap) && (!cond || cond(bm))) {
assert(!bm->active_iterators);
assert(!bdrv_dirty_bitmap_frozen(bm));
assert(!bm->meta);
@@ -373,17 +394,47 @@ out:
/* Called with BQL taken. */
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
{
- bdrv_do_release_matching_dirty_bitmap(bs, bitmap, false);
+ bdrv_do_release_matching_dirty_bitmap(bs, bitmap, NULL);
}
/**
* Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()).
* There must not be any frozen bitmaps attached.
+ * This function does not remove persistent bitmaps from the storage.
* Called with BQL taken.
*/
void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs)
{
- bdrv_do_release_matching_dirty_bitmap(bs, NULL, true);
+ bdrv_do_release_matching_dirty_bitmap(bs, NULL, bdrv_dirty_bitmap_has_name);
+}
+
+/**
+ * Release all persistent dirty bitmaps attached to a BDS (for use in
+ * bdrv_inactivate_recurse()).
+ * There must not be any frozen bitmaps attached.
+ * This function does not remove persistent bitmaps from the storage.
+ */
+void bdrv_release_persistent_dirty_bitmaps(BlockDriverState *bs)
+{
+ bdrv_do_release_matching_dirty_bitmap(bs, NULL,
+ bdrv_dirty_bitmap_get_persistance);
+}
+
+/**
+ * Remove persistent dirty bitmap from the storage if it exists.
+ * Absence of bitmap is not an error, because we have the following scenario:
+ * BdrvDirtyBitmap can have .persistent = true but not yet saved and have no
+ * stored version. For such bitmap bdrv_remove_persistent_dirty_bitmap() should
+ * not fail.
+ * This function doesn't release corresponding BdrvDirtyBitmap.
+ */
+void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs,
+ const char *name,
+ Error **errp)
+{
+ if (bs->drv && bs->drv->bdrv_remove_persistent_dirty_bitmap) {
+ bs->drv->bdrv_remove_persistent_dirty_bitmap(bs, name, errp);
+ }
}
/* Called with BQL taken. */
@@ -455,7 +506,7 @@ uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
return granularity;
}
-uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap)
+uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap)
{
return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
}
@@ -504,6 +555,7 @@ void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors)
{
assert(bdrv_dirty_bitmap_enabled(bitmap));
+ assert(!bdrv_dirty_bitmap_readonly(bitmap));
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
}
@@ -520,6 +572,7 @@ void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors)
{
assert(bdrv_dirty_bitmap_enabled(bitmap));
+ assert(!bdrv_dirty_bitmap_readonly(bitmap));
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
}
@@ -534,6 +587,7 @@ void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
{
assert(bdrv_dirty_bitmap_enabled(bitmap));
+ assert(!bdrv_dirty_bitmap_readonly(bitmap));
bdrv_dirty_bitmap_lock(bitmap);
if (!out) {
hbitmap_reset_all(bitmap->bitmap);
@@ -550,6 +604,7 @@ void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
{
HBitmap *tmp = bitmap->bitmap;
assert(bdrv_dirty_bitmap_enabled(bitmap));
+ assert(!bdrv_dirty_bitmap_readonly(bitmap));
bitmap->bitmap = in;
hbitmap_free(tmp);
}
@@ -586,6 +641,13 @@ void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
hbitmap_deserialize_zeroes(bitmap->bitmap, start, count, finish);
}
+void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
+ uint64_t start, uint64_t count,
+ bool finish)
+{
+ hbitmap_deserialize_ones(bitmap->bitmap, start, count, finish);
+}
+
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
{
hbitmap_deserialize_finish(bitmap->bitmap);
@@ -605,6 +667,7 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
if (!bdrv_dirty_bitmap_enabled(bitmap)) {
continue;
}
+ assert(!bdrv_dirty_bitmap_readonly(bitmap));
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
}
bdrv_dirty_bitmaps_unlock(bs);
@@ -627,3 +690,78 @@ int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap)
{
return hbitmap_count(bitmap->meta);
}
+
+bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap)
+{
+ return bitmap->readonly;
+}
+
+/* Called with BQL taken. */
+void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value)
+{
+ qemu_mutex_lock(bitmap->mutex);
+ bitmap->readonly = value;
+ qemu_mutex_unlock(bitmap->mutex);
+}
+
+bool bdrv_has_readonly_bitmaps(BlockDriverState *bs)
+{
+ BdrvDirtyBitmap *bm;
+ QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
+ if (bm->readonly) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Called with BQL taken. */
+void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload)
+{
+ qemu_mutex_lock(bitmap->mutex);
+ bitmap->autoload = autoload;
+ qemu_mutex_unlock(bitmap->mutex);
+}
+
+bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap)
+{
+ return bitmap->autoload;
+}
+
+/* Called with BQL taken. */
+void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
+{
+ qemu_mutex_lock(bitmap->mutex);
+ bitmap->persistent = persistent;
+ qemu_mutex_unlock(bitmap->mutex);
+}
+
+bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap)
+{
+ return bitmap->persistent;
+}
+
+bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs)
+{
+ BdrvDirtyBitmap *bm;
+ QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
+ if (bm->persistent && !bm->readonly) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
+ BdrvDirtyBitmap *bitmap)
+{
+ return bitmap == NULL ? QLIST_FIRST(&bs->dirty_bitmaps) :
+ QLIST_NEXT(bitmap, list);
+}
+
+char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp)
+{
+ return hbitmap_sha256(bitmap->bitmap, errp);
+}
diff --git a/block/file-posix.c b/block/file-posix.c
index 3927fabf06..cfbb236f6f 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -1624,7 +1624,122 @@ static void raw_close(BlockDriverState *bs)
}
}
-static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
+/**
+ * Truncates the given regular file @fd to @offset and, when growing, fills the
+ * new space according to @prealloc.
+ *
+ * Returns: 0 on success, -errno on failure.
+ */
+static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc,
+ Error **errp)
+{
+ int result = 0;
+ int64_t current_length = 0;
+ char *buf = NULL;
+ struct stat st;
+
+ if (fstat(fd, &st) < 0) {
+ result = -errno;
+ error_setg_errno(errp, -result, "Could not stat file");
+ return result;
+ }
+
+ current_length = st.st_size;
+ if (current_length > offset && prealloc != PREALLOC_MODE_OFF) {
+ error_setg(errp, "Cannot use preallocation for shrinking files");
+ return -ENOTSUP;
+ }
+
+ switch (prealloc) {
+#ifdef CONFIG_POSIX_FALLOCATE
+ case PREALLOC_MODE_FALLOC:
+ /*
+ * Truncating before posix_fallocate() makes it about twice slower on
+ * file systems that do not support fallocate(), trying to check if a
+ * block is allocated before allocating it, so don't do that here.
+ */
+ result = -posix_fallocate(fd, current_length, offset - current_length);
+ if (result != 0) {
+ /* posix_fallocate() doesn't set errno. */
+ error_setg_errno(errp, -result,
+ "Could not preallocate new data");
+ }
+ goto out;
+#endif
+ case PREALLOC_MODE_FULL:
+ {
+ int64_t num = 0, left = offset - current_length;
+
+ /*
+ * Knowing the final size from the beginning could allow the file
+ * system driver to do less allocations and possibly avoid
+ * fragmentation of the file.
+ */
+ if (ftruncate(fd, offset) != 0) {
+ result = -errno;
+ error_setg_errno(errp, -result, "Could not resize file");
+ goto out;
+ }
+
+ buf = g_malloc0(65536);
+
+ result = lseek(fd, current_length, SEEK_SET);
+ if (result < 0) {
+ result = -errno;
+ error_setg_errno(errp, -result,
+ "Failed to seek to the old end of file");
+ goto out;
+ }
+
+ while (left > 0) {
+ num = MIN(left, 65536);
+ result = write(fd, buf, num);
+ if (result < 0) {
+ result = -errno;
+ error_setg_errno(errp, -result,
+ "Could not write zeros for preallocation");
+ goto out;
+ }
+ left -= result;
+ }
+ if (result >= 0) {
+ result = fsync(fd);
+ if (result < 0) {
+ result = -errno;
+ error_setg_errno(errp, -result,
+ "Could not flush file to disk");
+ goto out;
+ }
+ }
+ goto out;
+ }
+ case PREALLOC_MODE_OFF:
+ if (ftruncate(fd, offset) != 0) {
+ result = -errno;
+ error_setg_errno(errp, -result, "Could not resize file");
+ }
+ return result;
+ default:
+ result = -ENOTSUP;
+ error_setg(errp, "Unsupported preallocation mode: %s",
+ PreallocMode_lookup[prealloc]);
+ return result;
+ }
+
+out:
+ if (result < 0) {
+ if (ftruncate(fd, current_length) < 0) {
+ error_report("Failed to restore old file length: %s",
+ strerror(errno));
+ }
+ }
+
+ g_free(buf);
+ return result;
+}
+
+static int raw_truncate(BlockDriverState *bs, int64_t offset,
+ PreallocMode prealloc, Error **errp)
{
BDRVRawState *s = bs->opaque;
struct stat st;
@@ -1637,12 +1752,16 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
}
if (S_ISREG(st.st_mode)) {
- if (ftruncate(s->fd, offset) < 0) {
- ret = -errno;
- error_setg_errno(errp, -ret, "Failed to resize the file");
- return ret;
- }
- } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
+ return raw_regular_truncate(s->fd, offset, prealloc, errp);
+ }
+
+ if (prealloc != PREALLOC_MODE_OFF) {
+ error_setg(errp, "Preallocation mode '%s' unsupported for this "
+ "non-regular file", PreallocMode_lookup[prealloc]);
+ return -ENOTSUP;
+ }
+
+ if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
if (offset > raw_getlength(bs)) {
error_setg(errp, "Cannot grow device files");
return -EINVAL;
@@ -1885,71 +2004,9 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
#endif
}
- switch (prealloc) {
-#ifdef CONFIG_POSIX_FALLOCATE
- case PREALLOC_MODE_FALLOC:
- /*
- * Truncating before posix_fallocate() makes it about twice slower on
- * file systems that do not support fallocate(), trying to check if a
- * block is allocated before allocating it, so don't do that here.
- */
- result = -posix_fallocate(fd, 0, total_size);
- if (result != 0) {
- /* posix_fallocate() doesn't set errno. */
- error_setg_errno(errp, -result,
- "Could not preallocate data for the new file");
- }
- break;
-#endif
- case PREALLOC_MODE_FULL:
- {
- /*
- * Knowing the final size from the beginning could allow the file
- * system driver to do less allocations and possibly avoid
- * fragmentation of the file.
- */
- if (ftruncate(fd, total_size) != 0) {
- result = -errno;
- error_setg_errno(errp, -result, "Could not resize file");
- goto out_close;
- }
-
- int64_t num = 0, left = total_size;
- buf = g_malloc0(65536);
-
- while (left > 0) {
- num = MIN(left, 65536);
- result = write(fd, buf, num);
- if (result < 0) {
- result = -errno;
- error_setg_errno(errp, -result,
- "Could not write to the new file");
- break;
- }
- left -= result;
- }
- if (result >= 0) {
- result = fsync(fd);
- if (result < 0) {
- result = -errno;
- error_setg_errno(errp, -result,
- "Could not flush new file to disk");
- }
- }
- g_free(buf);
- break;
- }
- case PREALLOC_MODE_OFF:
- if (ftruncate(fd, total_size) != 0) {
- result = -errno;
- error_setg_errno(errp, -result, "Could not resize file");
- }
- break;
- default:
- result = -EINVAL;
- error_setg(errp, "Unsupported preallocation mode: %s",
- PreallocMode_lookup[prealloc]);
- break;
+ result = raw_regular_truncate(fd, total_size, prealloc, errp);
+ if (result < 0) {
+ goto out_close;
}
out_close:
diff --git a/block/file-win32.c b/block/file-win32.c
index ef2910b03f..4706335cff 100644
--- a/block/file-win32.c
+++ b/block/file-win32.c
@@ -461,12 +461,19 @@ static void raw_close(BlockDriverState *bs)
}
}
-static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
+static int raw_truncate(BlockDriverState *bs, int64_t offset,
+ PreallocMode prealloc, Error **errp)
{
BDRVRawState *s = bs->opaque;
LONG low, high;
DWORD dwPtrLow;
+ if (prealloc != PREALLOC_MODE_OFF) {
+ error_setg(errp, "Unsupported preallocation mode '%s'",
+ PreallocMode_lookup[prealloc]);
+ return -ENOTSUP;
+ }
+
low = offset;
high = offset >> 32;
diff --git a/block/gluster.c b/block/gluster.c
index addceed6eb..3064a45047 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -345,8 +345,7 @@ static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
is_unix = true;
} else if (!strcmp(uri->scheme, "gluster+rdma")) {
gsconf->type = SOCKET_ADDRESS_TYPE_INET;
- error_report("Warning: rdma feature is not supported, falling "
- "back to tcp");
+ warn_report("rdma feature is not supported, falling back to tcp");
} else {
ret = -EINVAL;
goto out;
@@ -1096,11 +1095,17 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
}
static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset,
- Error **errp)
+ PreallocMode prealloc, Error **errp)
{
int ret;
BDRVGlusterState *s = bs->opaque;
+ if (prealloc != PREALLOC_MODE_OFF) {
+ error_setg(errp, "Unsupported preallocation mode '%s'",
+ PreallocMode_lookup[prealloc]);
+ return -ENOTSUP;
+ }
+
ret = glfs_ftruncate(s->fd, offset);
if (ret < 0) {
ret = -errno;
diff --git a/block/io.c b/block/io.c
index 23170a57ee..aece54c015 100644
--- a/block/io.c
+++ b/block/io.c
@@ -149,6 +149,37 @@ bool bdrv_requests_pending(BlockDriverState *bs)
return false;
}
+typedef struct {
+ Coroutine *co;
+ BlockDriverState *bs;
+ bool done;
+} BdrvCoDrainData;
+
+static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
+{
+ BdrvCoDrainData *data = opaque;
+ BlockDriverState *bs = data->bs;
+
+ bs->drv->bdrv_co_drain(bs);
+
+ /* Set data->done before reading bs->wakeup. */
+ atomic_mb_set(&data->done, true);
+ bdrv_wakeup(bs);
+}
+
+static void bdrv_drain_invoke(BlockDriverState *bs)
+{
+ BdrvCoDrainData data = { .bs = bs, .done = false };
+
+ if (!bs->drv || !bs->drv->bdrv_co_drain) {
+ return;
+ }
+
+ data.co = qemu_coroutine_create(bdrv_drain_invoke_entry, &data);
+ bdrv_coroutine_enter(bs, data.co);
+ BDRV_POLL_WHILE(bs, !data.done);
+}
+
static bool bdrv_drain_recurse(BlockDriverState *bs)
{
BdrvChild *child, *tmp;
@@ -156,9 +187,8 @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0);
- if (bs->drv && bs->drv->bdrv_drain) {
- bs->drv->bdrv_drain(bs);
- }
+ /* Ensure any pending metadata writes are submitted to bs->file. */
+ bdrv_drain_invoke(bs);
QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
BlockDriverState *bs = child->bs;
@@ -184,12 +214,6 @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
return waited;
}
-typedef struct {
- Coroutine *co;
- BlockDriverState *bs;
- bool done;
-} BdrvCoDrainData;
-
static void bdrv_co_drain_bh_cb(void *opaque)
{
BdrvCoDrainData *data = opaque;
@@ -1315,6 +1339,10 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
uint64_t bytes_remaining = bytes;
int max_transfer;
+ if (bdrv_has_readonly_bitmaps(bs)) {
+ return -EPERM;
+ }
+
assert(is_power_of_2(align));
assert((offset & (align - 1)) == 0);
assert((bytes & (align - 1)) == 0);
@@ -2287,6 +2315,10 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
return -ENOMEDIUM;
}
+ if (bdrv_has_readonly_bitmaps(bs)) {
+ return -EPERM;
+ }
+
ret = bdrv_check_byte_request(bs, offset, bytes);
if (ret < 0) {
return ret;
diff --git a/block/iscsi.c b/block/iscsi.c
index 54067e2620..d557c99668 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -1761,9 +1761,9 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
* filename encoded options */
filename = qdict_get_try_str(options, "filename");
if (filename) {
- error_report("Warning: 'filename' option specified. "
- "This is an unsupported option, and may be deprecated "
- "in the future");
+ warn_report("'filename' option specified. "
+ "This is an unsupported option, and may be deprecated "
+ "in the future");
iscsi_parse_filename(filename, options, &local_err);
if (local_err) {
ret = -EINVAL;
@@ -2079,11 +2079,18 @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
}
}
-static int iscsi_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
+static int iscsi_truncate(BlockDriverState *bs, int64_t offset,
+ PreallocMode prealloc, Error **errp)
{
IscsiLun *iscsilun = bs->opaque;
Error *local_err = NULL;
+ if (prealloc != PREALLOC_MODE_OFF) {
+ error_setg(errp, "Unsupported preallocation mode '%s'",
+ PreallocMode_lookup[prealloc]);
+ return -ENOTSUP;
+ }
+
if (iscsilun->type != TYPE_DISK) {
error_setg(errp, "Cannot resize non-disk iSCSI devices");
return -ENOTSUP;
diff --git a/block/mirror.c b/block/mirror.c
index eaf0fe7858..8583b764a0 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -739,7 +739,8 @@ static void coroutine_fn mirror_run(void *opaque)
}
if (s->bdev_length > base_length) {
- ret = blk_truncate(s->target, s->bdev_length, NULL);
+ ret = blk_truncate(s->target, s->bdev_length, PREALLOC_MODE_OFF,
+ NULL);
if (ret < 0) {
goto immediate_exit;
}
diff --git a/block/nbd-client.c b/block/nbd-client.c
index 208f907095..25dd28406b 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -242,7 +242,7 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
ssize_t ret;
if (flags & BDRV_REQ_FUA) {
- assert(client->nbdflags & NBD_FLAG_SEND_FUA);
+ assert(client->info.flags & NBD_FLAG_SEND_FUA);
request.flags |= NBD_CMD_FLAG_FUA;
}
@@ -270,12 +270,12 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
};
NBDReply reply;
- if (!(client->nbdflags & NBD_FLAG_SEND_WRITE_ZEROES)) {
+ if (!(client->info.flags & NBD_FLAG_SEND_WRITE_ZEROES)) {
return -ENOTSUP;
}
if (flags & BDRV_REQ_FUA) {
- assert(client->nbdflags & NBD_FLAG_SEND_FUA);
+ assert(client->info.flags & NBD_FLAG_SEND_FUA);
request.flags |= NBD_CMD_FLAG_FUA;
}
if (!(flags & BDRV_REQ_MAY_UNMAP)) {
@@ -299,7 +299,7 @@ int nbd_client_co_flush(BlockDriverState *bs)
NBDReply reply;
ssize_t ret;
- if (!(client->nbdflags & NBD_FLAG_SEND_FLUSH)) {
+ if (!(client->info.flags & NBD_FLAG_SEND_FLUSH)) {
return 0;
}
@@ -327,7 +327,7 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
NBDReply reply;
ssize_t ret;
- if (!(client->nbdflags & NBD_FLAG_SEND_TRIM)) {
+ if (!(client->info.flags & NBD_FLAG_SEND_TRIM)) {
return 0;
}
@@ -384,22 +384,24 @@ int nbd_client_init(BlockDriverState *bs,
logout("session init %s\n", export);
qio_channel_set_blocking(QIO_CHANNEL(sioc), true, NULL);
+ client->info.request_sizes = true;
ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export,
- &client->nbdflags,
tlscreds, hostname,
- &client->ioc,
- &client->size, errp);
+ &client->ioc, &client->info, errp);
if (ret < 0) {
logout("Failed to negotiate with the NBD server\n");
return ret;
}
- if (client->nbdflags & NBD_FLAG_SEND_FUA) {
+ if (client->info.flags & NBD_FLAG_SEND_FUA) {
bs->supported_write_flags = BDRV_REQ_FUA;
bs->supported_zero_flags |= BDRV_REQ_FUA;
}
- if (client->nbdflags & NBD_FLAG_SEND_WRITE_ZEROES) {
+ if (client->info.flags & NBD_FLAG_SEND_WRITE_ZEROES) {
bs->supported_zero_flags |= BDRV_REQ_MAY_UNMAP;
}
+ if (client->info.min_block > bs->bl.request_alignment) {
+ bs->bl.request_alignment = client->info.min_block;
+ }
qemu_co_mutex_init(&client->send_mutex);
qemu_co_queue_init(&client->free_sema);
diff --git a/block/nbd-client.h b/block/nbd-client.h
index 49636bc621..df80771357 100644
--- a/block/nbd-client.h
+++ b/block/nbd-client.h
@@ -20,8 +20,7 @@
typedef struct NBDClientSession {
QIOChannelSocket *sioc; /* The master data channel */
QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
- uint16_t nbdflags;
- off_t size;
+ NBDExportInfo info;
CoMutex send_mutex;
CoQueue free_sema;
diff --git a/block/nbd.c b/block/nbd.c
index d529305330..a50d24b50a 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -472,9 +472,17 @@ static int nbd_co_flush(BlockDriverState *bs)
static void nbd_refresh_limits(BlockDriverState *bs, Error **errp)
{
- bs->bl.max_pdiscard = NBD_MAX_BUFFER_SIZE;
- bs->bl.max_pwrite_zeroes = NBD_MAX_BUFFER_SIZE;
- bs->bl.max_transfer = NBD_MAX_BUFFER_SIZE;
+ NBDClientSession *s = nbd_get_client_session(bs);
+ uint32_t max = MIN_NON_ZERO(NBD_MAX_BUFFER_SIZE, s->info.max_block);
+
+ bs->bl.max_pdiscard = max;
+ bs->bl.max_pwrite_zeroes = max;
+ bs->bl.max_transfer = max;
+
+ if (s->info.opt_block &&
+ s->info.opt_block > bs->bl.opt_transfer) {
+ bs->bl.opt_transfer = s->info.opt_block;
+ }
}
static void nbd_close(BlockDriverState *bs)
@@ -492,7 +500,7 @@ static int64_t nbd_getlength(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
- return s->client.size;
+ return s->client.info.size;
}
static void nbd_detach_aio_context(BlockDriverState *bs)
diff --git a/block/nfs.c b/block/nfs.c
index c3c5de0113..d8db419957 100644
--- a/block/nfs.c
+++ b/block/nfs.c
@@ -558,8 +558,8 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
}
client->readahead = qemu_opt_get_number(opts, "readahead-size", 0);
if (client->readahead > QEMU_NFS_MAX_READAHEAD_SIZE) {
- error_report("NFS Warning: Truncating NFS readahead "
- "size to %d", QEMU_NFS_MAX_READAHEAD_SIZE);
+ warn_report("Truncating NFS readahead size to %d",
+ QEMU_NFS_MAX_READAHEAD_SIZE);
client->readahead = QEMU_NFS_MAX_READAHEAD_SIZE;
}
nfs_set_readahead(client->context, client->readahead);
@@ -579,8 +579,8 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
}
client->pagecache = qemu_opt_get_number(opts, "page-cache-size", 0);
if (client->pagecache > QEMU_NFS_MAX_PAGECACHE_SIZE) {
- error_report("NFS Warning: Truncating NFS pagecache "
- "size to %d pages", QEMU_NFS_MAX_PAGECACHE_SIZE);
+ warn_report("Truncating NFS pagecache size to %d pages",
+ QEMU_NFS_MAX_PAGECACHE_SIZE);
client->pagecache = QEMU_NFS_MAX_PAGECACHE_SIZE;
}
nfs_set_pagecache(client->context, client->pagecache);
@@ -595,8 +595,8 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
/* limit the maximum debug level to avoid potential flooding
* of our log files. */
if (client->debug > QEMU_NFS_MAX_DEBUG_LEVEL) {
- error_report("NFS Warning: Limiting NFS debug level "
- "to %d", QEMU_NFS_MAX_DEBUG_LEVEL);
+ warn_report("Limiting NFS debug level to %d",
+ QEMU_NFS_MAX_DEBUG_LEVEL);
client->debug = QEMU_NFS_MAX_DEBUG_LEVEL;
}
nfs_set_debug(client->context, client->debug);
@@ -759,11 +759,18 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
return (task.ret < 0 ? task.ret : st.st_blocks * 512);
}
-static int nfs_file_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
+static int nfs_file_truncate(BlockDriverState *bs, int64_t offset,
+ PreallocMode prealloc, Error **errp)
{
NFSClient *client = bs->opaque;
int ret;
+ if (prealloc != PREALLOC_MODE_OFF) {
+ error_setg(errp, "Unsupported preallocation mode '%s'",
+ PreallocMode_lookup[prealloc]);
+ return -ENOTSUP;
+ }
+
ret = nfs_ftruncate(client->context, client->fh, offset);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to truncate file");
diff --git a/block/parallels.c b/block/parallels.c
index 8be46a7d48..5bbdfabb7a 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -224,7 +224,7 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
} else {
ret = bdrv_truncate(bs->file,
(s->data_end + space) << BDRV_SECTOR_BITS,
- NULL);
+ PREALLOC_MODE_OFF, NULL);
}
if (ret < 0) {
return ret;
@@ -458,7 +458,8 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
res->leaks += count;
if (fix & BDRV_FIX_LEAKS) {
Error *local_err = NULL;
- ret = bdrv_truncate(bs->file, res->image_end_offset, &local_err);
+ ret = bdrv_truncate(bs->file, res->image_end_offset,
+ PREALLOC_MODE_OFF, &local_err);
if (ret < 0) {
error_report_err(local_err);
res->check_errors++;
@@ -507,7 +508,7 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
blk_set_allow_write_beyond_eof(file, true);
- ret = blk_truncate(file, 0, errp);
+ ret = blk_truncate(file, 0, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto exit;
}
@@ -699,7 +700,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
}
if (!(flags & BDRV_O_RESIZE) || !bdrv_has_zero_init(bs->file->bs) ||
- bdrv_truncate(bs->file, bdrv_getlength(bs->file->bs), NULL) != 0) {
+ bdrv_truncate(bs->file, bdrv_getlength(bs->file->bs),
+ PREALLOC_MODE_OFF, NULL) != 0) {
s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
}
@@ -742,7 +744,8 @@ static void parallels_close(BlockDriverState *bs)
}
if (bs->open_flags & BDRV_O_RDWR) {
- bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, NULL);
+ bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS,
+ PREALLOC_MODE_OFF, NULL);
}
g_free(s->bat_dirty_bmap);
diff --git a/block/qapi.c b/block/qapi.c
index 0a41d59bf3..080eb8f115 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -45,7 +45,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
info->ro = bs->read_only;
info->drv = g_strdup(bs->drv->format_name);
info->encrypted = bs->encrypted;
- info->encryption_key_missing = bdrv_key_required(bs);
+ info->encryption_key_missing = false;
info->cache = g_new(BlockdevCacheInfo, 1);
*info->cache = (BlockdevCacheInfo) {
diff --git a/block/qcow.c b/block/qcow.c
index 7bd94dcd46..66827d6f24 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -31,8 +31,10 @@
#include "qemu/bswap.h"
#include <zlib.h>
#include "qapi/qmp/qerror.h"
-#include "crypto/cipher.h"
+#include "qapi/qmp/qstring.h"
+#include "crypto/block.h"
#include "migration/blocker.h"
+#include "block/crypto.h"
/**************************************************************/
/* QEMU COW block driver with compression and encryption support */
@@ -77,7 +79,7 @@ typedef struct BDRVQcowState {
uint8_t *cluster_cache;
uint8_t *cluster_data;
uint64_t cluster_cache_offset;
- QCryptoCipher *cipher; /* NULL if no key yet */
+ QCryptoBlock *crypto; /* Disk encryption format driver */
uint32_t crypt_method_header;
CoMutex lock;
Error *migration_blocker;
@@ -97,6 +99,15 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
+static QemuOptsList qcow_runtime_opts = {
+ .name = "qcow",
+ .head = QTAILQ_HEAD_INITIALIZER(qcow_runtime_opts.head),
+ .desc = {
+ BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."),
+ { /* end of list */ }
+ },
+};
+
static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
@@ -105,11 +116,19 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
int ret;
QCowHeader header;
Error *local_err = NULL;
+ QCryptoBlockOpenOptions *crypto_opts = NULL;
+ unsigned int cflags = 0;
+ QDict *encryptopts = NULL;
+ const char *encryptfmt;
+
+ qdict_extract_subqdict(options, &encryptopts, "encrypt.");
+ encryptfmt = qdict_get_try_str(encryptopts, "format");
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
false, errp);
if (!bs->file) {
- return -EINVAL;
+ ret = -EINVAL;
+ goto fail;
}
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
@@ -155,17 +174,6 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
- if (header.crypt_method > QCOW_CRYPT_AES) {
- error_setg(errp, "invalid encryption method in qcow header");
- ret = -EINVAL;
- goto fail;
- }
- if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128,
- QCRYPTO_CIPHER_MODE_CBC)) {
- error_setg(errp, "AES cipher not available");
- ret = -EINVAL;
- goto fail;
- }
s->crypt_method_header = header.crypt_method;
if (s->crypt_method_header) {
if (bdrv_uses_whitelist() &&
@@ -181,8 +189,44 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
ret = -ENOSYS;
goto fail;
}
+ if (s->crypt_method_header == QCOW_CRYPT_AES) {
+ if (encryptfmt && !g_str_equal(encryptfmt, "aes")) {
+ error_setg(errp,
+ "Header reported 'aes' encryption format but "
+ "options specify '%s'", encryptfmt);
+ ret = -EINVAL;
+ goto fail;
+ }
+ qdict_del(encryptopts, "format");
+ crypto_opts = block_crypto_open_opts_init(
+ Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
+ if (!crypto_opts) {
+ ret = -EINVAL;
+ goto fail;
+ }
+ if (flags & BDRV_O_NO_IO) {
+ cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
+ }
+ s->crypto = qcrypto_block_open(crypto_opts, "encrypt.",
+ NULL, NULL, cflags, errp);
+ if (!s->crypto) {
+ ret = -EINVAL;
+ goto fail;
+ }
+ } else {
+ error_setg(errp, "invalid encryption method in qcow header");
+ ret = -EINVAL;
+ goto fail;
+ }
bs->encrypted = true;
+ } else {
+ if (encryptfmt) {
+ error_setg(errp, "No encryption in image header, but options "
+ "specified format '%s'", encryptfmt);
+ ret = -EINVAL;
+ goto fail;
+ }
}
s->cluster_bits = header.cluster_bits;
s->cluster_size = 1 << s->cluster_bits;
@@ -266,6 +310,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
+ QDECREF(encryptopts);
+ qapi_free_QCryptoBlockOpenOptions(crypto_opts);
qemu_co_mutex_init(&s->lock);
return 0;
@@ -274,6 +320,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
qemu_vfree(s->l2_cache);
g_free(s->cluster_cache);
g_free(s->cluster_data);
+ qcrypto_block_free(s->crypto);
+ QDECREF(encryptopts);
+ qapi_free_QCryptoBlockOpenOptions(crypto_opts);
return ret;
}
@@ -286,85 +335,6 @@ static int qcow_reopen_prepare(BDRVReopenState *state,
return 0;
}
-static int qcow_set_key(BlockDriverState *bs, const char *key)
-{
- BDRVQcowState *s = bs->opaque;
- uint8_t keybuf[16];
- int len, i;
- Error *err;
-
- memset(keybuf, 0, 16);
- len = strlen(key);
- if (len > 16)
- len = 16;
- /* XXX: we could compress the chars to 7 bits to increase
- entropy */
- for(i = 0;i < len;i++) {
- keybuf[i] = key[i];
- }
- assert(bs->encrypted);
-
- qcrypto_cipher_free(s->cipher);
- s->cipher = qcrypto_cipher_new(
- QCRYPTO_CIPHER_ALG_AES_128,
- QCRYPTO_CIPHER_MODE_CBC,
- keybuf, G_N_ELEMENTS(keybuf),
- &err);
-
- if (!s->cipher) {
- /* XXX would be nice if errors in this method could
- * be properly propagate to the caller. Would need
- * the bdrv_set_key() API signature to be fixed. */
- error_free(err);
- return -1;
- }
- return 0;
-}
-
-/* The crypt function is compatible with the linux cryptoloop
- algorithm for < 4 GB images. NOTE: out_buf == in_buf is
- supported */
-static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
- uint8_t *out_buf, const uint8_t *in_buf,
- int nb_sectors, bool enc, Error **errp)
-{
- union {
- uint64_t ll[2];
- uint8_t b[16];
- } ivec;
- int i;
- int ret;
-
- for(i = 0; i < nb_sectors; i++) {
- ivec.ll[0] = cpu_to_le64(sector_num);
- ivec.ll[1] = 0;
- if (qcrypto_cipher_setiv(s->cipher,
- ivec.b, G_N_ELEMENTS(ivec.b),
- errp) < 0) {
- return -1;
- }
- if (enc) {
- ret = qcrypto_cipher_encrypt(s->cipher,
- in_buf,
- out_buf,
- 512,
- errp);
- } else {
- ret = qcrypto_cipher_decrypt(s->cipher,
- in_buf,
- out_buf,
- 512,
- errp);
- }
- if (ret < 0) {
- return -1;
- }
- sector_num++;
- in_buf += 512;
- out_buf += 512;
- }
- return 0;
-}
/* 'allocate' is:
*
@@ -473,22 +443,23 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
/* round to cluster size */
cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1);
- bdrv_truncate(bs->file, cluster_offset + s->cluster_size, NULL);
+ bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
+ PREALLOC_MODE_OFF, NULL);
/* if encrypted, we must initialize the cluster
content which won't be written */
if (bs->encrypted &&
(n_end - n_start) < s->cluster_sectors) {
uint64_t start_sect;
- assert(s->cipher);
+ assert(s->crypto);
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
- memset(s->cluster_data + 512, 0x00, 512);
for(i = 0; i < s->cluster_sectors; i++) {
if (i < n_start || i >= n_end) {
Error *err = NULL;
- if (encrypt_sectors(s, start_sect + i,
- s->cluster_data,
- s->cluster_data + 512, 1,
- true, &err) < 0) {
+ memset(s->cluster_data, 0x00, 512);
+ if (qcrypto_block_encrypt(s->crypto, start_sect + i,
+ s->cluster_data,
+ BDRV_SECTOR_SIZE,
+ &err) < 0) {
error_free(err);
errno = EIO;
return -1;
@@ -533,7 +504,7 @@ static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs,
if (!cluster_offset) {
return 0;
}
- if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->cipher) {
+ if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->crypto) {
return BDRV_BLOCK_DATA;
}
cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
@@ -664,9 +635,9 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
break;
}
if (bs->encrypted) {
- assert(s->cipher);
- if (encrypt_sectors(s, sector_num, buf, buf,
- n, false, &err) < 0) {
+ assert(s->crypto);
+ if (qcrypto_block_decrypt(s->crypto, sector_num, buf,
+ n * BDRV_SECTOR_SIZE, &err) < 0) {
goto fail;
}
}
@@ -700,9 +671,7 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
BDRVQcowState *s = bs->opaque;
int index_in_cluster;
uint64_t cluster_offset;
- const uint8_t *src_buf;
int ret = 0, n;
- uint8_t *cluster_data = NULL;
struct iovec hd_iov;
QEMUIOVector hd_qiov;
uint8_t *buf;
@@ -710,7 +679,9 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
s->cluster_cache_offset = -1; /* disable compressed cache */
- if (qiov->niov > 1) {
+ /* We must always copy the iov when encrypting, so we
+ * don't modify the original data buffer during encryption */
+ if (bs->encrypted || qiov->niov > 1) {
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
if (buf == NULL) {
return -ENOMEM;
@@ -739,22 +710,16 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
}
if (bs->encrypted) {
Error *err = NULL;
- assert(s->cipher);
- if (!cluster_data) {
- cluster_data = g_malloc0(s->cluster_size);
- }
- if (encrypt_sectors(s, sector_num, cluster_data, buf,
- n, true, &err) < 0) {
+ assert(s->crypto);
+ if (qcrypto_block_encrypt(s->crypto, sector_num, buf,
+ n * BDRV_SECTOR_SIZE, &err) < 0) {
error_free(err);
ret = -EIO;
break;
}
- src_buf = cluster_data;
- } else {
- src_buf = buf;
}
- hd_iov.iov_base = (void *)src_buf;
+ hd_iov.iov_base = (void *)buf;
hd_iov.iov_len = n * 512;
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
qemu_co_mutex_unlock(&s->lock);
@@ -773,10 +738,7 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
}
qemu_co_mutex_unlock(&s->lock);
- if (qiov->niov > 1) {
- qemu_vfree(orig_buf);
- }
- g_free(cluster_data);
+ qemu_vfree(orig_buf);
return ret;
}
@@ -785,8 +747,8 @@ static void qcow_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
- qcrypto_cipher_free(s->cipher);
- s->cipher = NULL;
+ qcrypto_block_free(s->crypto);
+ s->crypto = NULL;
g_free(s->l1_table);
qemu_vfree(s->l2_cache);
g_free(s->cluster_cache);
@@ -803,17 +765,35 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
uint8_t *tmp;
int64_t total_size = 0;
char *backing_file = NULL;
- int flags = 0;
Error *local_err = NULL;
int ret;
BlockBackend *qcow_blk;
+ const char *encryptfmt = NULL;
+ QDict *options;
+ QDict *encryptopts = NULL;
+ QCryptoBlockCreateOptions *crypto_opts = NULL;
+ QCryptoBlock *crypto = NULL;
/* Read out options */
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
+ if (total_size == 0) {
+ error_setg(errp, "Image size is too small, cannot be zero length");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
- if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
- flags |= BLOCK_FLAG_ENCRYPT;
+ encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
+ if (encryptfmt) {
+ if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
+ error_setg(errp, "Options " BLOCK_OPT_ENCRYPT " and "
+ BLOCK_OPT_ENCRYPT_FORMAT " are mutually exclusive");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ } else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
+ encryptfmt = "aes";
}
ret = bdrv_create_file(filename, opts, &local_err);
@@ -833,7 +813,7 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
blk_set_allow_write_beyond_eof(qcow_blk, true);
- ret = blk_truncate(qcow_blk, 0, errp);
+ ret = blk_truncate(qcow_blk, 0, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto exit;
}
@@ -867,8 +847,32 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
l1_size = (total_size + (1LL << shift) - 1) >> shift;
header.l1_table_offset = cpu_to_be64(header_size);
- if (flags & BLOCK_FLAG_ENCRYPT) {
+
+ options = qemu_opts_to_qdict(opts, NULL);
+ qdict_extract_subqdict(options, &encryptopts, "encrypt.");
+ QDECREF(options);
+ if (encryptfmt) {
+ if (!g_str_equal(encryptfmt, "aes")) {
+ error_setg(errp, "Unknown encryption format '%s', expected 'aes'",
+ encryptfmt);
+ ret = -EINVAL;
+ goto exit;
+ }
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
+
+ crypto_opts = block_crypto_create_opts_init(
+ Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
+ if (!crypto_opts) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ crypto = qcrypto_block_create(crypto_opts, "encrypt.",
+ NULL, NULL, NULL, errp);
+ if (!crypto) {
+ ret = -EINVAL;
+ goto exit;
+ }
} else {
header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
}
@@ -903,6 +907,9 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
exit:
blk_unref(qcow_blk);
cleanup:
+ QDECREF(encryptopts);
+ qcrypto_block_free(crypto);
+ qapi_free_QCryptoBlockCreateOptions(crypto_opts);
g_free(backing_file);
return ret;
}
@@ -917,7 +924,8 @@ static int qcow_make_empty(BlockDriverState *bs)
if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
l1_length) < 0)
return -1;
- ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, NULL);
+ ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length,
+ PREALLOC_MODE_OFF, NULL);
if (ret < 0)
return ret;
@@ -1041,9 +1049,15 @@ static QemuOptsList qcow_create_opts = {
{
.name = BLOCK_OPT_ENCRYPT,
.type = QEMU_OPT_BOOL,
- .help = "Encrypt the image",
- .def_value_str = "off"
+ .help = "Encrypt the image with format 'aes'. (Deprecated "
+ "in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)",
+ },
+ {
+ .name = BLOCK_OPT_ENCRYPT_FORMAT,
+ .type = QEMU_OPT_STRING,
+ .help = "Encrypt the image, format choices: 'aes'",
},
+ BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."),
{ /* end of list */ }
}
};
@@ -1064,7 +1078,6 @@ static BlockDriver bdrv_qcow = {
.bdrv_co_writev = qcow_co_writev,
.bdrv_co_get_block_status = qcow_co_get_block_status,
- .bdrv_set_key = qcow_set_key,
.bdrv_make_empty = qcow_make_empty,
.bdrv_co_pwritev_compressed = qcow_co_pwritev_compressed,
.bdrv_get_info = qcow_get_info,
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
new file mode 100644
index 0000000000..3e8735a20d
--- /dev/null
+++ b/block/qcow2-bitmap.c
@@ -0,0 +1,1482 @@
+/*
+ * Bitmaps for the QCOW version 2 format
+ *
+ * Copyright (c) 2014-2017 Vladimir Sementsov-Ogievskiy
+ *
+ * This file is derived from qcow2-snapshot.c, original copyright:
+ * Copyright (c) 2004-2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/cutils.h"
+
+#include "block/block_int.h"
+#include "block/qcow2.h"
+
+/* NOTICE: BME here means Bitmaps Extension and used as a namespace for
+ * _internal_ constants. Please do not use this _internal_ abbreviation for
+ * other needs and/or outside of this file. */
+
+/* Bitmap directory entry constraints */
+#define BME_MAX_TABLE_SIZE 0x8000000
+#define BME_MAX_PHYS_SIZE 0x20000000 /* restrict BdrvDirtyBitmap size in RAM */
+#define BME_MAX_GRANULARITY_BITS 31
+#define BME_MIN_GRANULARITY_BITS 9
+#define BME_MAX_NAME_SIZE 1023
+
+#if BME_MAX_TABLE_SIZE * 8ULL > INT_MAX
+#error In the code bitmap table physical size assumed to fit into int
+#endif
+
+/* Bitmap directory entry flags */
+#define BME_RESERVED_FLAGS 0xfffffffcU
+#define BME_FLAG_IN_USE (1U << 0)
+#define BME_FLAG_AUTO (1U << 1)
+
+/* bits [1, 8] U [56, 63] are reserved */
+#define BME_TABLE_ENTRY_RESERVED_MASK 0xff000000000001feULL
+#define BME_TABLE_ENTRY_OFFSET_MASK 0x00fffffffffffe00ULL
+#define BME_TABLE_ENTRY_FLAG_ALL_ONES (1ULL << 0)
+
+typedef struct QEMU_PACKED Qcow2BitmapDirEntry {
+ /* header is 8 byte aligned */
+ uint64_t bitmap_table_offset;
+
+ uint32_t bitmap_table_size;
+ uint32_t flags;
+
+ uint8_t type;
+ uint8_t granularity_bits;
+ uint16_t name_size;
+ uint32_t extra_data_size;
+ /* extra data follows */
+ /* name follows */
+} Qcow2BitmapDirEntry;
+
+typedef struct Qcow2BitmapTable {
+ uint64_t offset;
+ uint32_t size; /* number of 64bit entries */
+ QSIMPLEQ_ENTRY(Qcow2BitmapTable) entry;
+} Qcow2BitmapTable;
+typedef QSIMPLEQ_HEAD(Qcow2BitmapTableList, Qcow2BitmapTable)
+ Qcow2BitmapTableList;
+
+typedef struct Qcow2Bitmap {
+ Qcow2BitmapTable table;
+ uint32_t flags;
+ uint8_t granularity_bits;
+ char *name;
+
+ BdrvDirtyBitmap *dirty_bitmap;
+
+ QSIMPLEQ_ENTRY(Qcow2Bitmap) entry;
+} Qcow2Bitmap;
+typedef QSIMPLEQ_HEAD(Qcow2BitmapList, Qcow2Bitmap) Qcow2BitmapList;
+
+typedef enum BitmapType {
+ BT_DIRTY_TRACKING_BITMAP = 1
+} BitmapType;
+
+static inline bool can_write(BlockDriverState *bs)
+{
+ return !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE);
+}
+
+static int update_header_sync(BlockDriverState *bs)
+{
+ int ret;
+
+ ret = qcow2_update_header(bs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return bdrv_flush(bs);
+}
+
+static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; ++i) {
+ cpu_to_be64s(&bitmap_table[i]);
+ }
+}
+
+static int check_table_entry(uint64_t entry, int cluster_size)
+{
+ uint64_t offset;
+
+ if (entry & BME_TABLE_ENTRY_RESERVED_MASK) {
+ return -EINVAL;
+ }
+
+ offset = entry & BME_TABLE_ENTRY_OFFSET_MASK;
+ if (offset != 0) {
+ /* if offset specified, bit 0 is reserved */
+ if (entry & BME_TABLE_ENTRY_FLAG_ALL_ONES) {
+ return -EINVAL;
+ }
+
+ if (offset % cluster_size != 0) {
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int check_constraints_on_bitmap(BlockDriverState *bs,
+ const char *name,
+ uint32_t granularity,
+ Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int granularity_bits = ctz32(granularity);
+ int64_t len = bdrv_getlength(bs);
+
+ assert(granularity > 0);
+ assert((granularity & (granularity - 1)) == 0);
+
+ if (len < 0) {
+ error_setg_errno(errp, -len, "Failed to get size of '%s'",
+ bdrv_get_device_or_node_name(bs));
+ return len;
+ }
+
+ if (granularity_bits > BME_MAX_GRANULARITY_BITS) {
+ error_setg(errp, "Granularity exceeds maximum (%llu bytes)",
+ 1ULL << BME_MAX_GRANULARITY_BITS);
+ return -EINVAL;
+ }
+ if (granularity_bits < BME_MIN_GRANULARITY_BITS) {
+ error_setg(errp, "Granularity is under minimum (%llu bytes)",
+ 1ULL << BME_MIN_GRANULARITY_BITS);
+ return -EINVAL;
+ }
+
+ if ((len > (uint64_t)BME_MAX_PHYS_SIZE << granularity_bits) ||
+ (len > (uint64_t)BME_MAX_TABLE_SIZE * s->cluster_size <<
+ granularity_bits))
+ {
+ error_setg(errp, "Too much space will be occupied by the bitmap. "
+ "Use larger granularity");
+ return -EINVAL;
+ }
+
+ if (strlen(name) > BME_MAX_NAME_SIZE) {
+ error_setg(errp, "Name length exceeds maximum (%u characters)",
+ BME_MAX_NAME_SIZE);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table,
+ uint32_t bitmap_table_size)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int i;
+
+ for (i = 0; i < bitmap_table_size; ++i) {
+ uint64_t addr = bitmap_table[i] & BME_TABLE_ENTRY_OFFSET_MASK;
+ if (!addr) {
+ continue;
+ }
+
+ qcow2_free_clusters(bs, addr, s->cluster_size, QCOW2_DISCARD_OTHER);
+ bitmap_table[i] = 0;
+ }
+}
+
+static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb,
+ uint64_t **bitmap_table)
+{
+ int ret;
+ BDRVQcow2State *s = bs->opaque;
+ uint32_t i;
+ uint64_t *table;
+
+ assert(tb->size != 0);
+ table = g_try_new(uint64_t, tb->size);
+ if (table == NULL) {
+ return -ENOMEM;
+ }
+
+ assert(tb->size <= BME_MAX_TABLE_SIZE);
+ ret = bdrv_pread(bs->file, tb->offset,
+ table, tb->size * sizeof(uint64_t));
+ if (ret < 0) {
+ goto fail;
+ }
+
+ for (i = 0; i < tb->size; ++i) {
+ be64_to_cpus(&table[i]);
+ ret = check_table_entry(table[i], s->cluster_size);
+ if (ret < 0) {
+ goto fail;
+ }
+ }
+
+ *bitmap_table = table;
+ return 0;
+
+fail:
+ g_free(table);
+
+ return ret;
+}
+
+static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb)
+{
+ int ret;
+ uint64_t *bitmap_table;
+
+ ret = bitmap_table_load(bs, tb, &bitmap_table);
+ if (ret < 0) {
+ assert(bitmap_table == NULL);
+ return ret;
+ }
+
+ clear_bitmap_table(bs, bitmap_table, tb->size);
+ qcow2_free_clusters(bs, tb->offset, tb->size * sizeof(uint64_t),
+ QCOW2_DISCARD_OTHER);
+ g_free(bitmap_table);
+
+ tb->offset = 0;
+ tb->size = 0;
+
+ return 0;
+}
+
+/* This function returns the number of disk sectors covered by a single qcow2
+ * cluster of bitmap data. */
+static uint64_t sectors_covered_by_bitmap_cluster(const BDRVQcow2State *s,
+ const BdrvDirtyBitmap *bitmap)
+{
+ uint32_t sector_granularity =
+ bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
+
+ return (uint64_t)sector_granularity * (s->cluster_size << 3);
+}
+
+/* load_bitmap_data
+ * @bitmap_table entries must satisfy specification constraints.
+ * @bitmap must be cleared */
+static int load_bitmap_data(BlockDriverState *bs,
+ const uint64_t *bitmap_table,
+ uint32_t bitmap_table_size,
+ BdrvDirtyBitmap *bitmap)
+{
+ int ret = 0;
+ BDRVQcow2State *s = bs->opaque;
+ uint64_t sector, sbc;
+ uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
+ uint8_t *buf = NULL;
+ uint64_t i, tab_size =
+ size_to_clusters(s,
+ bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size));
+
+ if (tab_size != bitmap_table_size || tab_size > BME_MAX_TABLE_SIZE) {
+ return -EINVAL;
+ }
+
+ buf = g_malloc(s->cluster_size);
+ sbc = sectors_covered_by_bitmap_cluster(s, bitmap);
+ for (i = 0, sector = 0; i < tab_size; ++i, sector += sbc) {
+ uint64_t count = MIN(bm_size - sector, sbc);
+ uint64_t entry = bitmap_table[i];
+ uint64_t offset = entry & BME_TABLE_ENTRY_OFFSET_MASK;
+
+ assert(check_table_entry(entry, s->cluster_size) == 0);
+
+ if (offset == 0) {
+ if (entry & BME_TABLE_ENTRY_FLAG_ALL_ONES) {
+ bdrv_dirty_bitmap_deserialize_ones(bitmap, sector, count,
+ false);
+ } else {
+ /* No need to deserialize zeros because the dirty bitmap is
+ * already cleared */
+ }
+ } else {
+ ret = bdrv_pread(bs->file, offset, buf, s->cluster_size);
+ if (ret < 0) {
+ goto finish;
+ }
+ bdrv_dirty_bitmap_deserialize_part(bitmap, buf, sector, count,
+ false);
+ }
+ }
+ ret = 0;
+
+ bdrv_dirty_bitmap_deserialize_finish(bitmap);
+
+finish:
+ g_free(buf);
+
+ return ret;
+}
+
+static BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs,
+ Qcow2Bitmap *bm, Error **errp)
+{
+ int ret;
+ uint64_t *bitmap_table = NULL;
+ uint32_t granularity;
+ BdrvDirtyBitmap *bitmap = NULL;
+
+ if (bm->flags & BME_FLAG_IN_USE) {
+ error_setg(errp, "Bitmap '%s' is in use", bm->name);
+ goto fail;
+ }
+
+ ret = bitmap_table_load(bs, &bm->table, &bitmap_table);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "Could not read bitmap_table table from image for "
+ "bitmap '%s'", bm->name);
+ goto fail;
+ }
+
+ granularity = 1U << bm->granularity_bits;
+ bitmap = bdrv_create_dirty_bitmap(bs, granularity, bm->name, errp);
+ if (bitmap == NULL) {
+ goto fail;
+ }
+
+ ret = load_bitmap_data(bs, bitmap_table, bm->table.size, bitmap);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not read bitmap '%s' from image",
+ bm->name);
+ goto fail;
+ }
+
+ g_free(bitmap_table);
+ return bitmap;
+
+fail:
+ g_free(bitmap_table);
+ if (bitmap != NULL) {
+ bdrv_release_dirty_bitmap(bs, bitmap);
+ }
+
+ return NULL;
+}
+
+/*
+ * Bitmap List
+ */
+
+/*
+ * Bitmap List private functions
+ * Only Bitmap List knows about bitmap directory structure in Qcow2.
+ */
+
+static inline void bitmap_dir_entry_to_cpu(Qcow2BitmapDirEntry *entry)
+{
+ be64_to_cpus(&entry->bitmap_table_offset);
+ be32_to_cpus(&entry->bitmap_table_size);
+ be32_to_cpus(&entry->flags);
+ be16_to_cpus(&entry->name_size);
+ be32_to_cpus(&entry->extra_data_size);
+}
+
+static inline void bitmap_dir_entry_to_be(Qcow2BitmapDirEntry *entry)
+{
+ cpu_to_be64s(&entry->bitmap_table_offset);
+ cpu_to_be32s(&entry->bitmap_table_size);
+ cpu_to_be32s(&entry->flags);
+ cpu_to_be16s(&entry->name_size);
+ cpu_to_be32s(&entry->extra_data_size);
+}
+
+static inline int calc_dir_entry_size(size_t name_size, size_t extra_data_size)
+{
+ return align_offset(sizeof(Qcow2BitmapDirEntry) +
+ name_size + extra_data_size, 8);
+}
+
+static inline int dir_entry_size(Qcow2BitmapDirEntry *entry)
+{
+ return calc_dir_entry_size(entry->name_size, entry->extra_data_size);
+}
+
+static inline const char *dir_entry_name_field(Qcow2BitmapDirEntry *entry)
+{
+ return (const char *)(entry + 1) + entry->extra_data_size;
+}
+
+static inline char *dir_entry_copy_name(Qcow2BitmapDirEntry *entry)
+{
+ const char *name_field = dir_entry_name_field(entry);
+ return g_strndup(name_field, entry->name_size);
+}
+
+static inline Qcow2BitmapDirEntry *next_dir_entry(Qcow2BitmapDirEntry *entry)
+{
+ return (Qcow2BitmapDirEntry *)((uint8_t *)entry + dir_entry_size(entry));
+}
+
+static int check_dir_entry(BlockDriverState *bs, Qcow2BitmapDirEntry *entry)
+{
+ BDRVQcow2State *s = bs->opaque;
+ uint64_t phys_bitmap_bytes;
+ int64_t len;
+
+ bool fail = (entry->bitmap_table_size == 0) ||
+ (entry->bitmap_table_offset == 0) ||
+ (entry->bitmap_table_offset % s->cluster_size) ||
+ (entry->bitmap_table_size > BME_MAX_TABLE_SIZE) ||
+ (entry->granularity_bits > BME_MAX_GRANULARITY_BITS) ||
+ (entry->granularity_bits < BME_MIN_GRANULARITY_BITS) ||
+ (entry->flags & BME_RESERVED_FLAGS) ||
+ (entry->name_size > BME_MAX_NAME_SIZE) ||
+ (entry->type != BT_DIRTY_TRACKING_BITMAP);
+
+ if (fail) {
+ return -EINVAL;
+ }
+
+ phys_bitmap_bytes = (uint64_t)entry->bitmap_table_size * s->cluster_size;
+ len = bdrv_getlength(bs);
+
+ if (len < 0) {
+ return len;
+ }
+
+ fail = (phys_bitmap_bytes > BME_MAX_PHYS_SIZE) ||
+ (len > ((phys_bitmap_bytes * 8) << entry->granularity_bits));
+
+ return fail ? -EINVAL : 0;
+}
+
+static inline void bitmap_directory_to_be(uint8_t *dir, size_t size)
+{
+ uint8_t *end = dir + size;
+ while (dir < end) {
+ Qcow2BitmapDirEntry *e = (Qcow2BitmapDirEntry *)dir;
+ dir += dir_entry_size(e);
+
+ bitmap_dir_entry_to_be(e);
+ }
+}
+
+/*
+ * Bitmap List public functions
+ */
+
+static void bitmap_free(Qcow2Bitmap *bm)
+{
+ g_free(bm->name);
+ g_free(bm);
+}
+
+static void bitmap_list_free(Qcow2BitmapList *bm_list)
+{
+ Qcow2Bitmap *bm;
+
+ if (bm_list == NULL) {
+ return;
+ }
+
+ while ((bm = QSIMPLEQ_FIRST(bm_list)) != NULL) {
+ QSIMPLEQ_REMOVE_HEAD(bm_list, entry);
+ bitmap_free(bm);
+ }
+
+ g_free(bm_list);
+}
+
+static Qcow2BitmapList *bitmap_list_new(void)
+{
+ Qcow2BitmapList *bm_list = g_new(Qcow2BitmapList, 1);
+ QSIMPLEQ_INIT(bm_list);
+
+ return bm_list;
+}
+
+static uint32_t bitmap_list_count(Qcow2BitmapList *bm_list)
+{
+ Qcow2Bitmap *bm;
+ uint32_t nb_bitmaps = 0;
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ nb_bitmaps++;
+ }
+
+ return nb_bitmaps;
+}
+
+/* bitmap_list_load
+ * Get bitmap list from qcow2 image. Actually reads bitmap directory,
+ * checks it and convert to bitmap list.
+ */
+static Qcow2BitmapList *bitmap_list_load(BlockDriverState *bs, uint64_t offset,
+ uint64_t size, Error **errp)
+{
+ int ret;
+ BDRVQcow2State *s = bs->opaque;
+ uint8_t *dir, *dir_end;
+ Qcow2BitmapDirEntry *e;
+ uint32_t nb_dir_entries = 0;
+ Qcow2BitmapList *bm_list = NULL;
+
+ if (size == 0) {
+ error_setg(errp, "Requested bitmap directory size is zero");
+ return NULL;
+ }
+
+ if (size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) {
+ error_setg(errp, "Requested bitmap directory size is too big");
+ return NULL;
+ }
+
+ dir = g_try_malloc(size);
+ if (dir == NULL) {
+ error_setg(errp, "Failed to allocate space for bitmap directory");
+ return NULL;
+ }
+ dir_end = dir + size;
+
+ ret = bdrv_pread(bs->file, offset, dir, size);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to read bitmap directory");
+ goto fail;
+ }
+
+ bm_list = bitmap_list_new();
+ for (e = (Qcow2BitmapDirEntry *)dir;
+ e < (Qcow2BitmapDirEntry *)dir_end;
+ e = next_dir_entry(e))
+ {
+ Qcow2Bitmap *bm;
+
+ if ((uint8_t *)(e + 1) > dir_end) {
+ goto broken_dir;
+ }
+
+ if (++nb_dir_entries > s->nb_bitmaps) {
+ error_setg(errp, "More bitmaps found than specified in header"
+ " extension");
+ goto fail;
+ }
+ bitmap_dir_entry_to_cpu(e);
+
+ if ((uint8_t *)next_dir_entry(e) > dir_end) {
+ goto broken_dir;
+ }
+
+ if (e->extra_data_size != 0) {
+ error_setg(errp, "Bitmap extra data is not supported");
+ goto fail;
+ }
+
+ ret = check_dir_entry(bs, e);
+ if (ret < 0) {
+ error_setg(errp, "Bitmap '%.*s' doesn't satisfy the constraints",
+ e->name_size, dir_entry_name_field(e));
+ goto fail;
+ }
+
+ bm = g_new(Qcow2Bitmap, 1);
+ bm->table.offset = e->bitmap_table_offset;
+ bm->table.size = e->bitmap_table_size;
+ bm->flags = e->flags;
+ bm->granularity_bits = e->granularity_bits;
+ bm->name = dir_entry_copy_name(e);
+ QSIMPLEQ_INSERT_TAIL(bm_list, bm, entry);
+ }
+
+ if (nb_dir_entries != s->nb_bitmaps) {
+ error_setg(errp, "Less bitmaps found than specified in header"
+ " extension");
+ goto fail;
+ }
+
+ if ((uint8_t *)e != dir_end) {
+ goto broken_dir;
+ }
+
+ g_free(dir);
+ return bm_list;
+
+broken_dir:
+ ret = -EINVAL;
+ error_setg(errp, "Broken bitmap directory");
+
+fail:
+ g_free(dir);
+ bitmap_list_free(bm_list);
+
+ return NULL;
+}
+
+int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table,
+ int64_t *refcount_table_size)
+{
+ int ret;
+ BDRVQcow2State *s = bs->opaque;
+ Qcow2BitmapList *bm_list;
+ Qcow2Bitmap *bm;
+
+ if (s->nb_bitmaps == 0) {
+ return 0;
+ }
+
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size,
+ s->bitmap_directory_offset,
+ s->bitmap_directory_size);
+ if (ret < 0) {
+ return ret;
+ }
+
+ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, NULL);
+ if (bm_list == NULL) {
+ res->corruptions++;
+ return -EINVAL;
+ }
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ uint64_t *bitmap_table = NULL;
+ int i;
+
+ ret = qcow2_inc_refcounts_imrt(bs, res,
+ refcount_table, refcount_table_size,
+ bm->table.offset,
+ bm->table.size * sizeof(uint64_t));
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = bitmap_table_load(bs, &bm->table, &bitmap_table);
+ if (ret < 0) {
+ res->corruptions++;
+ goto out;
+ }
+
+ for (i = 0; i < bm->table.size; ++i) {
+ uint64_t entry = bitmap_table[i];
+ uint64_t offset = entry & BME_TABLE_ENTRY_OFFSET_MASK;
+
+ if (check_table_entry(entry, s->cluster_size) < 0) {
+ res->corruptions++;
+ continue;
+ }
+
+ if (offset == 0) {
+ continue;
+ }
+
+ ret = qcow2_inc_refcounts_imrt(bs, res,
+ refcount_table, refcount_table_size,
+ offset, s->cluster_size);
+ if (ret < 0) {
+ g_free(bitmap_table);
+ goto out;
+ }
+ }
+
+ g_free(bitmap_table);
+ }
+
+out:
+ bitmap_list_free(bm_list);
+
+ return ret;
+}
+
+/* bitmap_list_store
+ * Store bitmap list to qcow2 image as a bitmap directory.
+ * Everything is checked.
+ */
+static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list,
+ uint64_t *offset, uint64_t *size, bool in_place)
+{
+ int ret;
+ uint8_t *dir;
+ int64_t dir_offset = 0;
+ uint64_t dir_size = 0;
+ Qcow2Bitmap *bm;
+ Qcow2BitmapDirEntry *e;
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ dir_size += calc_dir_entry_size(strlen(bm->name), 0);
+ }
+
+ if (dir_size == 0 || dir_size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) {
+ return -EINVAL;
+ }
+
+ if (in_place) {
+ if (*size != dir_size || *offset == 0) {
+ return -EINVAL;
+ }
+
+ dir_offset = *offset;
+ }
+
+ dir = g_try_malloc(dir_size);
+ if (dir == NULL) {
+ return -ENOMEM;
+ }
+
+ e = (Qcow2BitmapDirEntry *)dir;
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ e->bitmap_table_offset = bm->table.offset;
+ e->bitmap_table_size = bm->table.size;
+ e->flags = bm->flags;
+ e->type = BT_DIRTY_TRACKING_BITMAP;
+ e->granularity_bits = bm->granularity_bits;
+ e->name_size = strlen(bm->name);
+ e->extra_data_size = 0;
+ memcpy(e + 1, bm->name, e->name_size);
+
+ if (check_dir_entry(bs, e) < 0) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ e = next_dir_entry(e);
+ }
+
+ bitmap_directory_to_be(dir, dir_size);
+
+ if (!in_place) {
+ dir_offset = qcow2_alloc_clusters(bs, dir_size);
+ if (dir_offset < 0) {
+ ret = dir_offset;
+ goto fail;
+ }
+ }
+
+ ret = qcow2_pre_write_overlap_check(bs, 0, dir_offset, dir_size);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ ret = bdrv_pwrite(bs->file, dir_offset, dir, dir_size);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ g_free(dir);
+
+ if (!in_place) {
+ *size = dir_size;
+ *offset = dir_offset;
+ }
+
+ return 0;
+
+fail:
+ g_free(dir);
+
+ if (!in_place && dir_offset > 0) {
+ qcow2_free_clusters(bs, dir_offset, dir_size, QCOW2_DISCARD_OTHER);
+ }
+
+ return ret;
+}
+
+/*
+ * Bitmap List end
+ */
+
+static int update_ext_header_and_dir_in_place(BlockDriverState *bs,
+ Qcow2BitmapList *bm_list)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int ret;
+
+ if (!(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS) ||
+ bm_list == NULL || QSIMPLEQ_EMPTY(bm_list) ||
+ bitmap_list_count(bm_list) != s->nb_bitmaps)
+ {
+ return -EINVAL;
+ }
+
+ s->autoclear_features &= ~(uint64_t)QCOW2_AUTOCLEAR_BITMAPS;
+ ret = update_header_sync(bs);
+ if (ret < 0) {
+ /* Two variants are possible here:
+ * 1. Autoclear flag is dropped, all bitmaps will be lost.
+ * 2. Autoclear flag is not dropped, old state is left.
+ */
+ return ret;
+ }
+
+ /* autoclear bit is not set, so we can safely update bitmap directory */
+
+ ret = bitmap_list_store(bs, bm_list, &s->bitmap_directory_offset,
+ &s->bitmap_directory_size, true);
+ if (ret < 0) {
+ /* autoclear bit is cleared, so all leaked clusters would be removed on
+ * qemu-img check */
+ return ret;
+ }
+
+ ret = update_header_sync(bs);
+ if (ret < 0) {
+ /* autoclear bit is cleared, so all leaked clusters would be removed on
+ * qemu-img check */
+ return ret;
+ }
+
+ s->autoclear_features |= QCOW2_AUTOCLEAR_BITMAPS;
+ return update_header_sync(bs);
+ /* If final update_header_sync() fails, two variants are possible:
+ * 1. Autoclear flag is not set, all bitmaps will be lost.
+ * 2. Autoclear flag is set, header and directory are successfully updated.
+ */
+}
+
+static int update_ext_header_and_dir(BlockDriverState *bs,
+ Qcow2BitmapList *bm_list)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int ret;
+ uint64_t new_offset = 0;
+ uint64_t new_size = 0;
+ uint32_t new_nb_bitmaps = 0;
+ uint64_t old_offset = s->bitmap_directory_offset;
+ uint64_t old_size = s->bitmap_directory_size;
+ uint32_t old_nb_bitmaps = s->nb_bitmaps;
+ uint64_t old_autocl = s->autoclear_features;
+
+ if (bm_list != NULL && !QSIMPLEQ_EMPTY(bm_list)) {
+ new_nb_bitmaps = bitmap_list_count(bm_list);
+
+ if (new_nb_bitmaps > QCOW2_MAX_BITMAPS) {
+ return -EINVAL;
+ }
+
+ ret = bitmap_list_store(bs, bm_list, &new_offset, &new_size, false);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = bdrv_flush(bs->file->bs);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ s->autoclear_features |= QCOW2_AUTOCLEAR_BITMAPS;
+ } else {
+ s->autoclear_features &= ~(uint64_t)QCOW2_AUTOCLEAR_BITMAPS;
+ }
+
+ s->bitmap_directory_offset = new_offset;
+ s->bitmap_directory_size = new_size;
+ s->nb_bitmaps = new_nb_bitmaps;
+
+ ret = update_header_sync(bs);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ if (old_size > 0) {
+ qcow2_free_clusters(bs, old_offset, old_size, QCOW2_DISCARD_OTHER);
+ }
+
+ return 0;
+
+fail:
+ if (new_offset > 0) {
+ qcow2_free_clusters(bs, new_offset, new_size, QCOW2_DISCARD_OTHER);
+ }
+
+ s->bitmap_directory_offset = old_offset;
+ s->bitmap_directory_size = old_size;
+ s->nb_bitmaps = old_nb_bitmaps;
+ s->autoclear_features = old_autocl;
+
+ return ret;
+}
+
+/* for g_slist_foreach for GSList of BdrvDirtyBitmap* elements */
+static void release_dirty_bitmap_helper(gpointer bitmap,
+ gpointer bs)
+{
+ bdrv_release_dirty_bitmap(bs, bitmap);
+}
+
+/* for g_slist_foreach for GSList of BdrvDirtyBitmap* elements */
+static void set_readonly_helper(gpointer bitmap, gpointer value)
+{
+ bdrv_dirty_bitmap_set_readonly(bitmap, (bool)value);
+}
+
+/* qcow2_load_autoloading_dirty_bitmaps()
+ * Return value is a hint for caller: true means that the Qcow2 header was
+ * updated. (false doesn't mean that the header should be updated by the
+ * caller, it just means that updating was not needed or the image cannot be
+ * written to).
+ * On failure the function returns false.
+ */
+bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ Qcow2BitmapList *bm_list;
+ Qcow2Bitmap *bm;
+ GSList *created_dirty_bitmaps = NULL;
+ bool header_updated = false;
+
+ if (s->nb_bitmaps == 0) {
+ /* No bitmaps - nothing to do */
+ return false;
+ }
+
+ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, errp);
+ if (bm_list == NULL) {
+ return false;
+ }
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ if ((bm->flags & BME_FLAG_AUTO) && !(bm->flags & BME_FLAG_IN_USE)) {
+ BdrvDirtyBitmap *bitmap = load_bitmap(bs, bm, errp);
+ if (bitmap == NULL) {
+ goto fail;
+ }
+
+ bdrv_dirty_bitmap_set_persistance(bitmap, true);
+ bdrv_dirty_bitmap_set_autoload(bitmap, true);
+ bm->flags |= BME_FLAG_IN_USE;
+ created_dirty_bitmaps =
+ g_slist_append(created_dirty_bitmaps, bitmap);
+ }
+ }
+
+ if (created_dirty_bitmaps != NULL) {
+ if (can_write(bs)) {
+ /* in_use flags must be updated */
+ int ret = update_ext_header_and_dir_in_place(bs, bm_list);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Can't update bitmap directory");
+ goto fail;
+ }
+ header_updated = true;
+ } else {
+ g_slist_foreach(created_dirty_bitmaps, set_readonly_helper,
+ (gpointer)true);
+ }
+ }
+
+ g_slist_free(created_dirty_bitmaps);
+ bitmap_list_free(bm_list);
+
+ return header_updated;
+
+fail:
+ g_slist_foreach(created_dirty_bitmaps, release_dirty_bitmap_helper, bs);
+ g_slist_free(created_dirty_bitmaps);
+ bitmap_list_free(bm_list);
+
+ return false;
+}
+
+int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ Qcow2BitmapList *bm_list;
+ Qcow2Bitmap *bm;
+ GSList *ro_dirty_bitmaps = NULL;
+ int ret = 0;
+
+ if (s->nb_bitmaps == 0) {
+ /* No bitmaps - nothing to do */
+ return 0;
+ }
+
+ if (!can_write(bs)) {
+ error_setg(errp, "Can't write to the image on reopening bitmaps rw");
+ return -EINVAL;
+ }
+
+ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, errp);
+ if (bm_list == NULL) {
+ return -EINVAL;
+ }
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ if (!(bm->flags & BME_FLAG_IN_USE)) {
+ BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(bs, bm->name);
+ if (bitmap == NULL) {
+ continue;
+ }
+
+ if (!bdrv_dirty_bitmap_readonly(bitmap)) {
+ error_setg(errp, "Bitmap %s is not readonly but not marked"
+ "'IN_USE' in the image. Something went wrong,"
+ "all the bitmaps may be corrupted", bm->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ bm->flags |= BME_FLAG_IN_USE;
+ ro_dirty_bitmaps = g_slist_append(ro_dirty_bitmaps, bitmap);
+ }
+ }
+
+ if (ro_dirty_bitmaps != NULL) {
+ /* in_use flags must be updated */
+ ret = update_ext_header_and_dir_in_place(bs, bm_list);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Can't update bitmap directory");
+ goto out;
+ }
+ g_slist_foreach(ro_dirty_bitmaps, set_readonly_helper, false);
+ }
+
+out:
+ g_slist_free(ro_dirty_bitmaps);
+ bitmap_list_free(bm_list);
+
+ return ret;
+}
+
+/* store_bitmap_data()
+ * Store bitmap to image, filling bitmap table accordingly.
+ */
+static uint64_t *store_bitmap_data(BlockDriverState *bs,
+ BdrvDirtyBitmap *bitmap,
+ uint32_t *bitmap_table_size, Error **errp)
+{
+ int ret;
+ BDRVQcow2State *s = bs->opaque;
+ int64_t sector;
+ uint64_t sbc;
+ uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
+ const char *bm_name = bdrv_dirty_bitmap_name(bitmap);
+ uint8_t *buf = NULL;
+ BdrvDirtyBitmapIter *dbi;
+ uint64_t *tb;
+ uint64_t tb_size =
+ size_to_clusters(s,
+ bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size));
+
+ if (tb_size > BME_MAX_TABLE_SIZE ||
+ tb_size * s->cluster_size > BME_MAX_PHYS_SIZE)
+ {
+ error_setg(errp, "Bitmap '%s' is too big", bm_name);
+ return NULL;
+ }
+
+ tb = g_try_new0(uint64_t, tb_size);
+ if (tb == NULL) {
+ error_setg(errp, "No memory");
+ return NULL;
+ }
+
+ dbi = bdrv_dirty_iter_new(bitmap, 0);
+ buf = g_malloc(s->cluster_size);
+ sbc = sectors_covered_by_bitmap_cluster(s, bitmap);
+ assert(DIV_ROUND_UP(bm_size, sbc) == tb_size);
+
+ while ((sector = bdrv_dirty_iter_next(dbi)) != -1) {
+ uint64_t cluster = sector / sbc;
+ uint64_t end, write_size;
+ int64_t off;
+
+ sector = cluster * sbc;
+ end = MIN(bm_size, sector + sbc);
+ write_size =
+ bdrv_dirty_bitmap_serialization_size(bitmap, sector, end - sector);
+ assert(write_size <= s->cluster_size);
+
+ off = qcow2_alloc_clusters(bs, s->cluster_size);
+ if (off < 0) {
+ error_setg_errno(errp, -off,
+ "Failed to allocate clusters for bitmap '%s'",
+ bm_name);
+ goto fail;
+ }
+ tb[cluster] = off;
+
+ bdrv_dirty_bitmap_serialize_part(bitmap, buf, sector, end - sector);
+ if (write_size < s->cluster_size) {
+ memset(buf + write_size, 0, s->cluster_size - write_size);
+ }
+
+ ret = qcow2_pre_write_overlap_check(bs, 0, off, s->cluster_size);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Qcow2 overlap check failed");
+ goto fail;
+ }
+
+ ret = bdrv_pwrite(bs->file, off, buf, s->cluster_size);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to write bitmap '%s' to file",
+ bm_name);
+ goto fail;
+ }
+
+ if (end >= bm_size) {
+ break;
+ }
+
+ bdrv_set_dirty_iter(dbi, end);
+ }
+
+ *bitmap_table_size = tb_size;
+ g_free(buf);
+ bdrv_dirty_iter_free(dbi);
+
+ return tb;
+
+fail:
+ clear_bitmap_table(bs, tb, tb_size);
+ g_free(buf);
+ bdrv_dirty_iter_free(dbi);
+ g_free(tb);
+
+ return NULL;
+}
+
+/* store_bitmap()
+ * Store bm->dirty_bitmap to qcow2.
+ * Set bm->table_offset and bm->table_size accordingly.
+ */
+static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp)
+{
+ int ret;
+ uint64_t *tb;
+ int64_t tb_offset;
+ uint32_t tb_size;
+ BdrvDirtyBitmap *bitmap = bm->dirty_bitmap;
+ const char *bm_name;
+
+ assert(bitmap != NULL);
+
+ bm_name = bdrv_dirty_bitmap_name(bitmap);
+
+ tb = store_bitmap_data(bs, bitmap, &tb_size, errp);
+ if (tb == NULL) {
+ return -EINVAL;
+ }
+
+ assert(tb_size <= BME_MAX_TABLE_SIZE);
+ tb_offset = qcow2_alloc_clusters(bs, tb_size * sizeof(tb[0]));
+ if (tb_offset < 0) {
+ error_setg_errno(errp, -tb_offset,
+ "Failed to allocate clusters for bitmap '%s'",
+ bm_name);
+ ret = tb_offset;
+ goto fail;
+ }
+
+ ret = qcow2_pre_write_overlap_check(bs, 0, tb_offset,
+ tb_size * sizeof(tb[0]));
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Qcow2 overlap check failed");
+ goto fail;
+ }
+
+ bitmap_table_to_be(tb, tb_size);
+ ret = bdrv_pwrite(bs->file, tb_offset, tb, tb_size * sizeof(tb[0]));
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to write bitmap '%s' to file",
+ bm_name);
+ goto fail;
+ }
+
+ g_free(tb);
+
+ bm->table.offset = tb_offset;
+ bm->table.size = tb_size;
+
+ return 0;
+
+fail:
+ clear_bitmap_table(bs, tb, tb_size);
+
+ if (tb_offset > 0) {
+ qcow2_free_clusters(bs, tb_offset, tb_size * sizeof(tb[0]),
+ QCOW2_DISCARD_OTHER);
+ }
+
+ g_free(tb);
+
+ return ret;
+}
+
+static Qcow2Bitmap *find_bitmap_by_name(Qcow2BitmapList *bm_list,
+ const char *name)
+{
+ Qcow2Bitmap *bm;
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ if (strcmp(name, bm->name) == 0) {
+ return bm;
+ }
+ }
+
+ return NULL;
+}
+
+void qcow2_remove_persistent_dirty_bitmap(BlockDriverState *bs,
+ const char *name,
+ Error **errp)
+{
+ int ret;
+ BDRVQcow2State *s = bs->opaque;
+ Qcow2Bitmap *bm;
+ Qcow2BitmapList *bm_list;
+
+ if (s->nb_bitmaps == 0) {
+ /* Absence of the bitmap is not an error: see explanation above
+ * bdrv_remove_persistent_dirty_bitmap() definition. */
+ return;
+ }
+
+ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, errp);
+ if (bm_list == NULL) {
+ return;
+ }
+
+ bm = find_bitmap_by_name(bm_list, name);
+ if (bm == NULL) {
+ goto fail;
+ }
+
+ QSIMPLEQ_REMOVE(bm_list, bm, Qcow2Bitmap, entry);
+
+ ret = update_ext_header_and_dir(bs, bm_list);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to update bitmap extension");
+ goto fail;
+ }
+
+ free_bitmap_clusters(bs, &bm->table);
+
+fail:
+ bitmap_free(bm);
+ bitmap_list_free(bm_list);
+}
+
+void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
+{
+ BdrvDirtyBitmap *bitmap;
+ BDRVQcow2State *s = bs->opaque;
+ uint32_t new_nb_bitmaps = s->nb_bitmaps;
+ uint64_t new_dir_size = s->bitmap_directory_size;
+ int ret;
+ Qcow2BitmapList *bm_list;
+ Qcow2Bitmap *bm;
+ Qcow2BitmapTableList drop_tables;
+ Qcow2BitmapTable *tb, *tb_next;
+
+ if (!bdrv_has_changed_persistent_bitmaps(bs)) {
+ /* nothing to do */
+ return;
+ }
+
+ if (!can_write(bs)) {
+ error_setg(errp, "No write access");
+ return;
+ }
+
+ QSIMPLEQ_INIT(&drop_tables);
+
+ if (s->nb_bitmaps == 0) {
+ bm_list = bitmap_list_new();
+ } else {
+ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, errp);
+ if (bm_list == NULL) {
+ return;
+ }
+ }
+
+ /* check constraints and names */
+ for (bitmap = bdrv_dirty_bitmap_next(bs, NULL); bitmap != NULL;
+ bitmap = bdrv_dirty_bitmap_next(bs, bitmap))
+ {
+ const char *name = bdrv_dirty_bitmap_name(bitmap);
+ uint32_t granularity = bdrv_dirty_bitmap_granularity(bitmap);
+ Qcow2Bitmap *bm;
+
+ if (!bdrv_dirty_bitmap_get_persistance(bitmap) ||
+ bdrv_dirty_bitmap_readonly(bitmap))
+ {
+ continue;
+ }
+
+ if (check_constraints_on_bitmap(bs, name, granularity, errp) < 0) {
+ error_prepend(errp, "Bitmap '%s' doesn't satisfy the constraints: ",
+ name);
+ goto fail;
+ }
+
+ bm = find_bitmap_by_name(bm_list, name);
+ if (bm == NULL) {
+ if (++new_nb_bitmaps > QCOW2_MAX_BITMAPS) {
+ error_setg(errp, "Too many persistent bitmaps");
+ goto fail;
+ }
+
+ new_dir_size += calc_dir_entry_size(strlen(name), 0);
+ if (new_dir_size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) {
+ error_setg(errp, "Bitmap directory is too large");
+ goto fail;
+ }
+
+ bm = g_new0(Qcow2Bitmap, 1);
+ bm->name = g_strdup(name);
+ QSIMPLEQ_INSERT_TAIL(bm_list, bm, entry);
+ } else {
+ if (!(bm->flags & BME_FLAG_IN_USE)) {
+ error_setg(errp, "Bitmap '%s' already exists in the image",
+ name);
+ goto fail;
+ }
+ tb = g_memdup(&bm->table, sizeof(bm->table));
+ bm->table.offset = 0;
+ bm->table.size = 0;
+ QSIMPLEQ_INSERT_TAIL(&drop_tables, tb, entry);
+ }
+ bm->flags = bdrv_dirty_bitmap_get_autoload(bitmap) ? BME_FLAG_AUTO : 0;
+ bm->granularity_bits = ctz32(bdrv_dirty_bitmap_granularity(bitmap));
+ bm->dirty_bitmap = bitmap;
+ }
+
+ /* allocate clusters and store bitmaps */
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ if (bm->dirty_bitmap == NULL) {
+ continue;
+ }
+
+ ret = store_bitmap(bs, bm, errp);
+ if (ret < 0) {
+ goto fail;
+ }
+ }
+
+ ret = update_ext_header_and_dir(bs, bm_list);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to update bitmap extension");
+ goto fail;
+ }
+
+ /* Bitmap directory was successfully updated, so, old data can be dropped.
+ * TODO it is better to reuse these clusters */
+ QSIMPLEQ_FOREACH_SAFE(tb, &drop_tables, entry, tb_next) {
+ free_bitmap_clusters(bs, tb);
+ g_free(tb);
+ }
+
+ bitmap_list_free(bm_list);
+ return;
+
+fail:
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ if (bm->dirty_bitmap == NULL || bm->table.offset == 0) {
+ continue;
+ }
+
+ free_bitmap_clusters(bs, &bm->table);
+ }
+
+ QSIMPLEQ_FOREACH_SAFE(tb, &drop_tables, entry, tb_next) {
+ g_free(tb);
+ }
+
+ bitmap_list_free(bm_list);
+}
+
+int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp)
+{
+ BdrvDirtyBitmap *bitmap;
+ Error *local_err = NULL;
+
+ qcow2_store_persistent_dirty_bitmaps(bs, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return -EINVAL;
+ }
+
+ for (bitmap = bdrv_dirty_bitmap_next(bs, NULL); bitmap != NULL;
+ bitmap = bdrv_dirty_bitmap_next(bs, bitmap))
+ {
+ if (bdrv_dirty_bitmap_get_persistance(bitmap)) {
+ bdrv_dirty_bitmap_set_readonly(bitmap, true);
+ }
+ }
+
+ return 0;
+}
+
+bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs,
+ const char *name,
+ uint32_t granularity,
+ Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ bool found;
+ Qcow2BitmapList *bm_list;
+
+ if (check_constraints_on_bitmap(bs, name, granularity, errp) != 0) {
+ goto fail;
+ }
+
+ if (s->nb_bitmaps == 0) {
+ return true;
+ }
+
+ if (s->nb_bitmaps >= QCOW2_MAX_BITMAPS) {
+ error_setg(errp,
+ "Maximum number of persistent bitmaps is already reached");
+ goto fail;
+ }
+
+ if (s->bitmap_directory_size + calc_dir_entry_size(strlen(name), 0) >
+ QCOW2_MAX_BITMAP_DIRECTORY_SIZE)
+ {
+ error_setg(errp, "Not enough space in the bitmap directory");
+ goto fail;
+ }
+
+ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, errp);
+ if (bm_list == NULL) {
+ goto fail;
+ }
+
+ found = find_bitmap_by_name(bm_list, name);
+ bitmap_list_free(bm_list);
+ if (found) {
+ error_setg(errp, "Bitmap with the same name is already stored");
+ goto fail;
+ }
+
+ return true;
+
+fail:
+ error_prepend(errp, "Can't make bitmap '%s' persistent in '%s': ",
+ name, bdrv_get_device_or_node_name(bs));
+ return false;
+}
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 3d341fd9cb..f06c08f64c 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -357,52 +357,6 @@ static int count_contiguous_clusters_unallocated(int nb_clusters,
return i;
}
-/* The crypt function is compatible with the linux cryptoloop
- algorithm for < 4 GB images. NOTE: out_buf == in_buf is
- supported */
-int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
- uint8_t *out_buf, const uint8_t *in_buf,
- int nb_sectors, bool enc,
- Error **errp)
-{
- union {
- uint64_t ll[2];
- uint8_t b[16];
- } ivec;
- int i;
- int ret;
-
- for(i = 0; i < nb_sectors; i++) {
- ivec.ll[0] = cpu_to_le64(sector_num);
- ivec.ll[1] = 0;
- if (qcrypto_cipher_setiv(s->cipher,
- ivec.b, G_N_ELEMENTS(ivec.b),
- errp) < 0) {
- return -1;
- }
- if (enc) {
- ret = qcrypto_cipher_encrypt(s->cipher,
- in_buf,
- out_buf,
- 512,
- errp);
- } else {
- ret = qcrypto_cipher_decrypt(s->cipher,
- in_buf,
- out_buf,
- 512,
- errp);
- }
- if (ret < 0) {
- return -1;
- }
- sector_num++;
- in_buf += 512;
- out_buf += 512;
- }
- return 0;
-}
-
static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
uint64_t src_cluster_offset,
unsigned offset_in_cluster,
@@ -435,19 +389,22 @@ static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs,
uint64_t src_cluster_offset,
+ uint64_t cluster_offset,
unsigned offset_in_cluster,
uint8_t *buffer,
unsigned bytes)
{
if (bytes && bs->encrypted) {
BDRVQcow2State *s = bs->opaque;
- int64_t sector = (src_cluster_offset + offset_in_cluster)
+ int64_t sector = (s->crypt_physical_offset ?
+ (cluster_offset + offset_in_cluster) :
+ (src_cluster_offset + offset_in_cluster))
>> BDRV_SECTOR_BITS;
- assert(s->cipher);
assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
assert((bytes & ~BDRV_SECTOR_MASK) == 0);
- if (qcow2_encrypt_sectors(s, sector, buffer, buffer,
- bytes >> BDRV_SECTOR_BITS, true, NULL) < 0) {
+ assert(s->crypto);
+ if (qcrypto_block_encrypt(s->crypto, sector, buffer,
+ bytes, NULL) < 0) {
return false;
}
}
@@ -834,10 +791,11 @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
/* Encrypt the data if necessary before writing it */
if (bs->encrypted) {
- if (!do_perform_cow_encrypt(bs, m->offset, start->offset,
- start_buffer, start->nb_bytes) ||
- !do_perform_cow_encrypt(bs, m->offset, end->offset,
- end_buffer, end->nb_bytes)) {
+ if (!do_perform_cow_encrypt(bs, m->offset, m->alloc_offset,
+ start->offset, start_buffer,
+ start->nb_bytes) ||
+ !do_perform_cow_encrypt(bs, m->offset, m->alloc_offset,
+ end->offset, end_buffer, end->nb_bytes)) {
ret = -EIO;
goto fail;
}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 7c06061aae..c9b0dcb4f3 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -281,25 +281,6 @@ int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
return 0;
}
-/*
- * Rounds the refcount table size up to avoid growing the table for each single
- * refcount block that is allocated.
- */
-static unsigned int next_refcount_table_size(BDRVQcow2State *s,
- unsigned int min_size)
-{
- unsigned int min_clusters = (min_size >> (s->cluster_bits - 3)) + 1;
- unsigned int refcount_table_clusters =
- MAX(1, s->refcount_table_size >> (s->cluster_bits - 3));
-
- while (min_clusters > refcount_table_clusters) {
- refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
- }
-
- return refcount_table_clusters << (s->cluster_bits - 3);
-}
-
-
/* Checks if two offsets are described by the same refcount block */
static int in_same_refcount_block(BDRVQcow2State *s, uint64_t offset_a,
uint64_t offset_b)
@@ -321,7 +302,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
{
BDRVQcow2State *s = bs->opaque;
unsigned int refcount_table_index;
- int ret;
+ int64_t ret;
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC);
@@ -396,7 +377,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
refcount_block);
if (ret < 0) {
- goto fail_block;
+ goto fail;
}
memset(*refcount_block, 0, s->cluster_size);
@@ -411,12 +392,12 @@ static int alloc_refcount_block(BlockDriverState *bs,
ret = update_refcount(bs, new_block, s->cluster_size, 1, false,
QCOW2_DISCARD_NEVER);
if (ret < 0) {
- goto fail_block;
+ goto fail;
}
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
- goto fail_block;
+ goto fail;
}
/* Initialize the new refcount block only after updating its refcount,
@@ -424,7 +405,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
refcount_block);
if (ret < 0) {
- goto fail_block;
+ goto fail;
}
memset(*refcount_block, 0, s->cluster_size);
@@ -435,7 +416,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache, *refcount_block);
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
- goto fail_block;
+ goto fail;
}
/* If the refcount table is big enough, just hook the block up there */
@@ -446,7 +427,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
&data64, sizeof(data64));
if (ret < 0) {
- goto fail_block;
+ goto fail;
}
s->refcount_table[refcount_table_index] = new_block;
@@ -490,74 +471,201 @@ static int alloc_refcount_block(BlockDriverState *bs,
(new_block >> s->cluster_bits) + 1),
s->refcount_block_size);
- if (blocks_used > QCOW_MAX_REFTABLE_SIZE / sizeof(uint64_t)) {
- return -EFBIG;
+ /* Create the new refcount table and blocks */
+ uint64_t meta_offset = (blocks_used * s->refcount_block_size) *
+ s->cluster_size;
+
+ ret = qcow2_refcount_area(bs, meta_offset, 0, false,
+ refcount_table_index, new_block);
+ if (ret < 0) {
+ return ret;
}
- /* And now we need at least one block more for the new metadata */
- uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
- uint64_t last_table_size;
- uint64_t blocks_clusters;
- do {
- uint64_t table_clusters =
- size_to_clusters(s, table_size * sizeof(uint64_t));
- blocks_clusters = 1 +
- DIV_ROUND_UP(table_clusters, s->refcount_block_size);
- uint64_t meta_clusters = table_clusters + blocks_clusters;
+ ret = load_refcount_block(bs, new_block, refcount_block);
+ if (ret < 0) {
+ return ret;
+ }
- last_table_size = table_size;
- table_size = next_refcount_table_size(s, blocks_used +
- DIV_ROUND_UP(meta_clusters, s->refcount_block_size));
+ /* If we were trying to do the initial refcount update for some cluster
+ * allocation, we might have used the same clusters to store newly
+ * allocated metadata. Make the caller search some new space. */
+ return -EAGAIN;
- } while (last_table_size != table_size);
+fail:
+ if (*refcount_block != NULL) {
+ qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
+ }
+ return ret;
+}
-#ifdef DEBUG_ALLOC2
- fprintf(stderr, "qcow2: Grow refcount table %" PRId32 " => %" PRId64 "\n",
- s->refcount_table_size, table_size);
-#endif
+/*
+ * Starting at @start_offset, this function creates new self-covering refcount
+ * structures: A new refcount table and refcount blocks which cover all of
+ * themselves, and a number of @additional_clusters beyond their end.
+ * @start_offset must be at the end of the image file, that is, there must be
+ * only empty space beyond it.
+ * If @exact_size is false, the refcount table will have 50 % more entries than
+ * necessary so it will not need to grow again soon.
+ * If @new_refblock_offset is not zero, it contains the offset of a refcount
+ * block that should be entered into the new refcount table at index
+ * @new_refblock_index.
+ *
+ * Returns: The offset after the new refcount structures (i.e. where the
+ * @additional_clusters may be placed) on success, -errno on error.
+ */
+int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
+ uint64_t additional_clusters, bool exact_size,
+ int new_refblock_index,
+ uint64_t new_refblock_offset)
+{
+ BDRVQcow2State *s = bs->opaque;
+ uint64_t total_refblock_count_u64, additional_refblock_count;
+ int total_refblock_count, table_size, area_reftable_index, table_clusters;
+ int i;
+ uint64_t table_offset, block_offset, end_offset;
+ int ret;
+ uint64_t *new_table;
- /* Create the new refcount table and blocks */
- uint64_t meta_offset = (blocks_used * s->refcount_block_size) *
- s->cluster_size;
- uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
- uint64_t *new_table = g_try_new0(uint64_t, table_size);
- void *new_blocks = g_try_malloc0(blocks_clusters * s->cluster_size);
+ assert(!(start_offset % s->cluster_size));
+
+ qcow2_refcount_metadata_size(start_offset / s->cluster_size +
+ additional_clusters,
+ s->cluster_size, s->refcount_order,
+ !exact_size, &total_refblock_count_u64);
+ if (total_refblock_count_u64 > QCOW_MAX_REFTABLE_SIZE) {
+ return -EFBIG;
+ }
+ total_refblock_count = total_refblock_count_u64;
+
+ /* Index in the refcount table of the first refcount block to cover the area
+ * of refcount structures we are about to create; we know that
+ * @total_refblock_count can cover @start_offset, so this will definitely
+ * fit into an int. */
+ area_reftable_index = (start_offset / s->cluster_size) /
+ s->refcount_block_size;
- assert(table_size > 0 && blocks_clusters > 0);
- if (new_table == NULL || new_blocks == NULL) {
+ if (exact_size) {
+ table_size = total_refblock_count;
+ } else {
+ table_size = total_refblock_count +
+ DIV_ROUND_UP(total_refblock_count, 2);
+ }
+ /* The qcow2 file can only store the reftable size in number of clusters */
+ table_size = ROUND_UP(table_size, s->cluster_size / sizeof(uint64_t));
+ table_clusters = (table_size * sizeof(uint64_t)) / s->cluster_size;
+
+ if (table_size > QCOW_MAX_REFTABLE_SIZE) {
+ return -EFBIG;
+ }
+
+ new_table = g_try_new0(uint64_t, table_size);
+
+ assert(table_size > 0);
+ if (new_table == NULL) {
ret = -ENOMEM;
- goto fail_table;
+ goto fail;
}
/* Fill the new refcount table */
- memcpy(new_table, s->refcount_table,
- s->refcount_table_size * sizeof(uint64_t));
- new_table[refcount_table_index] = new_block;
+ if (table_size > s->max_refcount_table_index) {
+ /* We're actually growing the reftable */
+ memcpy(new_table, s->refcount_table,
+ (s->max_refcount_table_index + 1) * sizeof(uint64_t));
+ } else {
+ /* Improbable case: We're shrinking the reftable. However, the caller
+ * has assured us that there is only empty space beyond @start_offset,
+ * so we can simply drop all of the refblocks that won't fit into the
+ * new reftable. */
+ memcpy(new_table, s->refcount_table, table_size * sizeof(uint64_t));
+ }
- int i;
- for (i = 0; i < blocks_clusters; i++) {
- new_table[blocks_used + i] = meta_offset + (i * s->cluster_size);
+ if (new_refblock_offset) {
+ assert(new_refblock_index < total_refblock_count);
+ new_table[new_refblock_index] = new_refblock_offset;
}
- /* Fill the refcount blocks */
- uint64_t table_clusters = size_to_clusters(s, table_size * sizeof(uint64_t));
- int block = 0;
- for (i = 0; i < table_clusters + blocks_clusters; i++) {
- s->set_refcount(new_blocks, block++, 1);
+ /* Count how many new refblocks we have to create */
+ additional_refblock_count = 0;
+ for (i = area_reftable_index; i < total_refblock_count; i++) {
+ if (!new_table[i]) {
+ additional_refblock_count++;
+ }
+ }
+
+ table_offset = start_offset + additional_refblock_count * s->cluster_size;
+ end_offset = table_offset + table_clusters * s->cluster_size;
+
+ /* Fill the refcount blocks, and create new ones, if necessary */
+ block_offset = start_offset;
+ for (i = area_reftable_index; i < total_refblock_count; i++) {
+ void *refblock_data;
+ uint64_t first_offset_covered;
+
+ /* Reuse an existing refblock if possible, create a new one otherwise */
+ if (new_table[i]) {
+ ret = qcow2_cache_get(bs, s->refcount_block_cache, new_table[i],
+ &refblock_data);
+ if (ret < 0) {
+ goto fail;
+ }
+ } else {
+ ret = qcow2_cache_get_empty(bs, s->refcount_block_cache,
+ block_offset, &refblock_data);
+ if (ret < 0) {
+ goto fail;
+ }
+ memset(refblock_data, 0, s->cluster_size);
+ qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
+ refblock_data);
+
+ new_table[i] = block_offset;
+ block_offset += s->cluster_size;
+ }
+
+ /* First host offset covered by this refblock */
+ first_offset_covered = (uint64_t)i * s->refcount_block_size *
+ s->cluster_size;
+ if (first_offset_covered < end_offset) {
+ int j, end_index;
+
+ /* Set the refcount of all of the new refcount structures to 1 */
+
+ if (first_offset_covered < start_offset) {
+ assert(i == area_reftable_index);
+ j = (start_offset - first_offset_covered) / s->cluster_size;
+ assert(j < s->refcount_block_size);
+ } else {
+ j = 0;
+ }
+
+ end_index = MIN((end_offset - first_offset_covered) /
+ s->cluster_size,
+ s->refcount_block_size);
+
+ for (; j < end_index; j++) {
+ /* The caller guaranteed us this space would be empty */
+ assert(s->get_refcount(refblock_data, j) == 0);
+ s->set_refcount(refblock_data, j, 1);
+ }
+
+ qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
+ refblock_data);
+ }
+
+ qcow2_cache_put(bs, s->refcount_block_cache, &refblock_data);
}
+ assert(block_offset == table_offset);
+
/* Write refcount blocks to disk */
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
- ret = bdrv_pwrite_sync(bs->file, meta_offset, new_blocks,
- blocks_clusters * s->cluster_size);
- g_free(new_blocks);
- new_blocks = NULL;
+ ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
- goto fail_table;
+ goto fail;
}
/* Write refcount table to disk */
- for(i = 0; i < table_size; i++) {
+ for (i = 0; i < total_refblock_count; i++) {
cpu_to_be64s(&new_table[i]);
}
@@ -565,10 +673,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
ret = bdrv_pwrite_sync(bs->file, table_offset, new_table,
table_size * sizeof(uint64_t));
if (ret < 0) {
- goto fail_table;
+ goto fail;
}
- for(i = 0; i < table_size; i++) {
+ for (i = 0; i < total_refblock_count; i++) {
be64_to_cpus(&new_table[i]);
}
@@ -584,7 +692,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
offsetof(QCowHeader, refcount_table_offset),
&data, sizeof(data));
if (ret < 0) {
- goto fail_table;
+ goto fail;
}
/* And switch it in memory */
@@ -601,23 +709,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
QCOW2_DISCARD_OTHER);
- ret = load_refcount_block(bs, new_block, refcount_block);
- if (ret < 0) {
- return ret;
- }
+ return end_offset;
- /* If we were trying to do the initial refcount update for some cluster
- * allocation, we might have used the same clusters to store newly
- * allocated metadata. Make the caller search some new space. */
- return -EAGAIN;
-
-fail_table:
- g_free(new_blocks);
+fail:
g_free(new_table);
-fail_block:
- if (*refcount_block != NULL) {
- qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
- }
return ret;
}
@@ -1323,11 +1418,10 @@ static int realloc_refcount_array(BDRVQcow2State *s, void **array,
*
* Modifies the number of errors in res.
*/
-static int inc_refcounts(BlockDriverState *bs,
- BdrvCheckResult *res,
- void **refcount_table,
- int64_t *refcount_table_size,
- int64_t offset, int64_t size)
+int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table,
+ int64_t *refcount_table_size,
+ int64_t offset, int64_t size)
{
BDRVQcow2State *s = bs->opaque;
uint64_t start, last, cluster_offset, k, refcount;
@@ -1420,8 +1514,9 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
nb_csectors = ((l2_entry >> s->csize_shift) &
s->csize_mask) + 1;
l2_entry &= s->cluster_offset_mask;
- ret = inc_refcounts(bs, res, refcount_table, refcount_table_size,
- l2_entry & ~511, nb_csectors * 512);
+ ret = qcow2_inc_refcounts_imrt(bs, res,
+ refcount_table, refcount_table_size,
+ l2_entry & ~511, nb_csectors * 512);
if (ret < 0) {
goto fail;
}
@@ -1454,8 +1549,9 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
}
/* Mark cluster as used */
- ret = inc_refcounts(bs, res, refcount_table, refcount_table_size,
- offset, s->cluster_size);
+ ret = qcow2_inc_refcounts_imrt(bs, res,
+ refcount_table, refcount_table_size,
+ offset, s->cluster_size);
if (ret < 0) {
goto fail;
}
@@ -1508,8 +1604,8 @@ static int check_refcounts_l1(BlockDriverState *bs,
l1_size2 = l1_size * sizeof(uint64_t);
/* Mark L1 table as used */
- ret = inc_refcounts(bs, res, refcount_table, refcount_table_size,
- l1_table_offset, l1_size2);
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size,
+ l1_table_offset, l1_size2);
if (ret < 0) {
goto fail;
}
@@ -1538,8 +1634,9 @@ static int check_refcounts_l1(BlockDriverState *bs,
if (l2_offset) {
/* Mark L2 table as used */
l2_offset &= L1E_OFFSET_MASK;
- ret = inc_refcounts(bs, res, refcount_table, refcount_table_size,
- l2_offset, s->cluster_size);
+ ret = qcow2_inc_refcounts_imrt(bs, res,
+ refcount_table, refcount_table_size,
+ l2_offset, s->cluster_size);
if (ret < 0) {
goto fail;
}
@@ -1730,7 +1827,7 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
}
ret = bdrv_truncate(bs->file, offset + s->cluster_size,
- &local_err);
+ PREALLOC_MODE_OFF, &local_err);
if (ret < 0) {
error_report_err(local_err);
goto resize_fail;
@@ -1757,14 +1854,15 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
}
res->corruptions_fixed++;
- ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
- offset, s->cluster_size);
+ ret = qcow2_inc_refcounts_imrt(bs, res,
+ refcount_table, nb_clusters,
+ offset, s->cluster_size);
if (ret < 0) {
return ret;
}
/* No need to check whether the refcount is now greater than 1:
* This area was just allocated and zeroed, so it can only be
- * exactly 1 after inc_refcounts() */
+ * exactly 1 after qcow2_inc_refcounts_imrt() */
continue;
resize_fail:
@@ -1779,8 +1877,8 @@ resize_fail:
}
if (offset != 0) {
- ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
- offset, s->cluster_size);
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
+ offset, s->cluster_size);
if (ret < 0) {
return ret;
}
@@ -1820,8 +1918,8 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
}
/* header */
- ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
- 0, s->cluster_size);
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
+ 0, s->cluster_size);
if (ret < 0) {
return ret;
}
@@ -1842,16 +1940,32 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
return ret;
}
}
- ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
- s->snapshots_offset, s->snapshots_size);
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
+ s->snapshots_offset, s->snapshots_size);
if (ret < 0) {
return ret;
}
/* refcount data */
- ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
- s->refcount_table_offset,
- s->refcount_table_size * sizeof(uint64_t));
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
+ s->refcount_table_offset,
+ s->refcount_table_size * sizeof(uint64_t));
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* encryption */
+ if (s->crypto_header.length) {
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
+ s->crypto_header.offset,
+ s->crypto_header.length);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ /* bitmaps */
+ ret = qcow2_check_bitmaps_refcounts(bs, res, refcount_table, nb_clusters);
if (ret < 0) {
return ret;
}
diff --git a/block/qcow2.c b/block/qcow2.c
index 2f94f0326e..d5790af1e0 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -37,6 +37,9 @@
#include "qemu/option_int.h"
#include "qemu/cutils.h"
#include "qemu/bswap.h"
+#include "qapi/opts-visitor.h"
+#include "qapi-visit.h"
+#include "block/crypto.h"
/*
Differences with QCOW:
@@ -63,6 +66,8 @@ typedef struct {
#define QCOW2_EXT_MAGIC_END 0
#define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
#define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857
+#define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77
+#define QCOW2_EXT_MAGIC_BITMAPS 0x23852875
static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
{
@@ -77,6 +82,86 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
}
+static ssize_t qcow2_crypto_hdr_read_func(QCryptoBlock *block, size_t offset,
+ uint8_t *buf, size_t buflen,
+ void *opaque, Error **errp)
+{
+ BlockDriverState *bs = opaque;
+ BDRVQcow2State *s = bs->opaque;
+ ssize_t ret;
+
+ if ((offset + buflen) > s->crypto_header.length) {
+ error_setg(errp, "Request for data outside of extension header");
+ return -1;
+ }
+
+ ret = bdrv_pread(bs->file,
+ s->crypto_header.offset + offset, buf, buflen);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not read encryption header");
+ return -1;
+ }
+ return ret;
+}
+
+
+static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen,
+ void *opaque, Error **errp)
+{
+ BlockDriverState *bs = opaque;
+ BDRVQcow2State *s = bs->opaque;
+ int64_t ret;
+ int64_t clusterlen;
+
+ ret = qcow2_alloc_clusters(bs, headerlen);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "Cannot allocate cluster for LUKS header size %zu",
+ headerlen);
+ return -1;
+ }
+
+ s->crypto_header.length = headerlen;
+ s->crypto_header.offset = ret;
+
+ /* Zero fill remaining space in cluster so it has predictable
+ * content in case of future spec changes */
+ clusterlen = size_to_clusters(s, headerlen) * s->cluster_size;
+ ret = bdrv_pwrite_zeroes(bs->file,
+ ret + headerlen,
+ clusterlen - headerlen, 0);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not zero fill encryption header");
+ return -1;
+ }
+
+ return ret;
+}
+
+
+static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset,
+ const uint8_t *buf, size_t buflen,
+ void *opaque, Error **errp)
+{
+ BlockDriverState *bs = opaque;
+ BDRVQcow2State *s = bs->opaque;
+ ssize_t ret;
+
+ if ((offset + buflen) > s->crypto_header.length) {
+ error_setg(errp, "Request for data outside of extension header");
+ return -1;
+ }
+
+ ret = bdrv_pwrite(bs->file,
+ s->crypto_header.offset + offset, buf, buflen);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not read encryption header");
+ return -1;
+ }
+ return ret;
+}
+
+
/*
* read qcow2 extension and fill bs
* start reading from start_offset
@@ -86,12 +171,18 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
*/
static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
uint64_t end_offset, void **p_feature_table,
+ int flags, bool *need_update_header,
Error **errp)
{
BDRVQcow2State *s = bs->opaque;
QCowExtension ext;
uint64_t offset;
int ret;
+ Qcow2BitmapHeaderExt bitmaps_ext;
+
+ if (need_update_header != NULL) {
+ *need_update_header = false;
+ }
#ifdef DEBUG_EXT
printf("qcow2_read_extensions: start=%ld end=%ld\n", start_offset, end_offset);
@@ -162,6 +253,126 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
}
break;
+ case QCOW2_EXT_MAGIC_CRYPTO_HEADER: {
+ unsigned int cflags = 0;
+ if (s->crypt_method_header != QCOW_CRYPT_LUKS) {
+ error_setg(errp, "CRYPTO header extension only "
+ "expected with LUKS encryption method");
+ return -EINVAL;
+ }
+ if (ext.len != sizeof(Qcow2CryptoHeaderExtension)) {
+ error_setg(errp, "CRYPTO header extension size %u, "
+ "but expected size %zu", ext.len,
+ sizeof(Qcow2CryptoHeaderExtension));
+ return -EINVAL;
+ }
+
+ ret = bdrv_pread(bs->file, offset, &s->crypto_header, ext.len);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "Unable to read CRYPTO header extension");
+ return ret;
+ }
+ be64_to_cpus(&s->crypto_header.offset);
+ be64_to_cpus(&s->crypto_header.length);
+
+ if ((s->crypto_header.offset % s->cluster_size) != 0) {
+ error_setg(errp, "Encryption header offset '%" PRIu64 "' is "
+ "not a multiple of cluster size '%u'",
+ s->crypto_header.offset, s->cluster_size);
+ return -EINVAL;
+ }
+
+ if (flags & BDRV_O_NO_IO) {
+ cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
+ }
+ s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.",
+ qcow2_crypto_hdr_read_func,
+ bs, cflags, errp);
+ if (!s->crypto) {
+ return -EINVAL;
+ }
+ } break;
+
+ case QCOW2_EXT_MAGIC_BITMAPS:
+ if (ext.len != sizeof(bitmaps_ext)) {
+ error_setg_errno(errp, -ret, "bitmaps_ext: "
+ "Invalid extension length");
+ return -EINVAL;
+ }
+
+ if (!(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS)) {
+ error_report("WARNING: a program lacking bitmap support "
+ "modified this file, so all bitmaps are now "
+ "considered inconsistent. Some clusters may be "
+ "leaked, run 'qemu-img check -r' on the image "
+ "file to fix.");
+ if (need_update_header != NULL) {
+ /* Updating is needed to drop invalid bitmap extension. */
+ *need_update_header = true;
+ }
+ break;
+ }
+
+ ret = bdrv_pread(bs->file, offset, &bitmaps_ext, ext.len);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "bitmaps_ext: "
+ "Could not read ext header");
+ return ret;
+ }
+
+ if (bitmaps_ext.reserved32 != 0) {
+ error_setg_errno(errp, -ret, "bitmaps_ext: "
+ "Reserved field is not zero");
+ return -EINVAL;
+ }
+
+ be32_to_cpus(&bitmaps_ext.nb_bitmaps);
+ be64_to_cpus(&bitmaps_ext.bitmap_directory_size);
+ be64_to_cpus(&bitmaps_ext.bitmap_directory_offset);
+
+ if (bitmaps_ext.nb_bitmaps > QCOW2_MAX_BITMAPS) {
+ error_setg(errp,
+ "bitmaps_ext: Image has %" PRIu32 " bitmaps, "
+ "exceeding the QEMU supported maximum of %d",
+ bitmaps_ext.nb_bitmaps, QCOW2_MAX_BITMAPS);
+ return -EINVAL;
+ }
+
+ if (bitmaps_ext.nb_bitmaps == 0) {
+ error_setg(errp, "found bitmaps extension with zero bitmaps");
+ return -EINVAL;
+ }
+
+ if (bitmaps_ext.bitmap_directory_offset & (s->cluster_size - 1)) {
+ error_setg(errp, "bitmaps_ext: "
+ "invalid bitmap directory offset");
+ return -EINVAL;
+ }
+
+ if (bitmaps_ext.bitmap_directory_size >
+ QCOW2_MAX_BITMAP_DIRECTORY_SIZE) {
+ error_setg(errp, "bitmaps_ext: "
+ "bitmap directory size (%" PRIu64 ") exceeds "
+ "the maximum supported size (%d)",
+ bitmaps_ext.bitmap_directory_size,
+ QCOW2_MAX_BITMAP_DIRECTORY_SIZE);
+ return -EINVAL;
+ }
+
+ s->nb_bitmaps = bitmaps_ext.nb_bitmaps;
+ s->bitmap_directory_offset =
+ bitmaps_ext.bitmap_directory_offset;
+ s->bitmap_directory_size =
+ bitmaps_ext.bitmap_directory_size;
+
+#ifdef DEBUG_EXT
+ printf("Qcow2: Got bitmaps extension: "
+ "offset=%" PRIu64 " nb_bitmaps=%" PRIu32 "\n",
+ s->bitmap_directory_offset, s->nb_bitmaps);
+#endif
+ break;
+
default:
/* unknown magic - save it in case we need to rewrite the header */
{
@@ -461,6 +672,8 @@ static QemuOptsList qcow2_runtime_opts = {
.type = QEMU_OPT_NUMBER,
.help = "Clean unused cache entries after this time (in seconds)",
},
+ BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.",
+ "ID of secret providing qcow2 AES key or LUKS passphrase"),
{ /* end of list */ }
},
};
@@ -585,6 +798,7 @@ typedef struct Qcow2ReopenState {
int overlap_check;
bool discard_passthrough[QCOW2_DISCARD_MAX];
uint64_t cache_clean_interval;
+ QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */
} Qcow2ReopenState;
static int qcow2_update_options_prepare(BlockDriverState *bs,
@@ -598,9 +812,14 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
int overlap_check_template = 0;
uint64_t l2_cache_size, refcount_cache_size;
int i;
+ const char *encryptfmt;
+ QDict *encryptopts = NULL;
Error *local_err = NULL;
int ret;
+ qdict_extract_subqdict(options, &encryptopts, "encrypt.");
+ encryptfmt = qdict_get_try_str(encryptopts, "format");
+
opts = qemu_opts_create(&qcow2_runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
@@ -751,8 +970,55 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
r->discard_passthrough[QCOW2_DISCARD_OTHER] =
qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
+ switch (s->crypt_method_header) {
+ case QCOW_CRYPT_NONE:
+ if (encryptfmt) {
+ error_setg(errp, "No encryption in image header, but options "
+ "specified format '%s'", encryptfmt);
+ ret = -EINVAL;
+ goto fail;
+ }
+ break;
+
+ case QCOW_CRYPT_AES:
+ if (encryptfmt && !g_str_equal(encryptfmt, "aes")) {
+ error_setg(errp,
+ "Header reported 'aes' encryption format but "
+ "options specify '%s'", encryptfmt);
+ ret = -EINVAL;
+ goto fail;
+ }
+ qdict_del(encryptopts, "format");
+ r->crypto_opts = block_crypto_open_opts_init(
+ Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
+ break;
+
+ case QCOW_CRYPT_LUKS:
+ if (encryptfmt && !g_str_equal(encryptfmt, "luks")) {
+ error_setg(errp,
+ "Header reported 'luks' encryption format but "
+ "options specify '%s'", encryptfmt);
+ ret = -EINVAL;
+ goto fail;
+ }
+ qdict_del(encryptopts, "format");
+ r->crypto_opts = block_crypto_open_opts_init(
+ Q_CRYPTO_BLOCK_FORMAT_LUKS, encryptopts, errp);
+ break;
+
+ default:
+ error_setg(errp, "Unsupported encryption method %d",
+ s->crypt_method_header);
+ break;
+ }
+ if (s->crypt_method_header != QCOW_CRYPT_NONE && !r->crypto_opts) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
ret = 0;
fail:
+ QDECREF(encryptopts);
qemu_opts_del(opts);
opts = NULL;
return ret;
@@ -785,6 +1051,9 @@ static void qcow2_update_options_commit(BlockDriverState *bs,
s->cache_clean_interval = r->cache_clean_interval;
cache_clean_timer_init(bs, bdrv_get_aio_context(bs));
}
+
+ qapi_free_QCryptoBlockOpenOptions(s->crypto_opts);
+ s->crypto_opts = r->crypto_opts;
}
static void qcow2_update_options_abort(BlockDriverState *bs,
@@ -796,6 +1065,7 @@ static void qcow2_update_options_abort(BlockDriverState *bs,
if (r->refcount_block_cache) {
qcow2_cache_destroy(bs, r->refcount_block_cache);
}
+ qapi_free_QCryptoBlockOpenOptions(r->crypto_opts);
}
static int qcow2_update_options(BlockDriverState *bs, QDict *options,
@@ -824,6 +1094,7 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
Error *local_err = NULL;
uint64_t ext_end;
uint64_t l1_vm_state_index;
+ bool update_header = false;
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
if (ret < 0) {
@@ -929,7 +1200,7 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
if (s->incompatible_features & ~QCOW2_INCOMPAT_MASK) {
void *feature_table = NULL;
qcow2_read_extensions(bs, header.header_length, ext_end,
- &feature_table, NULL);
+ &feature_table, flags, NULL, NULL);
report_unsupported_feature(errp, feature_table,
s->incompatible_features &
~QCOW2_INCOMPAT_MASK);
@@ -961,18 +1232,6 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
s->refcount_max = UINT64_C(1) << (s->refcount_bits - 1);
s->refcount_max += s->refcount_max - 1;
- if (header.crypt_method > QCOW_CRYPT_AES) {
- error_setg(errp, "Unsupported encryption method: %" PRIu32,
- header.crypt_method);
- ret = -EINVAL;
- goto fail;
- }
- if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128,
- QCRYPTO_CIPHER_MODE_CBC)) {
- error_setg(errp, "AES cipher not available");
- ret = -EINVAL;
- goto fail;
- }
s->crypt_method_header = header.crypt_method;
if (s->crypt_method_header) {
if (bdrv_uses_whitelist() &&
@@ -989,6 +1248,15 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
+ if (s->crypt_method_header == QCOW_CRYPT_AES) {
+ s->crypt_physical_offset = false;
+ } else {
+ /* Assuming LUKS and any future crypt methods we
+ * add will all use physical offsets, due to the
+ * fact that the alternative is insecure... */
+ s->crypt_physical_offset = true;
+ }
+
bs->encrypted = true;
}
@@ -1116,12 +1384,36 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
/* read qcow2 extensions */
if (qcow2_read_extensions(bs, header.header_length, ext_end, NULL,
- &local_err)) {
+ flags, &update_header, &local_err)) {
error_propagate(errp, local_err);
ret = -EINVAL;
goto fail;
}
+ /* qcow2_read_extension may have set up the crypto context
+ * if the crypt method needs a header region, some methods
+ * don't need header extensions, so must check here
+ */
+ if (s->crypt_method_header && !s->crypto) {
+ if (s->crypt_method_header == QCOW_CRYPT_AES) {
+ unsigned int cflags = 0;
+ if (flags & BDRV_O_NO_IO) {
+ cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
+ }
+ s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.",
+ NULL, NULL, cflags, errp);
+ if (!s->crypto) {
+ ret = -EINVAL;
+ goto fail;
+ }
+ } else if (!(flags & BDRV_O_NO_IO)) {
+ error_setg(errp, "Missing CRYPTO header for crypt method %d",
+ s->crypt_method_header);
+ ret = -EINVAL;
+ goto fail;
+ }
+ }
+
/* read the backing file name */
if (header.backing_file_offset != 0) {
len = header.backing_file_size;
@@ -1152,8 +1444,23 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
}
/* Clear unknown autoclear feature bits */
- if (!bs->read_only && !(flags & BDRV_O_INACTIVE) && s->autoclear_features) {
- s->autoclear_features = 0;
+ update_header |= s->autoclear_features & ~QCOW2_AUTOCLEAR_MASK;
+ update_header =
+ update_header && !bs->read_only && !(flags & BDRV_O_INACTIVE);
+ if (update_header) {
+ s->autoclear_features &= QCOW2_AUTOCLEAR_MASK;
+ }
+
+ if (qcow2_load_autoloading_dirty_bitmaps(bs, &local_err)) {
+ update_header = false;
+ }
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (update_header) {
ret = qcow2_update_header(bs);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not update qcow2 header");
@@ -1202,6 +1509,8 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
}
g_free(s->cluster_cache);
qemu_vfree(s->cluster_data);
+ qcrypto_block_free(s->crypto);
+ qapi_free_QCryptoBlockOpenOptions(s->crypto_opts);
return ret;
}
@@ -1229,41 +1538,6 @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
bs->bl.pdiscard_alignment = s->cluster_size;
}
-static int qcow2_set_key(BlockDriverState *bs, const char *key)
-{
- BDRVQcow2State *s = bs->opaque;
- uint8_t keybuf[16];
- int len, i;
- Error *err = NULL;
-
- memset(keybuf, 0, 16);
- len = strlen(key);
- if (len > 16)
- len = 16;
- /* XXX: we could compress the chars to 7 bits to increase
- entropy */
- for(i = 0;i < len;i++) {
- keybuf[i] = key[i];
- }
- assert(bs->encrypted);
-
- qcrypto_cipher_free(s->cipher);
- s->cipher = qcrypto_cipher_new(
- QCRYPTO_CIPHER_ALG_AES_128,
- QCRYPTO_CIPHER_MODE_CBC,
- keybuf, G_N_ELEMENTS(keybuf),
- &err);
-
- if (!s->cipher) {
- /* XXX would be nice if errors in this method could
- * be properly propagate to the caller. Would need
- * the bdrv_set_key() API signature to be fixed. */
- error_free(err);
- return -1;
- }
- return 0;
-}
-
static int qcow2_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
@@ -1281,6 +1555,11 @@ static int qcow2_reopen_prepare(BDRVReopenState *state,
/* We need to write out any unwritten data if we reopen read-only. */
if ((state->flags & BDRV_O_RDWR) == 0) {
+ ret = qcow2_reopen_bitmaps_ro(state->bs, errp);
+ if (ret < 0) {
+ goto fail;
+ }
+
ret = bdrv_flush(state->bs);
if (ret < 0) {
goto fail;
@@ -1379,7 +1658,7 @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
*pnum = bytes >> BDRV_SECTOR_BITS;
if (cluster_offset != 0 && ret != QCOW2_CLUSTER_COMPRESSED &&
- !s->cipher) {
+ !s->crypto) {
index_in_cluster = sector_num & (s->cluster_sectors - 1);
cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
*file = bs->file->bs;
@@ -1436,7 +1715,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
/* prepare next request */
cur_bytes = MIN(bytes, INT_MAX);
- if (s->cipher) {
+ if (s->crypto) {
cur_bytes = MIN(cur_bytes,
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
}
@@ -1506,7 +1785,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
}
if (bs->encrypted) {
- assert(s->cipher);
+ assert(s->crypto);
/*
* For encrypted images, read everything into a temporary
@@ -1538,14 +1817,17 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
goto fail;
}
if (bs->encrypted) {
- assert(s->cipher);
+ assert(s->crypto);
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
assert((cur_bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
Error *err = NULL;
- if (qcow2_encrypt_sectors(s, offset >> BDRV_SECTOR_BITS,
- cluster_data, cluster_data,
- cur_bytes >> BDRV_SECTOR_BITS,
- false, &err) < 0) {
+ if (qcrypto_block_decrypt(s->crypto,
+ (s->crypt_physical_offset ?
+ cluster_offset + offset_in_cluster :
+ offset) >> BDRV_SECTOR_BITS,
+ cluster_data,
+ cur_bytes,
+ &err) < 0) {
error_free(err);
ret = -EIO;
goto fail;
@@ -1661,7 +1943,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
if (bs->encrypted) {
Error *err = NULL;
- assert(s->cipher);
+ assert(s->crypto);
if (!cluster_data) {
cluster_data = qemu_try_blockalign(bs->file->bs,
QCOW_MAX_CRYPT_CLUSTERS
@@ -1676,10 +1958,12 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size);
- if (qcow2_encrypt_sectors(s, offset >> BDRV_SECTOR_BITS,
- cluster_data, cluster_data,
- cur_bytes >>BDRV_SECTOR_BITS,
- true, &err) < 0) {
+ if (qcrypto_block_encrypt(s->crypto,
+ (s->crypt_physical_offset ?
+ cluster_offset + offset_in_cluster :
+ offset) >> BDRV_SECTOR_BITS,
+ cluster_data,
+ cur_bytes, &err) < 0) {
error_free(err);
ret = -EIO;
goto fail;
@@ -1741,8 +2025,6 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
ret = 0;
fail:
- qemu_co_mutex_unlock(&s->lock);
-
while (l2meta != NULL) {
QCowL2Meta *next;
@@ -1756,6 +2038,8 @@ fail:
l2meta = next;
}
+ qemu_co_mutex_unlock(&s->lock);
+
qemu_iovec_destroy(&hd_qiov);
qemu_vfree(cluster_data);
trace_qcow2_writev_done_req(qemu_coroutine_self(), ret);
@@ -1767,6 +2051,7 @@ static int qcow2_inactivate(BlockDriverState *bs)
{
BDRVQcow2State *s = bs->opaque;
int ret, result = 0;
+ Error *local_err = NULL;
ret = qcow2_cache_flush(bs, s->l2_table_cache);
if (ret) {
@@ -1782,6 +2067,14 @@ static int qcow2_inactivate(BlockDriverState *bs)
strerror(-ret));
}
+ qcow2_store_persistent_dirty_bitmaps(bs, &local_err);
+ if (local_err != NULL) {
+ result = -EINVAL;
+ error_report_err(local_err);
+ error_report("Persistent bitmaps are lost for node '%s'",
+ bdrv_get_device_or_node_name(bs));
+ }
+
if (result == 0) {
qcow2_mark_clean(bs);
}
@@ -1804,8 +2097,8 @@ static void qcow2_close(BlockDriverState *bs)
qcow2_cache_destroy(bs, s->l2_table_cache);
qcow2_cache_destroy(bs, s->refcount_block_cache);
- qcrypto_cipher_free(s->cipher);
- s->cipher = NULL;
+ qcrypto_block_free(s->crypto);
+ s->crypto = NULL;
g_free(s->unknown_header_fields);
cleanup_unknown_header_ext(bs);
@@ -1823,7 +2116,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
{
BDRVQcow2State *s = bs->opaque;
int flags = s->flags;
- QCryptoCipher *cipher = NULL;
+ QCryptoBlock *crypto = NULL;
QDict *options;
Error *local_err = NULL;
int ret;
@@ -1833,8 +2126,8 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
* that means we don't have to worry about reopening them here.
*/
- cipher = s->cipher;
- s->cipher = NULL;
+ crypto = s->crypto;
+ s->crypto = NULL;
qcow2_close(bs);
@@ -1855,7 +2148,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
return;
}
- s->cipher = cipher;
+ s->crypto = crypto;
}
static size_t header_ext_add(char *buf, uint32_t magic, const void *s,
@@ -1981,6 +2274,22 @@ int qcow2_update_header(BlockDriverState *bs)
buflen -= ret;
}
+ /* Full disk encryption header pointer extension */
+ if (s->crypto_header.offset != 0) {
+ cpu_to_be64s(&s->crypto_header.offset);
+ cpu_to_be64s(&s->crypto_header.length);
+ ret = header_ext_add(buf, QCOW2_EXT_MAGIC_CRYPTO_HEADER,
+ &s->crypto_header, sizeof(s->crypto_header),
+ buflen);
+ be64_to_cpus(&s->crypto_header.offset);
+ be64_to_cpus(&s->crypto_header.length);
+ if (ret < 0) {
+ goto fail;
+ }
+ buf += ret;
+ buflen -= ret;
+ }
+
/* Feature table */
if (s->qcow_version >= 3) {
Qcow2Feature features[] = {
@@ -2010,6 +2319,25 @@ int qcow2_update_header(BlockDriverState *bs)
buflen -= ret;
}
+ /* Bitmap extension */
+ if (s->nb_bitmaps > 0) {
+ Qcow2BitmapHeaderExt bitmaps_header = {
+ .nb_bitmaps = cpu_to_be32(s->nb_bitmaps),
+ .bitmap_directory_size =
+ cpu_to_be64(s->bitmap_directory_size),
+ .bitmap_directory_offset =
+ cpu_to_be64(s->bitmap_directory_offset)
+ };
+ ret = header_ext_add(buf, QCOW2_EXT_MAGIC_BITMAPS,
+ &bitmaps_header, sizeof(bitmaps_header),
+ buflen);
+ if (ret < 0) {
+ goto fail;
+ }
+ buf += ret;
+ buflen -= ret;
+ }
+
/* Keep unknown header extensions */
QLIST_FOREACH(uext, &s->unknown_header_ext, next) {
ret = header_ext_add(buf, uext->magic, uext->data, uext->len, buflen);
@@ -2079,24 +2407,105 @@ static int qcow2_change_backing_file(BlockDriverState *bs,
return qcow2_update_header(bs);
}
-static int preallocate(BlockDriverState *bs)
+static int qcow2_crypt_method_from_format(const char *encryptfmt)
{
+ if (g_str_equal(encryptfmt, "luks")) {
+ return QCOW_CRYPT_LUKS;
+ } else if (g_str_equal(encryptfmt, "aes")) {
+ return QCOW_CRYPT_AES;
+ } else {
+ return -EINVAL;
+ }
+}
+
+static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
+ QemuOpts *opts, Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ QCryptoBlockCreateOptions *cryptoopts = NULL;
+ QCryptoBlock *crypto = NULL;
+ int ret = -EINVAL;
+ QDict *options, *encryptopts;
+ int fmt;
+
+ options = qemu_opts_to_qdict(opts, NULL);
+ qdict_extract_subqdict(options, &encryptopts, "encrypt.");
+ QDECREF(options);
+
+ fmt = qcow2_crypt_method_from_format(encryptfmt);
+
+ switch (fmt) {
+ case QCOW_CRYPT_LUKS:
+ cryptoopts = block_crypto_create_opts_init(
+ Q_CRYPTO_BLOCK_FORMAT_LUKS, encryptopts, errp);
+ break;
+ case QCOW_CRYPT_AES:
+ cryptoopts = block_crypto_create_opts_init(
+ Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
+ break;
+ default:
+ error_setg(errp, "Unknown encryption format '%s'", encryptfmt);
+ break;
+ }
+ if (!cryptoopts) {
+ ret = -EINVAL;
+ goto out;
+ }
+ s->crypt_method_header = fmt;
+
+ crypto = qcrypto_block_create(cryptoopts, "encrypt.",
+ qcow2_crypto_hdr_init_func,
+ qcow2_crypto_hdr_write_func,
+ bs, errp);
+ if (!crypto) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = qcow2_update_header(bs);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not write encryption header");
+ goto out;
+ }
+
+ out:
+ QDECREF(encryptopts);
+ qcrypto_block_free(crypto);
+ qapi_free_QCryptoBlockCreateOptions(cryptoopts);
+ return ret;
+}
+
+
+/**
+ * Preallocates metadata structures for data clusters between @offset (in the
+ * guest disk) and @new_length (which is thus generally the new guest disk
+ * size).
+ *
+ * Returns: 0 on success, -errno on failure.
+ */
+static int preallocate(BlockDriverState *bs,
+ uint64_t offset, uint64_t new_length)
+{
+ BDRVQcow2State *s = bs->opaque;
uint64_t bytes;
- uint64_t offset;
uint64_t host_offset = 0;
unsigned int cur_bytes;
int ret;
QCowL2Meta *meta;
- bytes = bdrv_getlength(bs);
- offset = 0;
+ if (qemu_in_coroutine()) {
+ qemu_co_mutex_lock(&s->lock);
+ }
+
+ assert(offset <= new_length);
+ bytes = new_length - offset;
while (bytes) {
cur_bytes = MIN(bytes, INT_MAX);
ret = qcow2_alloc_cluster_offset(bs, offset, &cur_bytes,
&host_offset, &meta);
if (ret < 0) {
- return ret;
+ goto done;
}
while (meta) {
@@ -2106,7 +2515,7 @@ static int preallocate(BlockDriverState *bs)
if (ret < 0) {
qcow2_free_any_clusters(bs, meta->alloc_offset,
meta->nb_clusters, QCOW2_DISCARD_NEVER);
- return ret;
+ goto done;
}
/* There are no dependent requests, but we need to remove our
@@ -2133,32 +2542,174 @@ static int preallocate(BlockDriverState *bs)
ret = bdrv_pwrite(bs->file, (host_offset + cur_bytes) - 1,
&data, 1);
if (ret < 0) {
- return ret;
+ goto done;
}
}
- return 0;
+ ret = 0;
+
+done:
+ if (qemu_in_coroutine()) {
+ qemu_co_mutex_unlock(&s->lock);
+ }
+ return ret;
}
-static int qcow2_create2(const char *filename, int64_t total_size,
- const char *backing_file, const char *backing_format,
- int flags, size_t cluster_size, PreallocMode prealloc,
- QemuOpts *opts, int version, int refcount_order,
- Error **errp)
+/* qcow2_refcount_metadata_size:
+ * @clusters: number of clusters to refcount (including data and L1/L2 tables)
+ * @cluster_size: size of a cluster, in bytes
+ * @refcount_order: refcount bits power-of-2 exponent
+ * @generous_increase: allow for the refcount table to be 1.5x as large as it
+ * needs to be
+ *
+ * Returns: Number of bytes required for refcount blocks and table metadata.
+ */
+int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
+ int refcount_order, bool generous_increase,
+ uint64_t *refblock_count)
+{
+ /*
+ * Every host cluster is reference-counted, including metadata (even
+ * refcount metadata is recursively included).
+ *
+ * An accurate formula for the size of refcount metadata size is difficult
+ * to derive. An easier method of calculation is finding the fixed point
+ * where no further refcount blocks or table clusters are required to
+ * reference count every cluster.
+ */
+ int64_t blocks_per_table_cluster = cluster_size / sizeof(uint64_t);
+ int64_t refcounts_per_block = cluster_size * 8 / (1 << refcount_order);
+ int64_t table = 0; /* number of refcount table clusters */
+ int64_t blocks = 0; /* number of refcount block clusters */
+ int64_t last;
+ int64_t n = 0;
+
+ do {
+ last = n;
+ blocks = DIV_ROUND_UP(clusters + table + blocks, refcounts_per_block);
+ table = DIV_ROUND_UP(blocks, blocks_per_table_cluster);
+ n = clusters + blocks + table;
+
+ if (n == last && generous_increase) {
+ clusters += DIV_ROUND_UP(table, 2);
+ n = 0; /* force another loop */
+ generous_increase = false;
+ }
+ } while (n != last);
+
+ if (refblock_count) {
+ *refblock_count = blocks;
+ }
+
+ return (blocks + table) * cluster_size;
+}
+
+/**
+ * qcow2_calc_prealloc_size:
+ * @total_size: virtual disk size in bytes
+ * @cluster_size: cluster size in bytes
+ * @refcount_order: refcount bits power-of-2 exponent
+ *
+ * Returns: Total number of bytes required for the fully allocated image
+ * (including metadata).
+ */
+static int64_t qcow2_calc_prealloc_size(int64_t total_size,
+ size_t cluster_size,
+ int refcount_order)
+{
+ int64_t meta_size = 0;
+ uint64_t nl1e, nl2e;
+ int64_t aligned_total_size = align_offset(total_size, cluster_size);
+
+ /* header: 1 cluster */
+ meta_size += cluster_size;
+
+ /* total size of L2 tables */
+ nl2e = aligned_total_size / cluster_size;
+ nl2e = align_offset(nl2e, cluster_size / sizeof(uint64_t));
+ meta_size += nl2e * sizeof(uint64_t);
+
+ /* total size of L1 tables */
+ nl1e = nl2e * sizeof(uint64_t) / cluster_size;
+ nl1e = align_offset(nl1e, cluster_size / sizeof(uint64_t));
+ meta_size += nl1e * sizeof(uint64_t);
+
+ /* total size of refcount table and blocks */
+ meta_size += qcow2_refcount_metadata_size(
+ (meta_size + aligned_total_size) / cluster_size,
+ cluster_size, refcount_order, false, NULL);
+
+ return meta_size + aligned_total_size;
+}
+
+static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, Error **errp)
{
+ size_t cluster_size;
int cluster_bits;
- QDict *options;
- /* Calculate cluster_bits */
+ cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
+ DEFAULT_CLUSTER_SIZE);
cluster_bits = ctz32(cluster_size);
if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS ||
(1 << cluster_bits) != cluster_size)
{
error_setg(errp, "Cluster size must be a power of two between %d and "
"%dk", 1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10));
- return -EINVAL;
+ return 0;
+ }
+ return cluster_size;
+}
+
+static int qcow2_opt_get_version_del(QemuOpts *opts, Error **errp)
+{
+ char *buf;
+ int ret;
+
+ buf = qemu_opt_get_del(opts, BLOCK_OPT_COMPAT_LEVEL);
+ if (!buf) {
+ ret = 3; /* default */
+ } else if (!strcmp(buf, "0.10")) {
+ ret = 2;
+ } else if (!strcmp(buf, "1.1")) {
+ ret = 3;
+ } else {
+ error_setg(errp, "Invalid compatibility level: '%s'", buf);
+ ret = -EINVAL;
+ }
+ g_free(buf);
+ return ret;
+}
+
+static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
+ Error **errp)
+{
+ uint64_t refcount_bits;
+
+ refcount_bits = qemu_opt_get_number_del(opts, BLOCK_OPT_REFCOUNT_BITS, 16);
+ if (refcount_bits > 64 || !is_power_of_2(refcount_bits)) {
+ error_setg(errp, "Refcount width must be a power of two and may not "
+ "exceed 64 bits");
+ return 0;
}
+ if (version < 3 && refcount_bits != 16) {
+ error_setg(errp, "Different refcount widths than 16 bits require "
+ "compatibility level 1.1 or above (use compat=1.1 or "
+ "greater)");
+ return 0;
+ }
+
+ return refcount_bits;
+}
+
+static int qcow2_create2(const char *filename, int64_t total_size,
+ const char *backing_file, const char *backing_format,
+ int flags, size_t cluster_size, PreallocMode prealloc,
+ QemuOpts *opts, int version, int refcount_order,
+ const char *encryptfmt, Error **errp)
+{
+ QDict *options;
+
/*
* Open the image file and write a minimal qcow2 header.
*
@@ -2178,65 +2729,9 @@ static int qcow2_create2(const char *filename, int64_t total_size,
int ret;
if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
- /* Note: The following calculation does not need to be exact; if it is a
- * bit off, either some bytes will be "leaked" (which is fine) or we
- * will need to increase the file size by some bytes (which is fine,
- * too, as long as the bulk is allocated here). Therefore, using
- * floating point arithmetic is fine. */
- int64_t meta_size = 0;
- uint64_t nreftablee, nrefblocke, nl1e, nl2e, refblock_count;
- int64_t aligned_total_size = align_offset(total_size, cluster_size);
- int refblock_bits, refblock_size;
- /* refcount entry size in bytes */
- double rces = (1 << refcount_order) / 8.;
-
- /* see qcow2_open() */
- refblock_bits = cluster_bits - (refcount_order - 3);
- refblock_size = 1 << refblock_bits;
-
- /* header: 1 cluster */
- meta_size += cluster_size;
-
- /* total size of L2 tables */
- nl2e = aligned_total_size / cluster_size;
- nl2e = align_offset(nl2e, cluster_size / sizeof(uint64_t));
- meta_size += nl2e * sizeof(uint64_t);
-
- /* total size of L1 tables */
- nl1e = nl2e * sizeof(uint64_t) / cluster_size;
- nl1e = align_offset(nl1e, cluster_size / sizeof(uint64_t));
- meta_size += nl1e * sizeof(uint64_t);
-
- /* total size of refcount blocks
- *
- * note: every host cluster is reference-counted, including metadata
- * (even refcount blocks are recursively included).
- * Let:
- * a = total_size (this is the guest disk size)
- * m = meta size not including refcount blocks and refcount tables
- * c = cluster size
- * y1 = number of refcount blocks entries
- * y2 = meta size including everything
- * rces = refcount entry size in bytes
- * then,
- * y1 = (y2 + a)/c
- * y2 = y1 * rces + y1 * rces * sizeof(u64) / c + m
- * we can get y1:
- * y1 = (a + m) / (c - rces - rces * sizeof(u64) / c)
- */
- nrefblocke = (aligned_total_size + meta_size + cluster_size)
- / (cluster_size - rces - rces * sizeof(uint64_t)
- / cluster_size);
- refblock_count = DIV_ROUND_UP(nrefblocke, refblock_size);
- meta_size += refblock_count * cluster_size;
-
- /* total size of refcount tables */
- nreftablee = align_offset(refblock_count,
- cluster_size / sizeof(uint64_t));
- meta_size += nreftablee * sizeof(uint64_t);
-
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
- aligned_total_size + meta_size, &error_abort);
+ int64_t prealloc_size =
+ qcow2_calc_prealloc_size(total_size, cluster_size, refcount_order);
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort);
qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_lookup[prealloc],
&error_abort);
}
@@ -2263,7 +2758,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
*header = (QCowHeader) {
.magic = cpu_to_be32(QCOW_MAGIC),
.version = cpu_to_be32(version),
- .cluster_bits = cpu_to_be32(cluster_bits),
+ .cluster_bits = cpu_to_be32(ctz32(cluster_size)),
.size = cpu_to_be64(0),
.l1_table_offset = cpu_to_be64(0),
.l1_size = cpu_to_be32(0),
@@ -2273,11 +2768,8 @@ static int qcow2_create2(const char *filename, int64_t total_size,
.header_length = cpu_to_be32(sizeof(*header)),
};
- if (flags & BLOCK_FLAG_ENCRYPT) {
- header->crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
- } else {
- header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
- }
+ /* We'll update this to correct value later */
+ header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
if (flags & BLOCK_FLAG_LAZY_REFCOUNTS) {
header->compatible_features |=
@@ -2340,7 +2832,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
}
/* Okay, now that we have a valid image, let's give it the right size */
- ret = blk_truncate(blk, total_size, errp);
+ ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
error_prepend(errp, "Could not resize image: ");
goto out;
@@ -2356,12 +2848,17 @@ static int qcow2_create2(const char *filename, int64_t total_size,
}
}
+ /* Want encryption? There you go. */
+ if (encryptfmt) {
+ ret = qcow2_set_up_encryption(blk_bs(blk), encryptfmt, opts, errp);
+ if (ret < 0) {
+ goto out;
+ }
+ }
+
/* And if we're supposed to preallocate metadata, do that now */
if (prealloc != PREALLOC_MODE_OFF) {
- BDRVQcow2State *s = blk_bs(blk)->opaque;
- qemu_co_mutex_lock(&s->lock);
- ret = preallocate(blk_bs(blk));
- qemu_co_mutex_unlock(&s->lock);
+ ret = preallocate(blk_bs(blk), 0, total_size);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not preallocate metadata");
goto out;
@@ -2371,11 +2868,17 @@ static int qcow2_create2(const char *filename, int64_t total_size,
blk_unref(blk);
blk = NULL;
- /* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */
+ /* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning.
+ * Using BDRV_O_NO_IO, since encryption is now setup we don't want to
+ * have to setup decryption context. We're not doing any I/O on the top
+ * level BlockDriverState, only lower layers, where BDRV_O_NO_IO does
+ * not have effect.
+ */
options = qdict_new();
qdict_put_str(options, "driver", "qcow2");
blk = blk_new_open(filename, NULL, options,
- BDRV_O_RDWR | BDRV_O_NO_BACKING, &local_err);
+ BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO,
+ &local_err);
if (blk == NULL) {
error_propagate(errp, local_err);
ret = -EIO;
@@ -2399,9 +2902,10 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
int flags = 0;
size_t cluster_size = DEFAULT_CLUSTER_SIZE;
PreallocMode prealloc;
- int version = 3;
- uint64_t refcount_bits = 16;
+ int version;
+ uint64_t refcount_bits;
int refcount_order;
+ const char *encryptfmt = NULL;
Error *local_err = NULL;
int ret;
@@ -2410,11 +2914,23 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
BDRV_SECTOR_SIZE);
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
- if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
- flags |= BLOCK_FLAG_ENCRYPT;
+ encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
+ if (encryptfmt) {
+ if (qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT)) {
+ error_setg(errp, "Options " BLOCK_OPT_ENCRYPT " and "
+ BLOCK_OPT_ENCRYPT_FORMAT " are mutually exclusive");
+ ret = -EINVAL;
+ goto finish;
+ }
+ } else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
+ encryptfmt = "aes";
+ }
+ cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto finish;
}
- cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
- DEFAULT_CLUSTER_SIZE);
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
prealloc = qapi_enum_parse(PreallocMode_lookup, buf,
PREALLOC_MODE__MAX, PREALLOC_MODE_OFF,
@@ -2424,16 +2940,10 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
ret = -EINVAL;
goto finish;
}
- g_free(buf);
- buf = qemu_opt_get_del(opts, BLOCK_OPT_COMPAT_LEVEL);
- if (!buf) {
- /* keep the default */
- } else if (!strcmp(buf, "0.10")) {
- version = 2;
- } else if (!strcmp(buf, "1.1")) {
- version = 3;
- } else {
- error_setg(errp, "Invalid compatibility level: '%s'", buf);
+
+ version = qcow2_opt_get_version_del(opts, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
ret = -EINVAL;
goto finish;
}
@@ -2456,19 +2966,9 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
goto finish;
}
- refcount_bits = qemu_opt_get_number_del(opts, BLOCK_OPT_REFCOUNT_BITS,
- refcount_bits);
- if (refcount_bits > 64 || !is_power_of_2(refcount_bits)) {
- error_setg(errp, "Refcount width must be a power of two and may not "
- "exceed 64 bits");
- ret = -EINVAL;
- goto finish;
- }
-
- if (version < 3 && refcount_bits != 16) {
- error_setg(errp, "Different refcount widths than 16 bits require "
- "compatibility level 1.1 or above (use compat=1.1 or "
- "greater)");
+ refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
ret = -EINVAL;
goto finish;
}
@@ -2477,7 +2977,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
ret = qcow2_create2(filename, size, backing_file, backing_fmt, flags,
cluster_size, prealloc, opts, version, refcount_order,
- &local_err);
+ encryptfmt, &local_err);
error_propagate(errp, local_err);
finish:
@@ -2585,12 +3085,22 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
return ret;
}
-static int qcow2_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
+static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
+ PreallocMode prealloc, Error **errp)
{
BDRVQcow2State *s = bs->opaque;
+ uint64_t old_length;
int64_t new_l1_size;
int ret;
+ if (prealloc != PREALLOC_MODE_OFF && prealloc != PREALLOC_MODE_METADATA &&
+ prealloc != PREALLOC_MODE_FALLOC && prealloc != PREALLOC_MODE_FULL)
+ {
+ error_setg(errp, "Unsupported preallocation mode '%s'",
+ PreallocMode_lookup[prealloc]);
+ return -ENOTSUP;
+ }
+
if (offset & 511) {
error_setg(errp, "The new size must be a multiple of 512");
return -EINVAL;
@@ -2602,8 +3112,17 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
return -ENOTSUP;
}
+ /* cannot proceed if image has bitmaps */
+ if (s->nb_bitmaps) {
+ /* TODO: resize bitmaps in the image */
+ error_setg(errp, "Can't resize an image which has bitmaps");
+ return -ENOTSUP;
+ }
+
+ old_length = bs->total_sectors * 512;
+
/* shrinking is currently not supported */
- if (offset < bs->total_sectors * 512) {
+ if (offset < old_length) {
error_setg(errp, "qcow2 doesn't support shrinking images yet");
return -ENOTSUP;
}
@@ -2615,6 +3134,128 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
return ret;
}
+ switch (prealloc) {
+ case PREALLOC_MODE_OFF:
+ break;
+
+ case PREALLOC_MODE_METADATA:
+ ret = preallocate(bs, old_length, offset);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Preallocation failed");
+ return ret;
+ }
+ break;
+
+ case PREALLOC_MODE_FALLOC:
+ case PREALLOC_MODE_FULL:
+ {
+ int64_t allocation_start, host_offset, guest_offset;
+ int64_t clusters_allocated;
+ int64_t old_file_size, new_file_size;
+ uint64_t nb_new_data_clusters, nb_new_l2_tables;
+
+ old_file_size = bdrv_getlength(bs->file->bs);
+ if (old_file_size < 0) {
+ error_setg_errno(errp, -old_file_size,
+ "Failed to inquire current file length");
+ return ret;
+ }
+
+ nb_new_data_clusters = DIV_ROUND_UP(offset - old_length,
+ s->cluster_size);
+
+ /* This is an overestimation; we will not actually allocate space for
+ * these in the file but just make sure the new refcount structures are
+ * able to cover them so we will not have to allocate new refblocks
+ * while entering the data blocks in the potentially new L2 tables.
+ * (We do not actually care where the L2 tables are placed. Maybe they
+ * are already allocated or they can be placed somewhere before
+ * @old_file_size. It does not matter because they will be fully
+ * allocated automatically, so they do not need to be covered by the
+ * preallocation. All that matters is that we will not have to allocate
+ * new refcount structures for them.) */
+ nb_new_l2_tables = DIV_ROUND_UP(nb_new_data_clusters,
+ s->cluster_size / sizeof(uint64_t));
+ /* The cluster range may not be aligned to L2 boundaries, so add one L2
+ * table for a potential head/tail */
+ nb_new_l2_tables++;
+
+ allocation_start = qcow2_refcount_area(bs, old_file_size,
+ nb_new_data_clusters +
+ nb_new_l2_tables,
+ true, 0, 0);
+ if (allocation_start < 0) {
+ error_setg_errno(errp, -allocation_start,
+ "Failed to resize refcount structures");
+ return -allocation_start;
+ }
+
+ clusters_allocated = qcow2_alloc_clusters_at(bs, allocation_start,
+ nb_new_data_clusters);
+ if (clusters_allocated < 0) {
+ error_setg_errno(errp, -clusters_allocated,
+ "Failed to allocate data clusters");
+ return -clusters_allocated;
+ }
+
+ assert(clusters_allocated == nb_new_data_clusters);
+
+ /* Allocate the data area */
+ new_file_size = allocation_start +
+ nb_new_data_clusters * s->cluster_size;
+ ret = bdrv_truncate(bs->file, new_file_size, prealloc, errp);
+ if (ret < 0) {
+ error_prepend(errp, "Failed to resize underlying file: ");
+ qcow2_free_clusters(bs, allocation_start,
+ nb_new_data_clusters * s->cluster_size,
+ QCOW2_DISCARD_OTHER);
+ return ret;
+ }
+
+ /* Create the necessary L2 entries */
+ host_offset = allocation_start;
+ guest_offset = old_length;
+ while (nb_new_data_clusters) {
+ int64_t guest_cluster = guest_offset >> s->cluster_bits;
+ int64_t nb_clusters = MIN(nb_new_data_clusters,
+ s->l2_size - guest_cluster % s->l2_size);
+ QCowL2Meta allocation = {
+ .offset = guest_offset,
+ .alloc_offset = host_offset,
+ .nb_clusters = nb_clusters,
+ };
+ qemu_co_queue_init(&allocation.dependent_requests);
+
+ ret = qcow2_alloc_cluster_link_l2(bs, &allocation);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to update L2 tables");
+ qcow2_free_clusters(bs, host_offset,
+ nb_new_data_clusters * s->cluster_size,
+ QCOW2_DISCARD_OTHER);
+ return ret;
+ }
+
+ guest_offset += nb_clusters * s->cluster_size;
+ host_offset += nb_clusters * s->cluster_size;
+ nb_new_data_clusters -= nb_clusters;
+ }
+ break;
+ }
+
+ default:
+ g_assert_not_reached();
+ }
+
+ if (prealloc != PREALLOC_MODE_OFF) {
+ /* Flush metadata before actually changing the image size */
+ ret = bdrv_flush(bs);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "Failed to flush the preallocated area to disk");
+ return ret;
+ }
+ }
+
/* write updated header.size */
offset = cpu_to_be64(offset);
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size),
@@ -2646,7 +3287,7 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
/* align end of file to a sector boundary to ease reading with
sector based I/Os */
cluster_offset = bdrv_getlength(bs->file->bs);
- return bdrv_truncate(bs->file, cluster_offset, NULL);
+ return bdrv_truncate(bs->file, cluster_offset, PREALLOC_MODE_OFF, NULL);
}
buf = qemu_blockalign(bs, s->cluster_size);
@@ -2862,7 +3503,7 @@ static int make_completely_empty(BlockDriverState *bs)
}
ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size,
- &local_err);
+ PREALLOC_MODE_OFF, &local_err);
if (ret < 0) {
error_report_err(local_err);
goto fail;
@@ -2946,6 +3587,142 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
return 0;
}
+static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
+ Error **errp)
+{
+ Error *local_err = NULL;
+ BlockMeasureInfo *info;
+ uint64_t required = 0; /* bytes that contribute to required size */
+ uint64_t virtual_size; /* disk size as seen by guest */
+ uint64_t refcount_bits;
+ uint64_t l2_tables;
+ size_t cluster_size;
+ int version;
+ char *optstr;
+ PreallocMode prealloc;
+ bool has_backing_file;
+
+ /* Parse image creation options */
+ cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
+ if (local_err) {
+ goto err;
+ }
+
+ version = qcow2_opt_get_version_del(opts, &local_err);
+ if (local_err) {
+ goto err;
+ }
+
+ refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, &local_err);
+ if (local_err) {
+ goto err;
+ }
+
+ optstr = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
+ prealloc = qapi_enum_parse(PreallocMode_lookup, optstr,
+ PREALLOC_MODE__MAX, PREALLOC_MODE_OFF,
+ &local_err);
+ g_free(optstr);
+ if (local_err) {
+ goto err;
+ }
+
+ optstr = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
+ has_backing_file = !!optstr;
+ g_free(optstr);
+
+ virtual_size = align_offset(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
+ cluster_size);
+
+ /* Check that virtual disk size is valid */
+ l2_tables = DIV_ROUND_UP(virtual_size / cluster_size,
+ cluster_size / sizeof(uint64_t));
+ if (l2_tables * sizeof(uint64_t) > QCOW_MAX_L1_SIZE) {
+ error_setg(&local_err, "The image size is too large "
+ "(try using a larger cluster size)");
+ goto err;
+ }
+
+ /* Account for input image */
+ if (in_bs) {
+ int64_t ssize = bdrv_getlength(in_bs);
+ if (ssize < 0) {
+ error_setg_errno(&local_err, -ssize,
+ "Unable to get image virtual_size");
+ goto err;
+ }
+
+ virtual_size = align_offset(ssize, cluster_size);
+
+ if (has_backing_file) {
+ /* We don't how much of the backing chain is shared by the input
+ * image and the new image file. In the worst case the new image's
+ * backing file has nothing in common with the input image. Be
+ * conservative and assume all clusters need to be written.
+ */
+ required = virtual_size;
+ } else {
+ int cluster_sectors = cluster_size / BDRV_SECTOR_SIZE;
+ int64_t sector_num;
+ int pnum = 0;
+
+ for (sector_num = 0;
+ sector_num < ssize / BDRV_SECTOR_SIZE;
+ sector_num += pnum) {
+ int nb_sectors = MAX(ssize / BDRV_SECTOR_SIZE - sector_num,
+ INT_MAX);
+ BlockDriverState *file;
+ int64_t ret;
+
+ ret = bdrv_get_block_status_above(in_bs, NULL,
+ sector_num, nb_sectors,
+ &pnum, &file);
+ if (ret < 0) {
+ error_setg_errno(&local_err, -ret,
+ "Unable to get block status");
+ goto err;
+ }
+
+ if (ret & BDRV_BLOCK_ZERO) {
+ /* Skip zero regions (safe with no backing file) */
+ } else if ((ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) ==
+ (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) {
+ /* Extend pnum to end of cluster for next iteration */
+ pnum = ROUND_UP(sector_num + pnum, cluster_sectors) -
+ sector_num;
+
+ /* Count clusters we've seen */
+ required += (sector_num % cluster_sectors + pnum) *
+ BDRV_SECTOR_SIZE;
+ }
+ }
+ }
+ }
+
+ /* Take into account preallocation. Nothing special is needed for
+ * PREALLOC_MODE_METADATA since metadata is always counted.
+ */
+ if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
+ required = virtual_size;
+ }
+
+ info = g_new(BlockMeasureInfo, 1);
+ info->fully_allocated =
+ qcow2_calc_prealloc_size(virtual_size, cluster_size,
+ ctz32(refcount_bits));
+
+ /* Remove data clusters that are not required. This overestimates the
+ * required size because metadata needed for the fully allocated file is
+ * still counted.
+ */
+ info->required = info->fully_allocated - virtual_size + required;
+ return info;
+
+err:
+ error_propagate(errp, local_err);
+ return NULL;
+}
+
static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
BDRVQcow2State *s = bs->opaque;
@@ -2959,8 +3736,14 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
{
BDRVQcow2State *s = bs->opaque;
- ImageInfoSpecific *spec_info = g_new(ImageInfoSpecific, 1);
+ ImageInfoSpecific *spec_info;
+ QCryptoBlockInfo *encrypt_info = NULL;
+ if (s->crypto != NULL) {
+ encrypt_info = qcrypto_block_get_info(s->crypto, &error_abort);
+ }
+
+ spec_info = g_new(ImageInfoSpecific, 1);
*spec_info = (ImageInfoSpecific){
.type = IMAGE_INFO_SPECIFIC_KIND_QCOW2,
.u.qcow2.data = g_new(ImageInfoSpecificQCow2, 1),
@@ -2987,6 +3770,30 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
assert(false);
}
+ if (encrypt_info) {
+ ImageInfoSpecificQCow2Encryption *qencrypt =
+ g_new(ImageInfoSpecificQCow2Encryption, 1);
+ switch (encrypt_info->format) {
+ case Q_CRYPTO_BLOCK_FORMAT_QCOW:
+ qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_AES;
+ qencrypt->u.aes = encrypt_info->u.qcow;
+ break;
+ case Q_CRYPTO_BLOCK_FORMAT_LUKS:
+ qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_LUKS;
+ qencrypt->u.luks = encrypt_info->u.luks;
+ break;
+ default:
+ abort();
+ }
+ /* Since we did shallow copy above, erase any pointers
+ * in the original info */
+ memset(&encrypt_info->u, 0, sizeof(encrypt_info->u));
+ qapi_free_QCryptoBlockInfo(encrypt_info);
+
+ spec_info->u.qcow2.data->has_encrypt = true;
+ spec_info->u.qcow2.data->encrypt = qencrypt;
+ }
+
return spec_info;
}
@@ -3175,6 +3982,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
const char *compat = NULL;
uint64_t cluster_size = s->cluster_size;
bool encrypt;
+ int encformat;
int refcount_bits = s->refcount_bits;
Error *local_err = NULL;
int ret;
@@ -3211,12 +4019,20 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
backing_format = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
} else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT)) {
encrypt = qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT,
- !!s->cipher);
+ !!s->crypto);
- if (encrypt != !!s->cipher) {
+ if (encrypt != !!s->crypto) {
error_report("Changing the encryption flag is not supported");
return -ENOTSUP;
}
+ } else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT_FORMAT)) {
+ encformat = qcow2_crypt_method_from_format(
+ qemu_opt_get(opts, BLOCK_OPT_ENCRYPT_FORMAT));
+
+ if (encformat != s->crypt_method_header) {
+ error_report("Changing the encryption format is not supported");
+ return -ENOTSUP;
+ }
} else if (!strcmp(desc->name, BLOCK_OPT_CLUSTER_SIZE)) {
cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE,
cluster_size);
@@ -3333,7 +4149,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
return ret;
}
- ret = blk_truncate(blk, new_size, &local_err);
+ ret = blk_truncate(blk, new_size, PREALLOC_MODE_OFF, &local_err);
blk_unref(blk);
if (ret < 0) {
error_report_err(local_err);
@@ -3431,10 +4247,23 @@ static QemuOptsList qcow2_create_opts = {
{
.name = BLOCK_OPT_ENCRYPT,
.type = QEMU_OPT_BOOL,
- .help = "Encrypt the image",
- .def_value_str = "off"
+ .help = "Encrypt the image with format 'aes'. (Deprecated "
+ "in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)",
},
{
+ .name = BLOCK_OPT_ENCRYPT_FORMAT,
+ .type = QEMU_OPT_STRING,
+ .help = "Encrypt the image, format choices: 'aes', 'luks'",
+ },
+ BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.",
+ "ID of secret providing qcow AES key or LUKS passphrase"),
+ BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG("encrypt."),
+ BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE("encrypt."),
+ BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG("encrypt."),
+ BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG("encrypt."),
+ BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG("encrypt."),
+ BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."),
+ {
.name = BLOCK_OPT_CLUSTER_SIZE,
.type = QEMU_OPT_SIZE,
.help = "qcow2 cluster size",
@@ -3476,7 +4305,6 @@ BlockDriver bdrv_qcow2 = {
.bdrv_create = qcow2_create,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_co_get_block_status = qcow2_co_get_block_status,
- .bdrv_set_key = qcow2_set_key,
.bdrv_co_preadv = qcow2_co_preadv,
.bdrv_co_pwritev = qcow2_co_pwritev,
@@ -3493,6 +4321,7 @@ BlockDriver bdrv_qcow2 = {
.bdrv_snapshot_delete = qcow2_snapshot_delete,
.bdrv_snapshot_list = qcow2_snapshot_list,
.bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp,
+ .bdrv_measure = qcow2_measure,
.bdrv_get_info = qcow2_get_info,
.bdrv_get_specific_info = qcow2_get_specific_info,
@@ -3512,6 +4341,10 @@ BlockDriver bdrv_qcow2 = {
.bdrv_detach_aio_context = qcow2_detach_aio_context,
.bdrv_attach_aio_context = qcow2_attach_aio_context,
+
+ .bdrv_reopen_bitmaps_rw = qcow2_reopen_bitmaps_rw,
+ .bdrv_can_store_new_dirty_bitmap = qcow2_can_store_new_dirty_bitmap,
+ .bdrv_remove_persistent_dirty_bitmap = qcow2_remove_persistent_dirty_bitmap,
};
static void bdrv_qcow2_init(void)
diff --git a/block/qcow2.h b/block/qcow2.h
index 87b15eb4aa..96a8d43c17 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -25,7 +25,7 @@
#ifndef BLOCK_QCOW2_H
#define BLOCK_QCOW2_H
-#include "crypto/cipher.h"
+#include "crypto/block.h"
#include "qemu/coroutine.h"
//#define DEBUG_ALLOC
@@ -36,6 +36,7 @@
#define QCOW_CRYPT_NONE 0
#define QCOW_CRYPT_AES 1
+#define QCOW_CRYPT_LUKS 2
#define QCOW_MAX_CRYPT_CLUSTERS 32
#define QCOW_MAX_SNAPSHOTS 65536
@@ -52,6 +53,10 @@
* space for snapshot names and IDs */
#define QCOW_MAX_SNAPSHOTS_SIZE (1024 * QCOW_MAX_SNAPSHOTS)
+/* Bitmap header extension constraints */
+#define QCOW2_MAX_BITMAPS 65535
+#define QCOW2_MAX_BITMAP_DIRECTORY_SIZE (1024 * QCOW2_MAX_BITMAPS)
+
/* indicate that the refcount of the referenced cluster is exactly one. */
#define QCOW_OFLAG_COPIED (1ULL << 63)
/* indicate that the cluster is compressed (they never have the copied flag) */
@@ -163,6 +168,11 @@ typedef struct QCowSnapshot {
struct Qcow2Cache;
typedef struct Qcow2Cache Qcow2Cache;
+typedef struct Qcow2CryptoHeaderExtension {
+ uint64_t offset;
+ uint64_t length;
+} QEMU_PACKED Qcow2CryptoHeaderExtension;
+
typedef struct Qcow2UnknownHeaderExtension {
uint32_t magic;
uint32_t len;
@@ -195,6 +205,14 @@ enum {
QCOW2_COMPAT_FEAT_MASK = QCOW2_COMPAT_LAZY_REFCOUNTS,
};
+/* Autoclear feature bits */
+enum {
+ QCOW2_AUTOCLEAR_BITMAPS_BITNR = 0,
+ QCOW2_AUTOCLEAR_BITMAPS = 1 << QCOW2_AUTOCLEAR_BITMAPS_BITNR,
+
+ QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS,
+};
+
enum qcow2_discard_type {
QCOW2_DISCARD_NEVER = 0,
QCOW2_DISCARD_ALWAYS,
@@ -222,6 +240,13 @@ typedef uint64_t Qcow2GetRefcountFunc(const void *refcount_array,
typedef void Qcow2SetRefcountFunc(void *refcount_array,
uint64_t index, uint64_t value);
+typedef struct Qcow2BitmapHeaderExt {
+ uint32_t nb_bitmaps;
+ uint32_t reserved32;
+ uint64_t bitmap_directory_size;
+ uint64_t bitmap_directory_offset;
+} QEMU_PACKED Qcow2BitmapHeaderExt;
+
typedef struct BDRVQcow2State {
int cluster_bits;
int cluster_size;
@@ -257,13 +282,21 @@ typedef struct BDRVQcow2State {
CoMutex lock;
- QCryptoCipher *cipher; /* current cipher, NULL if no key yet */
+ Qcow2CryptoHeaderExtension crypto_header; /* QCow2 header extension */
+ QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */
+ QCryptoBlock *crypto; /* Disk encryption format driver */
+ bool crypt_physical_offset; /* Whether to use virtual or physical offset
+ for encryption initialization vector tweak */
uint32_t crypt_method_header;
uint64_t snapshots_offset;
int snapshots_size;
unsigned int nb_snapshots;
QCowSnapshot *snapshots;
+ uint32_t nb_bitmaps;
+ uint64_t bitmap_directory_size;
+ uint64_t bitmap_directory_offset;
+
int flags;
int qcow_version;
bool use_lazy_refcounts;
@@ -492,6 +525,10 @@ static inline uint64_t refcount_diff(uint64_t r1, uint64_t r2)
int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
int64_t sector_num, int nb_sectors);
+int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
+ int refcount_order, bool generous_increase,
+ uint64_t *refblock_count);
+
int qcow2_mark_dirty(BlockDriverState *bs);
int qcow2_mark_corrupt(BlockDriverState *bs);
int qcow2_mark_consistent(BlockDriverState *bs);
@@ -512,6 +549,11 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
uint64_t addend, bool decrease,
enum qcow2_discard_type type);
+int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t offset,
+ uint64_t additional_clusters, bool exact_size,
+ int new_refblock_index,
+ uint64_t new_refblock_offset);
+
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
int64_t nb_clusters);
@@ -534,6 +576,10 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
int64_t size);
int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
int64_t size);
+int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table,
+ int64_t *refcount_table_size,
+ int64_t offset, int64_t size);
int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
BlockDriverAmendStatusCB *status_cb,
@@ -545,8 +591,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
- uint8_t *out_buf, const uint8_t *in_buf,
- int nb_sectors, bool enc, Error **errp);
+ uint8_t *buf, int nb_sectors, bool enc, Error **errp);
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, uint64_t *cluster_offset);
@@ -605,4 +650,20 @@ int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
void **table);
void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
+/* qcow2-bitmap.c functions */
+int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table,
+ int64_t *refcount_table_size);
+bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
+int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
+void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
+int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
+bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs,
+ const char *name,
+ uint32_t granularity,
+ Error **errp);
+void qcow2_remove_persistent_dirty_bitmap(BlockDriverState *bs,
+ const char *name,
+ Error **errp);
+
#endif
diff --git a/block/qed-cluster.c b/block/qed-cluster.c
index d8d6e66a0f..672e2e654b 100644
--- a/block/qed-cluster.c
+++ b/block/qed-cluster.c
@@ -85,6 +85,8 @@ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
*
* On failure QED_CLUSTER_L2 or QED_CLUSTER_L1 is returned for missing L2 or L1
* table offset, respectively. len is number of contiguous unallocated bytes.
+ *
+ * Called with table_lock held.
*/
int coroutine_fn qed_find_cluster(BDRVQEDState *s, QEDRequest *request,
uint64_t pos, size_t *len,
@@ -112,7 +114,6 @@ int coroutine_fn qed_find_cluster(BDRVQEDState *s, QEDRequest *request,
}
ret = qed_read_l2_table(s, request, l2_offset);
- qed_acquire(s);
if (ret) {
goto out;
}
@@ -137,6 +138,5 @@ int coroutine_fn qed_find_cluster(BDRVQEDState *s, QEDRequest *request,
out:
*img_offset = offset;
- qed_release(s);
return ret;
}
diff --git a/block/qed-l2-cache.c b/block/qed-l2-cache.c
index 5cba794650..b548362398 100644
--- a/block/qed-l2-cache.c
+++ b/block/qed-l2-cache.c
@@ -101,6 +101,8 @@ CachedL2Table *qed_alloc_l2_cache_entry(L2TableCache *l2_cache)
/**
* Decrease an entry's reference count and free if necessary when the reference
* count drops to zero.
+ *
+ * Called with table_lock held.
*/
void qed_unref_l2_cache_entry(CachedL2Table *entry)
{
@@ -122,6 +124,8 @@ void qed_unref_l2_cache_entry(CachedL2Table *entry)
*
* For a cached entry, this function increases the reference count and returns
* the entry.
+ *
+ * Called with table_lock held.
*/
CachedL2Table *qed_find_l2_cache_entry(L2TableCache *l2_cache, uint64_t offset)
{
@@ -150,6 +154,8 @@ CachedL2Table *qed_find_l2_cache_entry(L2TableCache *l2_cache, uint64_t offset)
* N.B. This function steals a reference to the l2_table from the caller so the
* caller must obtain a new reference by issuing a call to
* qed_find_l2_cache_entry().
+ *
+ * Called with table_lock held.
*/
void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table)
{
diff --git a/block/qed-table.c b/block/qed-table.c
index ebee2c50f0..eead8b0fc7 100644
--- a/block/qed-table.c
+++ b/block/qed-table.c
@@ -18,6 +18,7 @@
#include "qed.h"
#include "qemu/bswap.h"
+/* Called either from qed_check or with table_lock held. */
static int qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table)
{
QEMUIOVector qiov;
@@ -32,18 +33,22 @@ static int qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table)
trace_qed_read_table(s, offset, table);
+ if (qemu_in_coroutine()) {
+ qemu_co_mutex_unlock(&s->table_lock);
+ }
ret = bdrv_preadv(s->bs->file, offset, &qiov);
+ if (qemu_in_coroutine()) {
+ qemu_co_mutex_lock(&s->table_lock);
+ }
if (ret < 0) {
goto out;
}
/* Byteswap offsets */
- qed_acquire(s);
noffsets = qiov.size / sizeof(uint64_t);
for (i = 0; i < noffsets; i++) {
table->offsets[i] = le64_to_cpu(table->offsets[i]);
}
- qed_release(s);
ret = 0;
out:
@@ -61,6 +66,8 @@ out:
* @index: Index of first element
* @n: Number of elements
* @flush: Whether or not to sync to disk
+ *
+ * Called either from qed_check or with table_lock held.
*/
static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
unsigned int index, unsigned int n, bool flush)
@@ -97,16 +104,20 @@ static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
/* Adjust for offset into table */
offset += start * sizeof(uint64_t);
+ if (qemu_in_coroutine()) {
+ qemu_co_mutex_unlock(&s->table_lock);
+ }
ret = bdrv_pwritev(s->bs->file, offset, &qiov);
+ if (qemu_in_coroutine()) {
+ qemu_co_mutex_lock(&s->table_lock);
+ }
trace_qed_write_table_cb(s, table, flush, ret);
if (ret < 0) {
goto out;
}
if (flush) {
- qed_acquire(s);
ret = bdrv_flush(s->bs);
- qed_release(s);
if (ret < 0) {
goto out;
}
@@ -123,6 +134,7 @@ int qed_read_l1_table_sync(BDRVQEDState *s)
return qed_read_table(s, s->header.l1_table_offset, s->l1_table);
}
+/* Called either from qed_check or with table_lock held. */
int qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n)
{
BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
@@ -136,6 +148,7 @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
return qed_write_l1_table(s, index, n);
}
+/* Called either from qed_check or with table_lock held. */
int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
{
int ret;
@@ -154,7 +167,6 @@ int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
BLKDBG_EVENT(s->bs->file, BLKDBG_L2_LOAD);
ret = qed_read_table(s, offset, request->l2_table->table);
- qed_acquire(s);
if (ret) {
/* can't trust loaded L2 table anymore */
qed_unref_l2_cache_entry(request->l2_table);
@@ -170,7 +182,6 @@ int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset);
assert(request->l2_table != NULL);
}
- qed_release(s);
return ret;
}
@@ -180,6 +191,7 @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset
return qed_read_l2_table(s, request, offset);
}
+/* Called either from qed_check or with table_lock held. */
int qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
unsigned int index, unsigned int n, bool flush)
{
diff --git a/block/qed.c b/block/qed.c
index 385381a78a..dc54bf4a93 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -93,6 +93,8 @@ int qed_write_header_sync(BDRVQEDState *s)
*
* This function only updates known header fields in-place and does not affect
* extra data after the QED header.
+ *
+ * No new allocating reqs can start while this function runs.
*/
static int coroutine_fn qed_write_header(BDRVQEDState *s)
{
@@ -109,6 +111,8 @@ static int coroutine_fn qed_write_header(BDRVQEDState *s)
QEMUIOVector qiov;
int ret;
+ assert(s->allocating_acb || s->allocating_write_reqs_plugged);
+
buf = qemu_blockalign(s->bs, len);
iov = (struct iovec) {
.iov_base = buf,
@@ -219,6 +223,8 @@ static int qed_read_string(BdrvChild *file, uint64_t offset, size_t n,
* This function only produces the offset where the new clusters should be
* written. It updates BDRVQEDState but does not make any changes to the image
* file.
+ *
+ * Called with table_lock held.
*/
static uint64_t qed_alloc_clusters(BDRVQEDState *s, unsigned int n)
{
@@ -236,6 +242,8 @@ QEDTable *qed_alloc_table(BDRVQEDState *s)
/**
* Allocate a new zeroed L2 table
+ *
+ * Called with table_lock held.
*/
static CachedL2Table *qed_new_l2_table(BDRVQEDState *s)
{
@@ -249,19 +257,32 @@ static CachedL2Table *qed_new_l2_table(BDRVQEDState *s)
return l2_table;
}
-static void qed_plug_allocating_write_reqs(BDRVQEDState *s)
+static bool qed_plug_allocating_write_reqs(BDRVQEDState *s)
{
+ qemu_co_mutex_lock(&s->table_lock);
+
+ /* No reentrancy is allowed. */
assert(!s->allocating_write_reqs_plugged);
+ if (s->allocating_acb != NULL) {
+ /* Another allocating write came concurrently. This cannot happen
+ * from bdrv_qed_co_drain, but it can happen when the timer runs.
+ */
+ qemu_co_mutex_unlock(&s->table_lock);
+ return false;
+ }
s->allocating_write_reqs_plugged = true;
+ qemu_co_mutex_unlock(&s->table_lock);
+ return true;
}
static void qed_unplug_allocating_write_reqs(BDRVQEDState *s)
{
+ qemu_co_mutex_lock(&s->table_lock);
assert(s->allocating_write_reqs_plugged);
-
s->allocating_write_reqs_plugged = false;
- qemu_co_enter_next(&s->allocating_write_reqs);
+ qemu_co_queue_next(&s->allocating_write_reqs);
+ qemu_co_mutex_unlock(&s->table_lock);
}
static void coroutine_fn qed_need_check_timer_entry(void *opaque)
@@ -269,17 +290,14 @@ static void coroutine_fn qed_need_check_timer_entry(void *opaque)
BDRVQEDState *s = opaque;
int ret;
- /* The timer should only fire when allocating writes have drained */
- assert(!s->allocating_acb);
-
trace_qed_need_check_timer_cb(s);
- qed_acquire(s);
- qed_plug_allocating_write_reqs(s);
+ if (!qed_plug_allocating_write_reqs(s)) {
+ return;
+ }
/* Ensure writes are on disk before clearing flag */
ret = bdrv_co_flush(s->bs->file->bs);
- qed_release(s);
if (ret < 0) {
qed_unplug_allocating_write_reqs(s);
return;
@@ -301,16 +319,6 @@ static void qed_need_check_timer_cb(void *opaque)
qemu_coroutine_enter(co);
}
-void qed_acquire(BDRVQEDState *s)
-{
- aio_context_acquire(bdrv_get_aio_context(s->bs));
-}
-
-void qed_release(BDRVQEDState *s)
-{
- aio_context_release(bdrv_get_aio_context(s->bs));
-}
-
static void qed_start_need_check_timer(BDRVQEDState *s)
{
trace_qed_start_need_check_timer(s);
@@ -350,7 +358,7 @@ static void bdrv_qed_attach_aio_context(BlockDriverState *bs,
}
}
-static void bdrv_qed_drain(BlockDriverState *bs)
+static void coroutine_fn bdrv_qed_co_drain(BlockDriverState *bs)
{
BDRVQEDState *s = bs->opaque;
@@ -359,10 +367,20 @@ static void bdrv_qed_drain(BlockDriverState *bs)
*/
if (s->need_check_timer && timer_pending(s->need_check_timer)) {
qed_cancel_need_check_timer(s);
- qed_need_check_timer_cb(s);
+ qed_need_check_timer_entry(s);
}
}
+static void bdrv_qed_init_state(BlockDriverState *bs)
+{
+ BDRVQEDState *s = bs->opaque;
+
+ memset(s, 0, sizeof(BDRVQEDState));
+ s->bs = bs;
+ qemu_co_mutex_init(&s->table_lock);
+ qemu_co_queue_init(&s->allocating_write_reqs);
+}
+
static int bdrv_qed_do_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
@@ -371,9 +389,6 @@ static int bdrv_qed_do_open(BlockDriverState *bs, QDict *options, int flags,
int64_t file_size;
int ret;
- s->bs = bs;
- qemu_co_queue_init(&s->allocating_write_reqs);
-
ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header));
if (ret < 0) {
return ret;
@@ -507,6 +522,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
return -EINVAL;
}
+ bdrv_qed_init_state(bs);
return bdrv_qed_do_open(bs, options, flags, errp);
}
@@ -583,7 +599,7 @@ static int qed_create(const char *filename, uint32_t cluster_size,
blk_set_allow_write_beyond_eof(blk, true);
/* File must start empty and grow, check truncate is supported */
- ret = blk_truncate(blk, 0, errp);
+ ret = blk_truncate(blk, 0, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto out;
}
@@ -681,6 +697,7 @@ typedef struct {
BlockDriverState **file;
} QEDIsAllocatedCB;
+/* Called with table_lock held. */
static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t len)
{
QEDIsAllocatedCB *cb = opaque;
@@ -728,6 +745,7 @@ static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs,
uint64_t offset;
int ret;
+ qemu_co_mutex_lock(&s->table_lock);
ret = qed_find_cluster(s, &request, cb.pos, &len, &offset);
qed_is_allocated_cb(&cb, ret, offset, len);
@@ -735,6 +753,7 @@ static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs,
assert(cb.status != BDRV_BLOCK_OFFSET_MASK);
qed_unref_l2_cache_entry(request.l2_table);
+ qemu_co_mutex_unlock(&s->table_lock);
return cb.status;
}
@@ -865,6 +884,8 @@ out:
*
* The cluster offset may be an allocated byte offset in the image file, the
* zero cluster marker, or the unallocated cluster marker.
+ *
+ * Called with table_lock held.
*/
static void coroutine_fn qed_update_l2_table(BDRVQEDState *s, QEDTable *table,
int index, unsigned int n,
@@ -880,6 +901,7 @@ static void coroutine_fn qed_update_l2_table(BDRVQEDState *s, QEDTable *table,
}
}
+/* Called with table_lock held. */
static void coroutine_fn qed_aio_complete(QEDAIOCB *acb)
{
BDRVQEDState *s = acb_to_s(acb);
@@ -903,7 +925,7 @@ static void coroutine_fn qed_aio_complete(QEDAIOCB *acb)
if (acb == s->allocating_acb) {
s->allocating_acb = NULL;
if (!qemu_co_queue_empty(&s->allocating_write_reqs)) {
- qemu_co_enter_next(&s->allocating_write_reqs);
+ qemu_co_queue_next(&s->allocating_write_reqs);
} else if (s->header.features & QED_F_NEED_CHECK) {
qed_start_need_check_timer(s);
}
@@ -912,6 +934,8 @@ static void coroutine_fn qed_aio_complete(QEDAIOCB *acb)
/**
* Update L1 table with new L2 table offset and write it out
+ *
+ * Called with table_lock held.
*/
static int coroutine_fn qed_aio_write_l1_update(QEDAIOCB *acb)
{
@@ -940,6 +964,8 @@ static int coroutine_fn qed_aio_write_l1_update(QEDAIOCB *acb)
/**
* Update L2 table with new cluster offsets and write them out
+ *
+ * Called with table_lock held.
*/
static int coroutine_fn qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset)
{
@@ -976,50 +1002,26 @@ static int coroutine_fn qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset)
/**
* Write data to the image file
+ *
+ * Called with table_lock *not* held.
*/
static int coroutine_fn qed_aio_write_main(QEDAIOCB *acb)
{
BDRVQEDState *s = acb_to_s(acb);
uint64_t offset = acb->cur_cluster +
qed_offset_into_cluster(s, acb->cur_pos);
- int ret;
trace_qed_aio_write_main(s, acb, 0, offset, acb->cur_qiov.size);
BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
- ret = bdrv_co_pwritev(s->bs->file, offset, acb->cur_qiov.size,
- &acb->cur_qiov, 0);
- if (ret < 0) {
- return ret;
- }
-
- if (acb->find_cluster_ret != QED_CLUSTER_FOUND) {
- if (s->bs->backing) {
- /*
- * Flush new data clusters before updating the L2 table
- *
- * This flush is necessary when a backing file is in use. A crash
- * during an allocating write could result in empty clusters in the
- * image. If the write only touched a subregion of the cluster,
- * then backing image sectors have been lost in the untouched
- * region. The solution is to flush after writing a new data
- * cluster and before updating the L2 table.
- */
- ret = bdrv_co_flush(s->bs->file->bs);
- if (ret < 0) {
- return ret;
- }
- }
- ret = qed_aio_write_l2_update(acb, acb->cur_cluster);
- if (ret < 0) {
- return ret;
- }
- }
- return 0;
+ return bdrv_co_pwritev(s->bs->file, offset, acb->cur_qiov.size,
+ &acb->cur_qiov, 0);
}
/**
* Populate untouched regions of new data cluster
+ *
+ * Called with table_lock held.
*/
static int coroutine_fn qed_aio_write_cow(QEDAIOCB *acb)
{
@@ -1027,6 +1029,8 @@ static int coroutine_fn qed_aio_write_cow(QEDAIOCB *acb)
uint64_t start, len, offset;
int ret;
+ qemu_co_mutex_unlock(&s->table_lock);
+
/* Populate front untouched region of new data cluster */
start = qed_start_of_cluster(s, acb->cur_pos);
len = qed_offset_into_cluster(s, acb->cur_pos);
@@ -1034,7 +1038,7 @@ static int coroutine_fn qed_aio_write_cow(QEDAIOCB *acb)
trace_qed_aio_write_prefill(s, acb, start, len, acb->cur_cluster);
ret = qed_copy_from_backing_file(s, start, len, acb->cur_cluster);
if (ret < 0) {
- return ret;
+ goto out;
}
/* Populate back untouched region of new data cluster */
@@ -1047,10 +1051,31 @@ static int coroutine_fn qed_aio_write_cow(QEDAIOCB *acb)
trace_qed_aio_write_postfill(s, acb, start, len, offset);
ret = qed_copy_from_backing_file(s, start, len, offset);
if (ret < 0) {
- return ret;
+ goto out;
+ }
+
+ ret = qed_aio_write_main(acb);
+ if (ret < 0) {
+ goto out;
+ }
+
+ if (s->bs->backing) {
+ /*
+ * Flush new data clusters before updating the L2 table
+ *
+ * This flush is necessary when a backing file is in use. A crash
+ * during an allocating write could result in empty clusters in the
+ * image. If the write only touched a subregion of the cluster,
+ * then backing image sectors have been lost in the untouched
+ * region. The solution is to flush after writing a new data
+ * cluster and before updating the L2 table.
+ */
+ ret = bdrv_co_flush(s->bs->file->bs);
}
- return qed_aio_write_main(acb);
+out:
+ qemu_co_mutex_lock(&s->table_lock);
+ return ret;
}
/**
@@ -1073,6 +1098,8 @@ static bool qed_should_set_need_check(BDRVQEDState *s)
* @len: Length in bytes
*
* This path is taken when writing to previously unallocated clusters.
+ *
+ * Called with table_lock held.
*/
static int coroutine_fn qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
{
@@ -1087,7 +1114,7 @@ static int coroutine_fn qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
/* Freeze this request if another allocating write is in progress */
if (s->allocating_acb != acb || s->allocating_write_reqs_plugged) {
if (s->allocating_acb != NULL) {
- qemu_co_queue_wait(&s->allocating_write_reqs, NULL);
+ qemu_co_queue_wait(&s->allocating_write_reqs, &s->table_lock);
assert(s->allocating_acb == NULL);
}
s->allocating_acb = acb;
@@ -1103,6 +1130,7 @@ static int coroutine_fn qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
if (acb->find_cluster_ret == QED_CLUSTER_ZERO) {
return 0;
}
+ acb->cur_cluster = 1;
} else {
acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
}
@@ -1115,15 +1143,14 @@ static int coroutine_fn qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
}
}
- if (acb->flags & QED_AIOCB_ZERO) {
- ret = qed_aio_write_l2_update(acb, 1);
- } else {
+ if (!(acb->flags & QED_AIOCB_ZERO)) {
ret = qed_aio_write_cow(acb);
+ if (ret < 0) {
+ return ret;
+ }
}
- if (ret < 0) {
- return ret;
- }
- return 0;
+
+ return qed_aio_write_l2_update(acb, acb->cur_cluster);
}
/**
@@ -1134,10 +1161,17 @@ static int coroutine_fn qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
* @len: Length in bytes
*
* This path is taken when writing to already allocated clusters.
+ *
+ * Called with table_lock held.
*/
static int coroutine_fn qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset,
size_t len)
{
+ BDRVQEDState *s = acb_to_s(acb);
+ int r;
+
+ qemu_co_mutex_unlock(&s->table_lock);
+
/* Allocate buffer for zero writes */
if (acb->flags & QED_AIOCB_ZERO) {
struct iovec *iov = acb->qiov->iov;
@@ -1145,7 +1179,8 @@ static int coroutine_fn qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset,
if (!iov->iov_base) {
iov->iov_base = qemu_try_blockalign(acb->bs, iov->iov_len);
if (iov->iov_base == NULL) {
- return -ENOMEM;
+ r = -ENOMEM;
+ goto out;
}
memset(iov->iov_base, 0, iov->iov_len);
}
@@ -1155,8 +1190,11 @@ static int coroutine_fn qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset,
acb->cur_cluster = offset;
qemu_iovec_concat(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
- /* Do the actual write */
- return qed_aio_write_main(acb);
+ /* Do the actual write. */
+ r = qed_aio_write_main(acb);
+out:
+ qemu_co_mutex_lock(&s->table_lock);
+ return r;
}
/**
@@ -1166,6 +1204,8 @@ static int coroutine_fn qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset,
* @ret: QED_CLUSTER_FOUND, QED_CLUSTER_L2 or QED_CLUSTER_L1
* @offset: Cluster offset in bytes
* @len: Length in bytes
+ *
+ * Called with table_lock held.
*/
static int coroutine_fn qed_aio_write_data(void *opaque, int ret,
uint64_t offset, size_t len)
@@ -1197,6 +1237,8 @@ static int coroutine_fn qed_aio_write_data(void *opaque, int ret,
* @ret: QED_CLUSTER_FOUND, QED_CLUSTER_L2 or QED_CLUSTER_L1
* @offset: Cluster offset in bytes
* @len: Length in bytes
+ *
+ * Called with table_lock held.
*/
static int coroutine_fn qed_aio_read_data(void *opaque, int ret,
uint64_t offset, size_t len)
@@ -1204,6 +1246,9 @@ static int coroutine_fn qed_aio_read_data(void *opaque, int ret,
QEDAIOCB *acb = opaque;
BDRVQEDState *s = acb_to_s(acb);
BlockDriverState *bs = acb->bs;
+ int r;
+
+ qemu_co_mutex_unlock(&s->table_lock);
/* Adjust offset into cluster */
offset += qed_offset_into_cluster(s, acb->cur_pos);
@@ -1212,22 +1257,23 @@ static int coroutine_fn qed_aio_read_data(void *opaque, int ret,
qemu_iovec_concat(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
- /* Handle zero cluster and backing file reads */
+ /* Handle zero cluster and backing file reads, otherwise read
+ * data cluster directly.
+ */
if (ret == QED_CLUSTER_ZERO) {
qemu_iovec_memset(&acb->cur_qiov, 0, 0, acb->cur_qiov.size);
- return 0;
+ r = 0;
} else if (ret != QED_CLUSTER_FOUND) {
- return qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov,
- &acb->backing_qiov);
+ r = qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov,
+ &acb->backing_qiov);
+ } else {
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+ r = bdrv_co_preadv(bs->file, offset, acb->cur_qiov.size,
+ &acb->cur_qiov, 0);
}
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
- ret = bdrv_co_preadv(bs->file, offset, acb->cur_qiov.size,
- &acb->cur_qiov, 0);
- if (ret < 0) {
- return ret;
- }
- return 0;
+ qemu_co_mutex_lock(&s->table_lock);
+ return r;
}
/**
@@ -1240,6 +1286,7 @@ static int coroutine_fn qed_aio_next_io(QEDAIOCB *acb)
size_t len;
int ret;
+ qemu_co_mutex_lock(&s->table_lock);
while (1) {
trace_qed_aio_next_io(s, acb, 0, acb->cur_pos + acb->cur_qiov.size);
@@ -1279,6 +1326,7 @@ static int coroutine_fn qed_aio_next_io(QEDAIOCB *acb)
trace_qed_aio_complete(s, acb, ret);
qed_aio_complete(acb);
+ qemu_co_mutex_unlock(&s->table_lock);
return ret;
}
@@ -1342,12 +1390,19 @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
QED_AIOCB_WRITE | QED_AIOCB_ZERO);
}
-static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
+static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset,
+ PreallocMode prealloc, Error **errp)
{
BDRVQEDState *s = bs->opaque;
uint64_t old_image_size;
int ret;
+ if (prealloc != PREALLOC_MODE_OFF) {
+ error_setg(errp, "Unsupported preallocation mode '%s'",
+ PreallocMode_lookup[prealloc]);
+ return -ENOTSUP;
+ }
+
if (!qed_is_image_size_valid(offset, s->header.cluster_size,
s->header.table_size)) {
error_setg(errp, "Invalid image size specified");
@@ -1467,8 +1522,14 @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp)
bdrv_qed_close(bs);
- memset(s, 0, sizeof(BDRVQEDState));
+ bdrv_qed_init_state(bs);
+ if (qemu_in_coroutine()) {
+ qemu_co_mutex_lock(&s->table_lock);
+ }
ret = bdrv_qed_do_open(bs, NULL, bs->open_flags, &local_err);
+ if (qemu_in_coroutine()) {
+ qemu_co_mutex_unlock(&s->table_lock);
+ }
if (local_err) {
error_propagate(errp, local_err);
error_prepend(errp, "Could not reopen qed layer: ");
@@ -1547,7 +1608,7 @@ static BlockDriver bdrv_qed = {
.bdrv_check = bdrv_qed_check,
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
- .bdrv_drain = bdrv_qed_drain,
+ .bdrv_co_drain = bdrv_qed_co_drain,
};
static void bdrv_qed_init(void)
diff --git a/block/qed.h b/block/qed.h
index dd3a2d5519..f35341f134 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -151,15 +151,21 @@ typedef struct QEDAIOCB {
typedef struct {
BlockDriverState *bs; /* device */
- uint64_t file_size; /* length of image file, in bytes */
+ /* Written only by an allocating write or the timer handler (the latter
+ * while allocating reqs are plugged).
+ */
QEDHeader header; /* always cpu-endian */
+
+ /* Protected by table_lock. */
+ CoMutex table_lock;
QEDTable *l1_table;
L2TableCache l2_cache; /* l2 table cache */
uint32_t table_nelems;
uint32_t l1_shift;
uint32_t l2_shift;
uint32_t l2_mask;
+ uint64_t file_size; /* length of image file, in bytes */
/* Allocating write request queue */
QEDAIOCB *allocating_acb;
@@ -177,9 +183,6 @@ enum {
QED_CLUSTER_L1, /* cluster missing in L1 */
};
-void qed_acquire(BDRVQEDState *s);
-void qed_release(BDRVQEDState *s);
-
/**
* Header functions
*/
diff --git a/block/raw-format.c b/block/raw-format.c
index 1ea8c2d7ff..142649ed56 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -312,6 +312,31 @@ static int64_t raw_getlength(BlockDriverState *bs)
return s->size;
}
+static BlockMeasureInfo *raw_measure(QemuOpts *opts, BlockDriverState *in_bs,
+ Error **errp)
+{
+ BlockMeasureInfo *info;
+ int64_t required;
+
+ if (in_bs) {
+ required = bdrv_getlength(in_bs);
+ if (required < 0) {
+ error_setg_errno(errp, -required, "Unable to get image size");
+ return NULL;
+ }
+ } else {
+ required = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
+ BDRV_SECTOR_SIZE);
+ }
+
+ info = g_new(BlockMeasureInfo, 1);
+ info->required = required;
+
+ /* Unallocated sectors count towards the file size in raw images */
+ info->fully_allocated = info->required;
+ return info;
+}
+
static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
return bdrv_get_info(bs->file->bs, bdi);
@@ -327,7 +352,8 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
}
}
-static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
+static int raw_truncate(BlockDriverState *bs, int64_t offset,
+ PreallocMode prealloc, Error **errp)
{
BDRVRawState *s = bs->opaque;
@@ -343,7 +369,7 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
s->size = offset;
offset += s->offset;
- return bdrv_truncate(bs->file, offset, errp);
+ return bdrv_truncate(bs->file, offset, prealloc, errp);
}
static int raw_media_changed(BlockDriverState *bs)
@@ -479,6 +505,7 @@ BlockDriver bdrv_raw = {
.bdrv_truncate = &raw_truncate,
.bdrv_getlength = &raw_getlength,
.has_variable_length = true,
+ .bdrv_measure = &raw_measure,
.bdrv_get_info = &raw_get_info,
.bdrv_refresh_limits = &raw_refresh_limits,
.bdrv_probe_blocksizes = &raw_probe_blocksizes,
diff --git a/block/rbd.c b/block/rbd.c
index 9da02cdceb..9c3aa638e7 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -555,9 +555,9 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
* filename encoded options */
filename = qdict_get_try_str(options, "filename");
if (filename) {
- error_report("Warning: 'filename' option specified. "
- "This is an unsupported option, and may be deprecated "
- "in the future");
+ warn_report("'filename' option specified. "
+ "This is an unsupported option, and may be deprecated "
+ "in the future");
qemu_rbd_parse_filename(filename, options, &local_err);
if (local_err) {
r = -EINVAL;
@@ -936,11 +936,18 @@ static int64_t qemu_rbd_getlength(BlockDriverState *bs)
return info.size;
}
-static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
+static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset,
+ PreallocMode prealloc, Error **errp)
{
BDRVRBDState *s = bs->opaque;
int r;
+ if (prealloc != PREALLOC_MODE_OFF) {
+ error_setg(errp, "Unsupported preallocation mode '%s'",
+ PreallocMode_lookup[prealloc]);
+ return -ENOTSUP;
+ }
+
r = rbd_resize(s->image, offset);
if (r < 0) {
error_setg_errno(errp, -r, "Failed to resize file");
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 08d7b11e9d..abb2e79065 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -390,6 +390,7 @@ struct BDRVSheepdogState {
QLIST_HEAD(inflight_aio_head, AIOReq) inflight_aio_head;
QLIST_HEAD(failed_aio_head, AIOReq) failed_aio_head;
+ CoMutex queue_lock;
CoQueue overlapping_queue;
QLIST_HEAD(inflight_aiocb_head, SheepdogAIOCB) inflight_aiocb_head;
};
@@ -488,7 +489,7 @@ static void wait_for_overlapping_aiocb(BDRVSheepdogState *s, SheepdogAIOCB *acb)
retry:
QLIST_FOREACH(cb, &s->inflight_aiocb_head, aiocb_siblings) {
if (AIOCBOverlapping(acb, cb)) {
- qemu_co_queue_wait(&s->overlapping_queue, NULL);
+ qemu_co_queue_wait(&s->overlapping_queue, &s->queue_lock);
goto retry;
}
}
@@ -525,8 +526,10 @@ static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s,
return;
}
+ qemu_co_mutex_lock(&s->queue_lock);
wait_for_overlapping_aiocb(s, acb);
QLIST_INSERT_HEAD(&s->inflight_aiocb_head, acb, aiocb_siblings);
+ qemu_co_mutex_unlock(&s->queue_lock);
}
static SocketAddress *sd_socket_address(const char *path,
@@ -785,6 +788,7 @@ static coroutine_fn void reconnect_to_sdog(void *opaque)
* have to move all the inflight requests to the failed queue before
* resend_aioreq() is called.
*/
+ qemu_co_mutex_lock(&s->queue_lock);
QLIST_FOREACH_SAFE(aio_req, &s->inflight_aio_head, aio_siblings, next) {
QLIST_REMOVE(aio_req, aio_siblings);
QLIST_INSERT_HEAD(&s->failed_aio_head, aio_req, aio_siblings);
@@ -794,8 +798,11 @@ static coroutine_fn void reconnect_to_sdog(void *opaque)
while (!QLIST_EMPTY(&s->failed_aio_head)) {
aio_req = QLIST_FIRST(&s->failed_aio_head);
QLIST_REMOVE(aio_req, aio_siblings);
+ qemu_co_mutex_unlock(&s->queue_lock);
resend_aioreq(s, aio_req);
+ qemu_co_mutex_lock(&s->queue_lock);
}
+ qemu_co_mutex_unlock(&s->queue_lock);
}
/*
@@ -887,7 +894,10 @@ static void coroutine_fn aio_read_response(void *opaque)
*/
s->co_recv = NULL;
+ qemu_co_mutex_lock(&s->queue_lock);
QLIST_REMOVE(aio_req, aio_siblings);
+ qemu_co_mutex_unlock(&s->queue_lock);
+
switch (rsp.result) {
case SD_RES_SUCCESS:
break;
@@ -1307,7 +1317,9 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
uint64_t old_oid = aio_req->base_oid;
bool create = aio_req->create;
+ qemu_co_mutex_lock(&s->queue_lock);
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
+ qemu_co_mutex_unlock(&s->queue_lock);
if (!nr_copies) {
error_report("bug");
@@ -1678,6 +1690,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
bs->total_sectors = s->inode.vdi_size / BDRV_SECTOR_SIZE;
pstrcpy(s->name, sizeof(s->name), vdi);
qemu_co_mutex_init(&s->lock);
+ qemu_co_mutex_init(&s->queue_lock);
qemu_co_queue_init(&s->overlapping_queue);
qemu_opts_del(opts);
g_free(buf);
@@ -2153,13 +2166,20 @@ static int64_t sd_getlength(BlockDriverState *bs)
return s->inode.vdi_size;
}
-static int sd_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
+static int sd_truncate(BlockDriverState *bs, int64_t offset,
+ PreallocMode prealloc, Error **errp)
{
BDRVSheepdogState *s = bs->opaque;
int ret, fd;
unsigned int datalen;
uint64_t max_vdi_size;
+ if (prealloc != PREALLOC_MODE_OFF) {
+ error_setg(errp, "Unsupported preallocation mode '%s'",
+ PreallocMode_lookup[prealloc]);
+ return -ENOTSUP;
+ }
+
max_vdi_size = (UINT64_C(1) << s->inode.block_size_shift) * MAX_DATA_OBJS;
if (offset < s->inode.vdi_size) {
error_setg(errp, "shrinking is not supported");
@@ -2431,12 +2451,16 @@ static void coroutine_fn sd_co_rw_vector(SheepdogAIOCB *acb)
static void sd_aio_complete(SheepdogAIOCB *acb)
{
+ BDRVSheepdogState *s;
if (acb->aiocb_type == AIOCB_FLUSH_CACHE) {
return;
}
+ s = acb->s;
+ qemu_co_mutex_lock(&s->queue_lock);
QLIST_REMOVE(acb, aiocb_siblings);
- qemu_co_queue_restart_all(&acb->s->overlapping_queue);
+ qemu_co_queue_restart_all(&s->overlapping_queue);
+ qemu_co_mutex_unlock(&s->queue_lock);
}
static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
@@ -2448,7 +2472,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
BDRVSheepdogState *s = bs->opaque;
if (offset > s->inode.vdi_size) {
- ret = sd_truncate(bs, offset, NULL);
+ ret = sd_truncate(bs, offset, PREALLOC_MODE_OFF, NULL);
if (ret < 0) {
return ret;
}
diff --git a/block/ssh.c b/block/ssh.c
index 52964416da..e8f0404c03 100644
--- a/block/ssh.c
+++ b/block/ssh.c
@@ -888,13 +888,22 @@ static int ssh_has_zero_init(BlockDriverState *bs)
return has_zero_init;
}
+typedef struct BDRVSSHRestart {
+ BlockDriverState *bs;
+ Coroutine *co;
+} BDRVSSHRestart;
+
static void restart_coroutine(void *opaque)
{
- Coroutine *co = opaque;
+ BDRVSSHRestart *restart = opaque;
+ BlockDriverState *bs = restart->bs;
+ BDRVSSHState *s = bs->opaque;
+ AioContext *ctx = bdrv_get_aio_context(bs);
- DPRINTF("co=%p", co);
+ DPRINTF("co=%p", restart->co);
+ aio_set_fd_handler(ctx, s->sock, false, NULL, NULL, NULL, NULL);
- aio_co_wake(co);
+ aio_co_wake(restart->co);
}
/* A non-blocking call returned EAGAIN, so yield, ensuring the
@@ -905,7 +914,10 @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
{
int r;
IOHandler *rd_handler = NULL, *wr_handler = NULL;
- Coroutine *co = qemu_coroutine_self();
+ BDRVSSHRestart restart = {
+ .bs = bs,
+ .co = qemu_coroutine_self()
+ };
r = libssh2_session_block_directions(s->session);
@@ -920,11 +932,9 @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
rd_handler, wr_handler);
aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock,
- false, rd_handler, wr_handler, NULL, co);
+ false, rd_handler, wr_handler, NULL, &restart);
qemu_coroutine_yield();
DPRINTF("s->sock=%d - back", s->sock);
- aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock, false,
- NULL, NULL, NULL, NULL);
}
/* SFTP has a function `libssh2_sftp_seek64' which seeks to a position
@@ -1114,8 +1124,8 @@ static coroutine_fn int ssh_co_writev(BlockDriverState *bs,
static void unsafe_flush_warning(BDRVSSHState *s, const char *what)
{
if (!s->unsafe_flush_warning) {
- error_report("warning: ssh server %s does not support fsync",
- s->inet->host);
+ warn_report("ssh server %s does not support fsync",
+ s->inet->host);
if (what) {
error_report("to support fsync, you need %s", what);
}
diff --git a/block/vdi.c b/block/vdi.c
index 79af47763b..8da5dfc897 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -172,7 +172,7 @@ typedef struct {
/* VDI header (converted to host endianness). */
VdiHeader header;
- CoMutex write_lock;
+ CoRwlock bmap_lock;
Error *migration_blocker;
} BDRVVdiState;
@@ -485,7 +485,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
goto fail_free_bmap;
}
- qemu_co_mutex_init(&s->write_lock);
+ qemu_co_rwlock_init(&s->bmap_lock);
return 0;
@@ -557,7 +557,9 @@ vdi_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
n_bytes, offset);
/* prepare next AIO request */
+ qemu_co_rwlock_rdlock(&s->bmap_lock);
bmap_entry = le32_to_cpu(s->bmap[block_index]);
+ qemu_co_rwlock_unlock(&s->bmap_lock);
if (!VDI_IS_ALLOCATED(bmap_entry)) {
/* Block not allocated, return zeros, no need to wait. */
qemu_iovec_memset(qiov, bytes_done, 0, n_bytes);
@@ -595,6 +597,7 @@ vdi_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
uint32_t block_index;
uint32_t offset_in_block;
uint32_t n_bytes;
+ uint64_t data_offset;
uint32_t bmap_first = VDI_UNALLOCATED;
uint32_t bmap_last = VDI_UNALLOCATED;
uint8_t *block = NULL;
@@ -614,10 +617,19 @@ vdi_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
n_bytes, offset);
/* prepare next AIO request */
+ qemu_co_rwlock_rdlock(&s->bmap_lock);
bmap_entry = le32_to_cpu(s->bmap[block_index]);
if (!VDI_IS_ALLOCATED(bmap_entry)) {
/* Allocate new block and write to it. */
uint64_t data_offset;
+ qemu_co_rwlock_upgrade(&s->bmap_lock);
+ bmap_entry = le32_to_cpu(s->bmap[block_index]);
+ if (VDI_IS_ALLOCATED(bmap_entry)) {
+ /* A concurrent allocation did the work for us. */
+ qemu_co_rwlock_downgrade(&s->bmap_lock);
+ goto nonallocating_write;
+ }
+
bmap_entry = s->header.blocks_allocated;
s->bmap[block_index] = cpu_to_le32(bmap_entry);
s->header.blocks_allocated++;
@@ -635,30 +647,18 @@ vdi_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
memset(block + offset_in_block + n_bytes, 0,
s->block_size - n_bytes - offset_in_block);
- /* Note that this coroutine does not yield anywhere from reading the
- * bmap entry until here, so in regards to all the coroutines trying
- * to write to this cluster, the one doing the allocation will
- * always be the first to try to acquire the lock.
- * Therefore, it is also the first that will actually be able to
- * acquire the lock and thus the padded cluster is written before
- * the other coroutines can write to the affected area. */
- qemu_co_mutex_lock(&s->write_lock);
+ /* Write the new block under CoRwLock write-side protection,
+ * so this full-cluster write does not overlap a partial write
+ * of the same cluster, issued from the "else" branch.
+ */
ret = bdrv_pwrite(bs->file, data_offset, block, s->block_size);
- qemu_co_mutex_unlock(&s->write_lock);
+ qemu_co_rwlock_unlock(&s->bmap_lock);
} else {
- uint64_t data_offset = s->header.offset_data +
- (uint64_t)bmap_entry * s->block_size +
- offset_in_block;
- qemu_co_mutex_lock(&s->write_lock);
- /* This lock is only used to make sure the following write operation
- * is executed after the write issued by the coroutine allocating
- * this cluster, therefore we do not need to keep it locked.
- * As stated above, the allocating coroutine will always try to lock
- * the mutex before all the other concurrent accesses to that
- * cluster, therefore at this point we can be absolutely certain
- * that that write operation has returned (there may be other writes
- * in flight, but they do not concern this very operation). */
- qemu_co_mutex_unlock(&s->write_lock);
+nonallocating_write:
+ data_offset = s->header.offset_data +
+ (uint64_t)bmap_entry * s->block_size +
+ offset_in_block;
+ qemu_co_rwlock_unlock(&s->bmap_lock);
qemu_iovec_reset(&local_qiov);
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
@@ -832,7 +832,8 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
}
if (image_type == VDI_TYPE_STATIC) {
- ret = blk_truncate(blk, offset + blocks * block_size, errp);
+ ret = blk_truncate(blk, offset + blocks * block_size,
+ PREALLOC_MODE_OFF, errp);
if (ret < 0) {
error_prepend(errp, "Failed to statically allocate %s", filename);
goto exit;
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
index 3f4c2aa095..01278f3fc9 100644
--- a/block/vhdx-log.c
+++ b/block/vhdx-log.c
@@ -548,7 +548,7 @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
if (new_file_size % (1024*1024)) {
/* round up to nearest 1MB boundary */
new_file_size = ((new_file_size >> 20) + 1) << 20;
- bdrv_truncate(bs->file, new_file_size, NULL);
+ bdrv_truncate(bs->file, new_file_size, PREALLOC_MODE_OFF, NULL);
}
}
qemu_vfree(desc_entries);
diff --git a/block/vhdx.c b/block/vhdx.c
index 8b270b57c9..a9cecd2773 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -1171,7 +1171,8 @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
/* per the spec, the address for a block is in units of 1MB */
*new_offset = ROUND_UP(*new_offset, 1024 * 1024);
- return bdrv_truncate(bs->file, *new_offset + s->block_size, NULL);
+ return bdrv_truncate(bs->file, *new_offset + s->block_size,
+ PREALLOC_MODE_OFF, NULL);
}
/*
@@ -1607,12 +1608,13 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
if (type == VHDX_TYPE_DYNAMIC) {
/* All zeroes, so we can just extend the file - the end of the BAT
* is the furthest thing we have written yet */
- ret = blk_truncate(blk, data_file_offset, errp);
+ ret = blk_truncate(blk, data_file_offset, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto exit;
}
} else if (type == VHDX_TYPE_FIXED) {
- ret = blk_truncate(blk, data_file_offset + image_size, errp);
+ ret = blk_truncate(blk, data_file_offset + image_size,
+ PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto exit;
}
diff --git a/block/vmdk.c b/block/vmdk.c
index 55581b03fe..24d71b5982 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1714,7 +1714,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
blk_set_allow_write_beyond_eof(blk, true);
if (flat) {
- ret = blk_truncate(blk, filesize, errp);
+ ret = blk_truncate(blk, filesize, PREALLOC_MODE_OFF, errp);
goto exit;
}
magic = cpu_to_be32(VMDK4_MAGIC);
@@ -1777,7 +1777,8 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
goto exit;
}
- ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, errp);
+ ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9,
+ PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto exit;
}
@@ -2086,7 +2087,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
/* bdrv_pwrite write padding zeros to align to sector, we don't need that
* for description file */
if (desc_offset == 0) {
- ret = blk_truncate(new_blk, desc_len, errp);
+ ret = blk_truncate(new_blk, desc_len, PREALLOC_MODE_OFF, errp);
}
exit:
if (new_blk) {
diff --git a/block/vpc.c b/block/vpc.c
index b313c68148..8057d42a23 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -496,12 +496,6 @@ static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
return block_offset;
}
-static inline int64_t get_sector_offset(BlockDriverState *bs,
- int64_t sector_num, bool write)
-{
- return get_image_offset(bs, sector_num * BDRV_SECTOR_SIZE, write);
-}
-
/*
* Writes the footer to the end of the image file. This is needed when the
* file grows as it overwrites the old footer
@@ -696,6 +690,7 @@ static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
VHDFooter *footer = (VHDFooter*) s->footer_buf;
int64_t start, offset;
bool allocated;
+ int64_t ret;
int n;
if (be32_to_cpu(footer->type) == VHD_FIXED) {
@@ -705,10 +700,13 @@ static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
(sector_num << BDRV_SECTOR_BITS);
}
- offset = get_sector_offset(bs, sector_num, 0);
+ qemu_co_mutex_lock(&s->lock);
+
+ offset = get_image_offset(bs, sector_num << BDRV_SECTOR_BITS, false);
start = offset;
allocated = (offset != -1);
*pnum = 0;
+ ret = 0;
do {
/* All sectors in a block are contiguous (without using the bitmap) */
@@ -723,15 +721,17 @@ static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
* sectors since there is always a bitmap in between. */
if (allocated) {
*file = bs->file->bs;
- return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
+ ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
+ break;
}
if (nb_sectors == 0) {
break;
}
- offset = get_sector_offset(bs, sector_num, 0);
+ offset = get_image_offset(bs, sector_num << BDRV_SECTOR_BITS, false);
} while (offset == -1);
- return 0;
+ qemu_co_mutex_unlock(&s->lock);
+ return ret;
}
/*
@@ -858,7 +858,7 @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
/* Add footer to total size */
total_size += HEADER_SIZE;
- ret = blk_truncate(blk, total_size, errp);
+ ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
return ret;
}
diff --git a/block/vvfat.c b/block/vvfat.c
index 4fd28e1e87..4dae790203 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -3078,8 +3078,14 @@ static int coroutine_fn
write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{
+ int ret;
+
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
- return try_commit(s);
+ qemu_co_mutex_lock(&s->lock);
+ ret = try_commit(s);
+ qemu_co_mutex_unlock(&s->lock);
+
+ return ret;
}
static void write_target_close(BlockDriverState *bs) {
diff --git a/blockdev.c b/blockdev.c
index e2016b6f37..7f53cc8bb3 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -593,10 +593,6 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
bs->detect_zeroes = detect_zeroes;
- if (bdrv_key_required(bs)) {
- autostart = 0;
- }
-
block_acct_setup(blk_get_stats(blk), account_invalid, account_failed);
if (!parse_stats_intervals(blk_get_stats(blk), interval_list, errp)) {
@@ -914,7 +910,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
copy_on_read = qemu_opt_get_bool(legacy_opts, "copy-on-read", false);
if (read_only && copy_on_read) {
- error_report("warning: disabling copy-on-read on read-only drive");
+ warn_report("disabling copy-on-read on read-only drive");
copy_on_read = false;
}
@@ -1987,6 +1983,8 @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common,
/* AIO context taken and released within qmp_block_dirty_bitmap_add */
qmp_block_dirty_bitmap_add(action->node, action->name,
action->has_granularity, action->granularity,
+ action->has_persistent, action->persistent,
+ action->has_autoload, action->autoload,
&local_err);
if (!local_err) {
@@ -2037,6 +2035,9 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
} else if (!bdrv_dirty_bitmap_enabled(state->bitmap)) {
error_setg(errp, "Cannot clear a disabled bitmap");
return;
+ } else if (bdrv_dirty_bitmap_readonly(state->bitmap)) {
+ error_setg(errp, "Cannot clear a readonly bitmap");
+ return;
}
bdrv_clear_dirty_bitmap(state->bitmap, &state->backup);
@@ -2265,24 +2266,8 @@ void qmp_block_passwd(bool has_device, const char *device,
bool has_node_name, const char *node_name,
const char *password, Error **errp)
{
- Error *local_err = NULL;
- BlockDriverState *bs;
- AioContext *aio_context;
-
- bs = bdrv_lookup_bs(has_device ? device : NULL,
- has_node_name ? node_name : NULL,
- &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
-
- bdrv_add_key(bs, password, errp);
-
- aio_context_release(aio_context);
+ error_setg(errp,
+ "Setting block passwords directly is no longer supported");
}
/*
@@ -2591,12 +2576,6 @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
goto fail;
}
- bdrv_add_key(medium_bs, NULL, &err);
- if (err) {
- error_propagate(errp, err);
- goto fail;
- }
-
rc = do_open_tray(has_device ? device : NULL,
has_id ? id : NULL,
false, &err);
@@ -2731,9 +2710,12 @@ out:
void qmp_block_dirty_bitmap_add(const char *node, const char *name,
bool has_granularity, uint32_t granularity,
+ bool has_persistent, bool persistent,
+ bool has_autoload, bool autoload,
Error **errp)
{
BlockDriverState *bs;
+ BdrvDirtyBitmap *bitmap;
if (!name || name[0] == '\0') {
error_setg(errp, "Bitmap name cannot be empty");
@@ -2756,7 +2738,32 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
granularity = bdrv_get_default_bitmap_granularity(bs);
}
- bdrv_create_dirty_bitmap(bs, granularity, name, errp);
+ if (!has_persistent) {
+ persistent = false;
+ }
+ if (!has_autoload) {
+ autoload = false;
+ }
+
+ if (has_autoload && !persistent) {
+ error_setg(errp, "Autoload flag must be used only for persistent "
+ "bitmaps");
+ return;
+ }
+
+ if (persistent &&
+ !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp))
+ {
+ return;
+ }
+
+ bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
+ if (bitmap == NULL) {
+ return;
+ }
+
+ bdrv_dirty_bitmap_set_persistance(bitmap, persistent);
+ bdrv_dirty_bitmap_set_autoload(bitmap, autoload);
}
void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
@@ -2764,6 +2771,7 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
{
BlockDriverState *bs;
BdrvDirtyBitmap *bitmap;
+ Error *local_err = NULL;
bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
if (!bitmap || !bs) {
@@ -2776,6 +2784,15 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
name);
return;
}
+
+ if (bdrv_dirty_bitmap_get_persistance(bitmap)) {
+ bdrv_remove_persistent_dirty_bitmap(bs, name, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+
bdrv_dirty_bitmap_make_anon(bitmap);
bdrv_release_dirty_bitmap(bs, bitmap);
}
@@ -2805,11 +2822,39 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
"Bitmap '%s' is currently disabled and cannot be cleared",
name);
return;
+ } else if (bdrv_dirty_bitmap_readonly(bitmap)) {
+ error_setg(errp, "Bitmap '%s' is readonly and cannot be cleared", name);
+ return;
}
bdrv_clear_dirty_bitmap(bitmap, NULL);
}
+BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,
+ const char *name,
+ Error **errp)
+{
+ BdrvDirtyBitmap *bitmap;
+ BlockDriverState *bs;
+ BlockDirtyBitmapSha256 *ret = NULL;
+ char *sha256;
+
+ bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
+ if (!bitmap || !bs) {
+ return NULL;
+ }
+
+ sha256 = bdrv_dirty_bitmap_sha256(bitmap, errp);
+ if (sha256 == NULL) {
+ return NULL;
+ }
+
+ ret = g_new(BlockDirtyBitmapSha256, 1);
+ ret->sha256 = sha256;
+
+ return ret;
+}
+
void hmp_drive_del(Monitor *mon, const QDict *qdict)
{
const char *id = qdict_get_str(qdict, "id");
@@ -2913,7 +2958,7 @@ void qmp_block_resize(bool has_device, const char *device,
}
bdrv_drained_begin(bs);
- ret = blk_truncate(blk, size, errp);
+ ret = blk_truncate(blk, size, PREALLOC_MODE_OFF, errp);
bdrv_drained_end(bs);
out:
@@ -3866,13 +3911,6 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list);
- if (bs && bdrv_key_required(bs)) {
- QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list);
- bdrv_unref(bs);
- error_setg(errp, "blockdev-add doesn't support encrypted devices");
- goto fail;
- }
-
fail:
visit_free(v);
}
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index b550cee0cb..19b2b8fecb 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -85,6 +85,8 @@ struct emulated_sigtable {
/* NOTE: we force a big alignment so that the stack stored after is
aligned too */
typedef struct TaskState {
+ pid_t ts_tid; /* tid (or pid) of this task */
+
struct TaskState *next;
int used; /* non zero if used */
struct image_info *info;
diff --git a/chardev/char-fe.c b/chardev/char-fe.c
index 3f90f0567c..f3af6ae584 100644
--- a/chardev/char-fe.c
+++ b/chardev/char-fe.c
@@ -179,9 +179,21 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
Chardev *qemu_chr_fe_get_driver(CharBackend *be)
{
+ /* this is unsafe for the users that support chardev hotswap */
+ assert(be->chr_be_change == NULL);
return be->chr;
}
+bool qemu_chr_fe_backend_connected(CharBackend *be)
+{
+ return !!be->chr;
+}
+
+bool qemu_chr_fe_backend_open(CharBackend *be)
+{
+ return be->chr && be->chr->be_open;
+}
+
bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp)
{
int tag = 0;
@@ -216,7 +228,7 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del)
assert(b);
if (b->chr) {
- qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true);
+ qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, NULL, true);
if (b->chr->be == b) {
b->chr->be = NULL;
}
@@ -235,6 +247,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
IOCanReadHandler *fd_can_read,
IOReadHandler *fd_read,
IOEventHandler *fd_event,
+ BackendChangeHandler *be_change,
void *opaque,
GMainContext *context,
bool set_open)
@@ -258,6 +271,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
b->chr_can_read = fd_can_read;
b->chr_read = fd_read;
b->chr_event = fd_event;
+ b->chr_be_change = be_change;
b->opaque = opaque;
if (cc->chr_update_read_handler) {
cc->chr_update_read_handler(s, context);
diff --git a/chardev/char-mux.c b/chardev/char-mux.c
index 08570b915e..4cda5e7458 100644
--- a/chardev/char-mux.c
+++ b/chardev/char-mux.c
@@ -278,6 +278,7 @@ void mux_chr_set_handlers(Chardev *chr, GMainContext *context)
mux_chr_can_read,
mux_chr_read,
mux_chr_event,
+ NULL,
chr,
context, true);
}
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index ccc499cfa1..1ae730a4cb 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -454,7 +454,9 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
return 0;
}
+ qio_channel_set_blocking(s->ioc, true, NULL);
size = tcp_chr_recv(chr, (void *) buf, len);
+ qio_channel_set_blocking(s->ioc, false, NULL);
if (size == 0) {
/* connection closed */
tcp_chr_disconnect(chr);
@@ -765,8 +767,8 @@ static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
* in TLS and telnet cases, only wait for an accepted socket */
while (!s->ioc) {
if (s->is_listen) {
- error_report("QEMU waiting for connection on: %s",
- chr->filename);
+ info_report("QEMU waiting for connection on: %s",
+ chr->filename);
qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), true, NULL);
tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
diff --git a/chardev/char.c b/chardev/char.c
index 2b679a2295..c34b44abc9 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -556,17 +556,23 @@ help_string_append(const char *name, void *opaque)
g_string_append_printf(str, "\n%s", name);
}
-Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
- Error **errp)
+static const char *chardev_alias_translate(const char *name)
+{
+ int i;
+ for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) {
+ if (g_strcmp0(chardev_alias_table[i].alias, name) == 0) {
+ return chardev_alias_table[i].typename;
+ }
+ }
+ return name;
+}
+
+ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp)
{
Error *local_err = NULL;
const ChardevClass *cc;
- Chardev *chr;
- int i;
ChardevBackend *backend = NULL;
- const char *name = qemu_opt_get(opts, "backend");
- const char *id = qemu_opts_id(opts);
- char *bid = NULL;
+ const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend"));
if (name == NULL) {
error_setg(errp, "chardev: \"%s\" missing backend",
@@ -574,7 +580,40 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
return NULL;
}
- if (is_help_option(name)) {
+ cc = char_get_class(name, errp);
+ if (cc == NULL) {
+ return NULL;
+ }
+
+ backend = g_new0(ChardevBackend, 1);
+ backend->type = CHARDEV_BACKEND_KIND_NULL;
+
+ if (cc->parse) {
+ cc->parse(opts, backend, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ qapi_free_ChardevBackend(backend);
+ return NULL;
+ }
+ } else {
+ ChardevCommon *ccom = g_new0(ChardevCommon, 1);
+ qemu_chr_parse_common(opts, ccom);
+ backend->u.null.data = ccom; /* Any ChardevCommon member would work */
+ }
+
+ return backend;
+}
+
+Chardev *qemu_chr_new_from_opts(QemuOpts *opts, Error **errp)
+{
+ const ChardevClass *cc;
+ Chardev *chr = NULL;
+ ChardevBackend *backend = NULL;
+ const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend"));
+ const char *id = qemu_opts_id(opts);
+ char *bid = NULL;
+
+ if (name && is_help_option(name)) {
GString *str = g_string_new("");
chardev_name_foreach(help_string_append, str);
@@ -589,38 +628,20 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
return NULL;
}
- for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) {
- if (g_strcmp0(chardev_alias_table[i].alias, name) == 0) {
- name = chardev_alias_table[i].typename;
- break;
- }
+ backend = qemu_chr_parse_opts(opts, errp);
+ if (backend == NULL) {
+ return NULL;
}
cc = char_get_class(name, errp);
if (cc == NULL) {
- return NULL;
+ goto out;
}
- backend = g_new0(ChardevBackend, 1);
- backend->type = CHARDEV_BACKEND_KIND_NULL;
-
if (qemu_opt_get_bool(opts, "mux", 0)) {
bid = g_strdup_printf("%s-base", id);
}
- chr = NULL;
- if (cc->parse) {
- cc->parse(opts, backend, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- goto out;
- }
- } else {
- ChardevCommon *ccom = g_new0(ChardevCommon, 1);
- qemu_chr_parse_common(opts, ccom);
- backend->u.null.data = ccom; /* Any ChardevCommon member would work */
- }
-
chr = qemu_chardev_new(bid ? bid : id,
object_class_get_name(OBJECT_CLASS(cc)),
backend, errp);
@@ -930,6 +951,89 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
return ret;
}
+ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend,
+ Error **errp)
+{
+ CharBackend *be;
+ const ChardevClass *cc;
+ Chardev *chr, *chr_new;
+ bool closed_sent = false;
+ ChardevReturn *ret;
+
+ chr = qemu_chr_find(id);
+ if (!chr) {
+ error_setg(errp, "Chardev '%s' does not exist", id);
+ return NULL;
+ }
+
+ if (CHARDEV_IS_MUX(chr)) {
+ error_setg(errp, "Mux device hotswap not supported yet");
+ return NULL;
+ }
+
+ if (qemu_chr_replay(chr)) {
+ error_setg(errp,
+ "Chardev '%s' cannot be changed in record/replay mode", id);
+ return NULL;
+ }
+
+ be = chr->be;
+ if (!be) {
+ /* easy case */
+ object_unparent(OBJECT(chr));
+ return qmp_chardev_add(id, backend, errp);
+ }
+
+ if (!be->chr_be_change) {
+ error_setg(errp, "Chardev user does not support chardev hotswap");
+ return NULL;
+ }
+
+ cc = char_get_class(ChardevBackendKind_lookup[backend->type], errp);
+ if (!cc) {
+ return NULL;
+ }
+
+ chr_new = qemu_chardev_new(NULL, object_class_get_name(OBJECT_CLASS(cc)),
+ backend, errp);
+ if (!chr_new) {
+ return NULL;
+ }
+ chr_new->label = g_strdup(id);
+
+ if (chr->be_open && !chr_new->be_open) {
+ qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
+ closed_sent = true;
+ }
+
+ chr->be = NULL;
+ qemu_chr_fe_init(be, chr_new, &error_abort);
+
+ if (be->chr_be_change(be->opaque) < 0) {
+ error_setg(errp, "Chardev '%s' change failed", chr_new->label);
+ chr_new->be = NULL;
+ qemu_chr_fe_init(be, chr, &error_abort);
+ if (closed_sent) {
+ qemu_chr_be_event(chr, CHR_EVENT_OPENED);
+ }
+ object_unref(OBJECT(chr_new));
+ return NULL;
+ }
+
+ object_unparent(OBJECT(chr));
+ object_property_add_child(get_chardevs_root(), chr_new->label,
+ OBJECT(chr_new), &error_abort);
+ object_unref(OBJECT(chr_new));
+
+ ret = g_new0(ChardevReturn, 1);
+ if (CHARDEV_IS_PTY(chr_new)) {
+ ret->pty = g_strdup(chr_new->filename + 4);
+ ret->has_pty = true;
+ }
+
+ return ret;
+}
+
void qmp_chardev_remove(const char *id, Error **errp)
{
Chardev *chr;
diff --git a/configure b/configure
index 5096cbcf14..a3f0522e8f 100755
--- a/configure
+++ b/configure
@@ -1583,7 +1583,7 @@ gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
gcc_flags="-Wno-missing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
gcc_flags="-Wendif-labels -Wno-shift-negative-value $gcc_flags"
-gcc_flags="-Wno-initializer-overrides $gcc_flags"
+gcc_flags="-Wno-initializer-overrides -Wexpansion-to-defined $gcc_flags"
gcc_flags="-Wno-string-plus-int $gcc_flags"
# Note that we do not add -Werror to gcc_flags here, because that would
# enable it for all configure tests. If a configure test failed due
@@ -2733,7 +2733,11 @@ int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
EOF
sdl_cflags=$($sdlconfig --cflags 2>/dev/null)
if test "$static" = "yes" ; then
- sdl_libs=$($sdlconfig --static-libs 2>/dev/null)
+ if $pkg_config $sdlname --exists; then
+ sdl_libs=$($pkg_config $sdlname --static --libs 2>/dev/null)
+ else
+ sdl_libs=$($sdlconfig --static-libs 2>/dev/null)
+ fi
else
sdl_libs=$($sdlconfig --libs 2>/dev/null)
fi
@@ -4767,7 +4771,7 @@ fi
if test "$fortify_source" != "no"; then
if echo | $cc -dM -E - | grep __clang__ > /dev/null 2>&1 ; then
fortify_source="no";
- elif test -n "$cxx" &&
+ elif test -n "$cxx" && has $cxx &&
echo | $cxx -dM -E - | grep __clang__ >/dev/null 2>&1 ; then
fortify_source="no";
else
@@ -6227,7 +6231,7 @@ case "$target_name" in
echo "TARGET_ABI32=y" >> $config_target_mak
;;
s390x)
- gdb_xml_files="s390x-core64.xml s390-acr.xml s390-fpr.xml s390-vx.xml s390-cr.xml s390-virt.xml"
+ gdb_xml_files="s390x-core64.xml s390-acr.xml s390-fpr.xml s390-vx.xml s390-cr.xml s390-virt.xml s390-gs.xml"
;;
tilegx)
;;
diff --git a/cpus.c b/cpus.c
index 14bb8d552e..9bed61eefc 100644
--- a/cpus.c
+++ b/cpus.c
@@ -557,7 +557,7 @@ void qemu_start_warp_timer(void)
if (deadline < 0) {
static bool notified;
if (!icount_sleep && !notified) {
- error_report("WARNING: icount sleep disabled and no active timers");
+ warn_report("icount sleep disabled and no active timers");
notified = true;
}
return;
diff --git a/crypto/block-luks.c b/crypto/block-luks.c
index 2b97d89a69..afb8543108 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -638,6 +638,7 @@ qcrypto_block_luks_find_key(QCryptoBlock *block,
static int
qcrypto_block_luks_open(QCryptoBlock *block,
QCryptoBlockOpenOptions *options,
+ const char *optprefix,
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
@@ -661,7 +662,8 @@ qcrypto_block_luks_open(QCryptoBlock *block,
if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) {
if (!options->u.luks.key_secret) {
- error_setg(errp, "Parameter 'key-secret' is required for cipher");
+ error_setg(errp, "Parameter '%skey-secret' is required for cipher",
+ optprefix ? optprefix : "");
return -1;
}
password = qcrypto_secret_lookup_as_utf8(
@@ -885,6 +887,7 @@ qcrypto_block_luks_uuid_gen(uint8_t *uuidstr)
static int
qcrypto_block_luks_create(QCryptoBlock *block,
QCryptoBlockCreateOptions *options,
+ const char *optprefix,
QCryptoBlockInitFunc initfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,
@@ -937,7 +940,8 @@ qcrypto_block_luks_create(QCryptoBlock *block,
* be silently ignored, for compatibility with dm-crypt */
if (!options->u.luks.key_secret) {
- error_setg(errp, "Parameter 'key-secret' is required for cipher");
+ error_setg(errp, "Parameter '%skey-secret' is required for cipher",
+ optprefix ? optprefix : "");
return -1;
}
password = qcrypto_secret_lookup_as_utf8(luks_opts.key_secret, errp);
diff --git a/crypto/block-qcow.c b/crypto/block-qcow.c
index be88c6f0ef..a456fe338b 100644
--- a/crypto/block-qcow.c
+++ b/crypto/block-qcow.c
@@ -94,6 +94,7 @@ qcrypto_block_qcow_init(QCryptoBlock *block,
static int
qcrypto_block_qcow_open(QCryptoBlock *block,
QCryptoBlockOpenOptions *options,
+ const char *optprefix,
QCryptoBlockReadFunc readfunc G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED,
unsigned int flags,
@@ -104,7 +105,8 @@ qcrypto_block_qcow_open(QCryptoBlock *block,
} else {
if (!options->u.qcow.key_secret) {
error_setg(errp,
- "Parameter 'key-secret' is required for cipher");
+ "Parameter '%skey-secret' is required for cipher",
+ optprefix ? optprefix : "");
return -1;
}
return qcrypto_block_qcow_init(block,
@@ -116,13 +118,15 @@ qcrypto_block_qcow_open(QCryptoBlock *block,
static int
qcrypto_block_qcow_create(QCryptoBlock *block,
QCryptoBlockCreateOptions *options,
+ const char *optprefix,
QCryptoBlockInitFunc initfunc G_GNUC_UNUSED,
QCryptoBlockWriteFunc writefunc G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED,
Error **errp)
{
if (!options->u.qcow.key_secret) {
- error_setg(errp, "Parameter 'key-secret' is required for cipher");
+ error_setg(errp, "Parameter '%skey-secret' is required for cipher",
+ optprefix ? optprefix : "");
return -1;
}
/* QCow2 has no special header, since everything is hardwired */
diff --git a/crypto/block.c b/crypto/block.c
index 64c8420425..b097d451af 100644
--- a/crypto/block.c
+++ b/crypto/block.c
@@ -48,6 +48,7 @@ bool qcrypto_block_has_format(QCryptoBlockFormat format,
QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
+ const char *optprefix,
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
@@ -67,7 +68,7 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
block->driver = qcrypto_block_drivers[options->format];
- if (block->driver->open(block, options,
+ if (block->driver->open(block, options, optprefix,
readfunc, opaque, flags, errp) < 0) {
g_free(block);
return NULL;
@@ -78,6 +79,7 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
+ const char *optprefix,
QCryptoBlockInitFunc initfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,
@@ -97,7 +99,7 @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
block->driver = qcrypto_block_drivers[options->format];
- if (block->driver->create(block, options, initfunc,
+ if (block->driver->create(block, options, optprefix, initfunc,
writefunc, opaque, errp) < 0) {
g_free(block);
return NULL;
diff --git a/crypto/blockpriv.h b/crypto/blockpriv.h
index 68f0f06704..0edb810e22 100644
--- a/crypto/blockpriv.h
+++ b/crypto/blockpriv.h
@@ -41,6 +41,7 @@ struct QCryptoBlock {
struct QCryptoBlockDriver {
int (*open)(QCryptoBlock *block,
QCryptoBlockOpenOptions *options,
+ const char *optprefix,
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
@@ -48,6 +49,7 @@ struct QCryptoBlockDriver {
int (*create)(QCryptoBlock *block,
QCryptoBlockCreateOptions *options,
+ const char *optprefix,
QCryptoBlockInitFunc initfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,
diff --git a/docs/devel/memory.txt b/docs/devel/memory.txt
index 811b1bd3c5..8ed810f8b9 100644
--- a/docs/devel/memory.txt
+++ b/docs/devel/memory.txt
@@ -91,6 +91,37 @@ one of whose subregions is a low priority "background" region covering
the whole address range; this is often clearer and is preferred.
Subregions cannot be added to an alias region.
+Migration
+---------
+
+Where the memory region is backed by host memory (RAM, ROM and
+ROM device memory region types), this host memory needs to be
+copied to the destination on migration. These APIs which allocate
+the host memory for you will also register the memory so it is
+migrated:
+ - memory_region_init_ram()
+ - memory_region_init_rom()
+ - memory_region_init_rom_device()
+
+For most devices and boards this is the correct thing. If you
+have a special case where you need to manage the migration of
+the backing memory yourself, you can call the functions:
+ - memory_region_init_ram_nomigrate()
+ - memory_region_init_rom_nomigrate()
+ - memory_region_init_rom_device_nomigrate()
+which only initialize the MemoryRegion and leave handling
+migration to the caller.
+
+The functions:
+ - memory_region_init_resizeable_ram()
+ - memory_region_init_ram_from_file()
+ - memory_region_init_ram_from_fd()
+ - memory_region_init_ram_ptr()
+ - memory_region_init_ram_device_ptr()
+are for special cases only, and so they do not automatically
+register the backing memory for migration; the caller must
+manage migration if necessary.
+
Region names
------------
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
index 80cdfd0e91..d7fdb1fee3 100644
--- a/docs/interop/qcow2.txt
+++ b/docs/interop/qcow2.txt
@@ -45,6 +45,7 @@ The first cluster of a qcow2 image contains the file header:
32 - 35: crypt_method
0 for no encryption
1 for AES encryption
+ 2 for LUKS encryption
36 - 39: l1_size
Number of entries in the active L1 table
@@ -135,6 +136,7 @@ be stored. Each extension has a structure like the following:
0xE2792ACA - Backing file format name
0x6803f857 - Feature name table
0x23852875 - Bitmaps extension
+ 0x0537be77 - Full disk encryption header pointer
other - Unknown header extension, can be safely
ignored
@@ -201,12 +203,113 @@ The fields of the bitmaps extension are:
8 - 15: bitmap_directory_size
Size of the bitmap directory in bytes. It is the cumulative
- size of all (nb_bitmaps) bitmap headers.
+ size of all (nb_bitmaps) bitmap directory entries.
16 - 23: bitmap_directory_offset
Offset into the image file at which the bitmap directory
starts. Must be aligned to a cluster boundary.
+== Full disk encryption header pointer ==
+
+The full disk encryption header must be present if, and only if, the
+'crypt_method' header requires metadata. Currently this is only true
+of the 'LUKS' crypt method. The header extension must be absent for
+other methods.
+
+This header provides the offset at which the crypt method can store
+its additional data, as well as the length of such data.
+
+ Byte 0 - 7: Offset into the image file at which the encryption
+ header starts in bytes. Must be aligned to a cluster
+ boundary.
+ Byte 8 - 15: Length of the written encryption header in bytes.
+ Note actual space allocated in the qcow2 file may
+ be larger than this value, since it will be rounded
+ to the nearest multiple of the cluster size. Any
+ unused bytes in the allocated space will be initialized
+ to 0.
+
+For the LUKS crypt method, the encryption header works as follows.
+
+The first 592 bytes of the header clusters will contain the LUKS
+partition header. This is then followed by the key material data areas.
+The size of the key material data areas is determined by the number of
+stripes in the key slot and key size. Refer to the LUKS format
+specification ('docs/on-disk-format.pdf' in the cryptsetup source
+package) for details of the LUKS partition header format.
+
+In the LUKS partition header, the "payload-offset" field will be
+calculated as normal for the LUKS spec. ie the size of the LUKS
+header, plus key material regions, plus padding, relative to the
+start of the LUKS header. This offset value is not required to be
+qcow2 cluster aligned. Its value is currently never used in the
+context of qcow2, since the qcow2 file format itself defines where
+the real payload offset is, but none the less a valid payload offset
+should always be present.
+
+In the LUKS key slots header, the "key-material-offset" is relative
+to the start of the LUKS header clusters in the qcow2 container,
+not the start of the qcow2 file.
+
+Logically the layout looks like
+
+ +-----------------------------+
+ | QCow2 header |
+ | QCow2 header extension X |
+ | QCow2 header extension FDE |
+ | QCow2 header extension ... |
+ | QCow2 header extension Z |
+ +-----------------------------+
+ | ....other QCow2 tables.... |
+ . .
+ . .
+ +-----------------------------+
+ | +-------------------------+ |
+ | | LUKS partition header | |
+ | +-------------------------+ |
+ | | LUKS key material 1 | |
+ | +-------------------------+ |
+ | | LUKS key material 2 | |
+ | +-------------------------+ |
+ | | LUKS key material ... | |
+ | +-------------------------+ |
+ | | LUKS key material 8 | |
+ | +-------------------------+ |
+ +-----------------------------+
+ | QCow2 cluster payload |
+ . .
+ . .
+ . .
+ | |
+ +-----------------------------+
+
+== Data encryption ==
+
+When an encryption method is requested in the header, the image payload
+data must be encrypted/decrypted on every write/read. The image headers
+and metadata are never encrypted.
+
+The algorithms used for encryption vary depending on the method
+
+ - AES:
+
+ The AES cipher, in CBC mode, with 256 bit keys.
+
+ Initialization vectors generated using plain64 method, with
+ the virtual disk sector as the input tweak.
+
+ This format is no longer supported in QEMU system emulators, due
+ to a number of design flaws affecting its security. It is only
+ supported in the command line tools for the sake of back compatibility
+ and data liberation.
+
+ - LUKS:
+
+ The algorithms are specified in the LUKS header.
+
+ Initialization vectors generated using the method specified
+ in the LUKS header, with the physical disk sector as the
+ input tweak.
== Host cluster management ==
@@ -426,8 +529,7 @@ Each bitmap saved in the image is described in a bitmap directory entry. The
bitmap directory is a contiguous area in the image file, whose starting offset
and length are given by the header extension fields bitmap_directory_offset and
bitmap_directory_size. The entries of the bitmap directory have variable
-length, depending on the lengths of the bitmap name and extra data. These
-entries are also called bitmap headers.
+length, depending on the lengths of the bitmap name and extra data.
Structure of a bitmap directory entry:
@@ -472,8 +574,7 @@ Structure of a bitmap directory entry:
17: granularity_bits
Granularity bits. Valid values: 0 - 63.
- Note: Qemu currently doesn't support granularity_bits
- greater than 31.
+ Note: Qemu currently supports only values 9 - 31.
Granularity is calculated as
granularity = 1 << granularity_bits
diff --git a/exec.c b/exec.c
index a083ff89ad..01ac21e3cd 100644
--- a/exec.c
+++ b/exec.c
@@ -27,6 +27,7 @@
#include "exec/target_page.h"
#include "tcg.h"
#include "hw/qdev-core.h"
+#include "hw/qdev-properties.h"
#if !defined(CONFIG_USER_ONLY)
#include "hw/boards.h"
#include "hw/xen/xen.h"
@@ -480,19 +481,21 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as,
{
IOMMUTLBEntry iotlb;
MemoryRegionSection *section;
- MemoryRegion *mr;
+ IOMMUMemoryRegion *iommu_mr;
+ IOMMUMemoryRegionClass *imrc;
for (;;) {
AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch);
section = address_space_translate_internal(d, addr, &addr, plen, is_mmio);
- mr = section->mr;
- if (!mr->iommu_ops) {
+ iommu_mr = memory_region_get_iommu(section->mr);
+ if (!iommu_mr) {
break;
}
+ imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
- iotlb = mr->iommu_ops->translate(mr, addr, is_write ?
- IOMMU_WO : IOMMU_RO);
+ iotlb = imrc->translate(iommu_mr, addr, is_write ?
+ IOMMU_WO : IOMMU_RO);
addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
| (addr & iotlb.addr_mask));
*plen = MIN(*plen, (addr | iotlb.addr_mask) - addr + 1);
@@ -588,7 +591,7 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
section = address_space_translate_internal(d, addr, xlat, plen, false);
- assert(!section->mr->iommu_ops);
+ assert(!memory_region_is_iommu(section->mr));
return section;
}
#endif
@@ -735,6 +738,20 @@ void cpu_exec_unrealizefn(CPUState *cpu)
}
}
+Property cpu_common_props[] = {
+#ifndef CONFIG_USER_ONLY
+ /* Create a memory property for softmmu CPU object,
+ * so users can wire up its memory. (This can't go in qom/cpu.c
+ * because that file is compiled only once for both user-mode
+ * and system builds.) The default if no link is set up is to use
+ * the system address space.
+ */
+ DEFINE_PROP_LINK("memory", CPUState, memory, TYPE_MEMORY_REGION,
+ MemoryRegion *),
+#endif
+ DEFINE_PROP_END_OF_LIST(),
+};
+
void cpu_exec_initfn(CPUState *cpu)
{
cpu->as = NULL;
@@ -742,18 +759,6 @@ void cpu_exec_initfn(CPUState *cpu)
#ifndef CONFIG_USER_ONLY
cpu->thread_id = qemu_get_thread_id();
-
- /* This is a softmmu CPU object, so create a property for it
- * so users can wire up its memory. (This can't go in qom/cpu.c
- * because that file is compiled only once for both user-mode
- * and system builds.) The default if no link is set up is to use
- * the system address space.
- */
- object_property_add_link(OBJECT(cpu), "memory", TYPE_MEMORY_REGION,
- (Object **)&cpu->memory,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
cpu->memory = system_memory;
object_ref(OBJECT(cpu->memory));
#endif
@@ -775,15 +780,28 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp)
#endif
}
+#if defined(CONFIG_USER_ONLY)
static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{
- /* Flush the whole TB as this will not have race conditions
- * even if we don't have proper locking yet.
- * Ideally we would just invalidate the TBs for the
- * specified PC.
- */
- tb_flush(cpu);
+ mmap_lock();
+ tb_lock();
+ tb_invalidate_phys_page_range(pc, pc + 1, 0);
+ tb_unlock();
+ mmap_unlock();
}
+#else
+static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
+{
+ MemTxAttrs attrs;
+ hwaddr phys = cpu_get_phys_page_attrs_debug(cpu, pc, &attrs);
+ int asidx = cpu_asidx_from_attrs(cpu, attrs);
+ if (phys != -1) {
+ /* Locks grabbed by tb_invalidate_phys_addr */
+ tb_invalidate_phys_addr(cpu->cpu_ases[asidx].as,
+ phys | (pc & ~TARGET_PAGE_MASK));
+ }
+}
+#endif
#if defined(CONFIG_USER_ONLY)
void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
@@ -2929,7 +2947,7 @@ static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr,
}
} else {
/* RAM case */
- ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
+ ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l);
memcpy(ptr, buf, l);
invalidate_and_set_dirty(mr, addr1, l);
}
@@ -3020,7 +3038,7 @@ MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
}
} else {
/* RAM case */
- ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
+ ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l);
memcpy(buf, ptr, l);
}
diff --git a/gdb-xml/s390-gs.xml b/gdb-xml/s390-gs.xml
new file mode 100644
index 0000000000..0487d31c07
--- /dev/null
+++ b/gdb-xml/s390-gs.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!-- Copyright 2017 IBM Corp.
+
+ This work is licensed under the terms of the GNU GPL, version 2 or
+ (at your option) any later version. See the COPYING file in the
+ top-level directory. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.s390.gs">
+ <reg name="gs_reserved" bitsize="64" type="uint64" group="system"/>
+ <reg name="gsd" bitsize="64" type="uint64" group="system"/>
+ <reg name="gssm" bitsize="64" type="uint64" group="system"/>
+ <reg name="gsepla" bitsize="64" type="data_ptr" group="system"/>
+</feature>
diff --git a/gdbstub.c b/gdbstub.c
index ec4e4b25be..f936ddd32d 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -56,6 +56,21 @@ static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
}
+/* Return the GDB index for a given vCPU state.
+ *
+ * For user mode this is simply the thread id. In system mode GDB
+ * numbers CPUs from 1 as 0 is reserved as an "any cpu" index.
+ */
+static inline int cpu_gdb_index(CPUState *cpu)
+{
+#if defined(CONFIG_USER_ONLY)
+ TaskState *ts = (TaskState *) cpu->opaque;
+ return ts->ts_tid;
+#else
+ return cpu->cpu_index + 1;
+#endif
+}
+
enum {
GDB_SIGNAL_0 = 0,
GDB_SIGNAL_INT = 2,
@@ -272,7 +287,20 @@ static int gdb_signal_to_target (int sig)
return -1;
}
-//#define DEBUG_GDB
+/* #define DEBUG_GDB */
+
+#ifdef DEBUG_GDB
+# define DEBUG_GDB_GATE 1
+#else
+# define DEBUG_GDB_GATE 0
+#endif
+
+#define gdb_debug(fmt, ...) do { \
+ if (DEBUG_GDB_GATE) { \
+ fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); \
+ } \
+} while (0)
+
typedef struct GDBRegisterState {
int base_reg;
@@ -548,9 +576,7 @@ static int put_packet_binary(GDBState *s, const char *buf, int len)
/* return -1 if error, 0 if OK */
static int put_packet(GDBState *s, const char *buf)
{
-#ifdef DEBUG_GDB
- printf("reply='%s'\n", buf);
-#endif
+ gdb_debug("reply='%s'\n", buf);
return put_packet_binary(s, buf, strlen(buf));
}
@@ -827,7 +853,7 @@ static CPUState *find_cpu(uint32_t thread_id)
CPUState *cpu;
CPU_FOREACH(cpu) {
- if (cpu_index(cpu) == thread_id) {
+ if (cpu_gdb_index(cpu) == thread_id) {
return cpu;
}
}
@@ -912,23 +938,16 @@ static int gdb_handle_vcont(GDBState *s, const char *p)
if (res) {
goto out;
}
- idx = tmp;
+
/* 0 means any thread, so we pick the first valid CPU */
- if (!idx) {
- idx = cpu_index(first_cpu);
- }
+ cpu = tmp ? find_cpu(tmp) : first_cpu;
- /*
- * If we are in user mode, the thread specified is actually a
- * thread id, and not an index. We need to find the actual
- * CPU first, and only then we can use its index.
- */
- cpu = find_cpu(idx);
/* invalid CPU/thread specified */
- if (!idx || !cpu) {
+ if (!cpu) {
res = -EINVAL;
goto out;
}
+
/* only use if no previous match occourred */
if (newstates[cpu->cpu_index] == 1) {
newstates[cpu->cpu_index] = cur_action;
@@ -956,16 +975,16 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
uint8_t *registers;
target_ulong addr, len;
-#ifdef DEBUG_GDB
- printf("command='%s'\n", line_buf);
-#endif
+
+ gdb_debug("command='%s'\n", line_buf);
+
p = line_buf;
ch = *p++;
switch(ch) {
case '?':
/* TODO: Make this return the correct value for user-mode. */
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
- cpu_index(s->c_cpu));
+ cpu_gdb_index(s->c_cpu));
put_packet(s, buf);
/* Remove all the breakpoints when this query is issued,
* because gdb is doing and initial connect and the state
@@ -1233,7 +1252,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
} else if (strcmp(p,"sThreadInfo") == 0) {
report_cpuinfo:
if (s->query_cpu) {
- snprintf(buf, sizeof(buf), "m%x", cpu_index(s->query_cpu));
+ snprintf(buf, sizeof(buf), "m%x", cpu_gdb_index(s->query_cpu));
put_packet(s, buf);
s->query_cpu = CPU_NEXT(s->query_cpu);
} else
@@ -1390,7 +1409,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
}
snprintf(buf, sizeof(buf),
"T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
- GDB_SIGNAL_TRAP, cpu_index(cpu), type,
+ GDB_SIGNAL_TRAP, cpu_gdb_index(cpu), type,
(target_ulong)cpu->watchpoint_hit->vaddr);
cpu->watchpoint_hit = NULL;
goto send_packet;
@@ -1424,7 +1443,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
break;
}
gdb_set_stop_cpu(cpu);
- snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_index(cpu));
+ snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_gdb_index(cpu));
send_packet:
put_packet(s, buf);
@@ -1519,17 +1538,14 @@ static void gdb_read_byte(GDBState *s, int ch)
/* Waiting for a response to the last packet. If we see the start
of a new command then abandon the previous response. */
if (ch == '-') {
-#ifdef DEBUG_GDB
- printf("Got NACK, retransmitting\n");
-#endif
+ gdb_debug("Got NACK, retransmitting\n");
put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len);
+ } else if (ch == '+') {
+ gdb_debug("Got ACK\n");
+ } else {
+ gdb_debug("Got '%c' when expecting ACK/NACK\n", ch);
}
-#ifdef DEBUG_GDB
- else if (ch == '+')
- printf("Got ACK\n");
- else
- printf("Got '%c' when expecting ACK/NACK\n", ch);
-#endif
+
if (ch == '+' || ch == '$')
s->last_packet_len = 0;
if (ch != '$')
@@ -1550,9 +1566,7 @@ static void gdb_read_byte(GDBState *s, int ch)
s->line_sum = 0;
s->state = RS_GETLINE;
} else {
-#ifdef DEBUG_GDB
- printf("gdbstub received garbage between packets: 0x%x\n", ch);
-#endif
+ gdb_debug("received garbage between packets: 0x%x\n", ch);
}
break;
case RS_GETLINE:
@@ -1568,9 +1582,7 @@ static void gdb_read_byte(GDBState *s, int ch)
/* end of command, start of checksum*/
s->state = RS_CHKSUM1;
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
-#ifdef DEBUG_GDB
- printf("gdbstub command buffer overrun, dropping command\n");
-#endif
+ gdb_debug("command buffer overrun, dropping command\n");
s->state = RS_IDLE;
} else {
/* unescaped command character */
@@ -1584,9 +1596,7 @@ static void gdb_read_byte(GDBState *s, int ch)
s->state = RS_CHKSUM1;
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
/* command buffer overrun */
-#ifdef DEBUG_GDB
- printf("gdbstub command buffer overrun, dropping command\n");
-#endif
+ gdb_debug("command buffer overrun, dropping command\n");
s->state = RS_IDLE;
} else {
/* parse escaped character and leave escape state */
@@ -1598,25 +1608,18 @@ static void gdb_read_byte(GDBState *s, int ch)
case RS_GETLINE_RLE:
if (ch < ' ') {
/* invalid RLE count encoding */
-#ifdef DEBUG_GDB
- printf("gdbstub got invalid RLE count: 0x%x\n", ch);
-#endif
+ gdb_debug("got invalid RLE count: 0x%x\n", ch);
s->state = RS_GETLINE;
} else {
/* decode repeat length */
int repeat = (unsigned char)ch - ' ' + 3;
if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) {
/* that many repeats would overrun the command buffer */
-#ifdef DEBUG_GDB
- printf("gdbstub command buffer overrun,"
- " dropping command\n");
-#endif
+ gdb_debug("command buffer overrun, dropping command\n");
s->state = RS_IDLE;
} else if (s->line_buf_index < 1) {
/* got a repeat but we have nothing to repeat */
-#ifdef DEBUG_GDB
- printf("gdbstub got invalid RLE sequence\n");
-#endif
+ gdb_debug("got invalid RLE sequence\n");
s->state = RS_GETLINE;
} else {
/* repeat the last character */
@@ -1631,9 +1634,7 @@ static void gdb_read_byte(GDBState *s, int ch)
case RS_CHKSUM1:
/* get high hex digit of checksum */
if (!isxdigit(ch)) {
-#ifdef DEBUG_GDB
- printf("gdbstub got invalid command checksum digit\n");
-#endif
+ gdb_debug("got invalid command checksum digit\n");
s->state = RS_GETLINE;
break;
}
@@ -1644,21 +1645,17 @@ static void gdb_read_byte(GDBState *s, int ch)
case RS_CHKSUM2:
/* get low hex digit of checksum */
if (!isxdigit(ch)) {
-#ifdef DEBUG_GDB
- printf("gdbstub got invalid command checksum digit\n");
-#endif
+ gdb_debug("got invalid command checksum digit\n");
s->state = RS_GETLINE;
break;
}
s->line_csum |= fromhex(ch);
if (s->line_csum != (s->line_sum & 0xff)) {
+ gdb_debug("got command packet with incorrect checksum\n");
/* send NAK reply */
reply = '-';
put_buffer(s, &reply, 1);
-#ifdef DEBUG_GDB
- printf("gdbstub got command packet with incorrect checksum\n");
-#endif
s->state = RS_IDLE;
} else {
/* send ACK reply */
@@ -2003,7 +2000,7 @@ int gdbserver_start(const char *device)
if (chr) {
qemu_chr_fe_init(&s->chr, chr, &error_abort);
qemu_chr_fe_set_handlers(&s->chr, gdb_chr_can_receive, gdb_chr_receive,
- gdb_chr_event, NULL, NULL, true);
+ gdb_chr_event, NULL, NULL, NULL, true);
}
s->state = chr ? RS_IDLE : RS_INACTIVE;
s->mon_chr = mon_chr;
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 07500ef787..d9df238a5f 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -777,6 +777,22 @@ STEXI
Display the value of a storage key (s390 only)
ETEXI
+#if defined(TARGET_S390X)
+ {
+ .name = "cmma",
+ .args_type = "addr:l,count:l?",
+ .params = "address [count]",
+ .help = "Display the values of the CMMA storage attributes for a range of pages",
+ .cmd = hmp_info_cmma,
+ },
+#endif
+
+STEXI
+@item info cmma @var{address}
+@findex cmma
+Display the values of the CMMA storage attributes for a range of pages (s390 only)
+ETEXI
+
{
.name = "dump",
.args_type = "",
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 275ccdfbc7..1941e19932 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1153,6 +1153,22 @@ STEXI
Save guest storage keys to a file.
ETEXI
+#if defined(TARGET_S390X)
+ {
+ .name = "migration_mode",
+ .args_type = "mode:i",
+ .params = "mode",
+ .help = "Enables or disables migration mode\n",
+ .cmd = hmp_migrationmode,
+ },
+#endif
+
+STEXI
+@item migration_mode @var{mode}
+@findex migration_mode
+Enables or disables migration mode.
+ETEXI
+
{
.name = "snapshot_blkdev",
.args_type = "reuse:-n,device:B,snapshot-file:s?,format:s?",
@@ -1646,6 +1662,8 @@ STEXI
@item block_passwd @var{device} @var{password}
@findex block_passwd
Set the encrypted device @var{device} password to @var{password}
+
+This command is now obsolete and will always return an error since 2.10
ETEXI
{
@@ -1724,7 +1742,23 @@ ETEXI
STEXI
@item chardev-add args
@findex chardev-add
-chardev_add accepts the same parameters as the -chardev command line switch.
+chardev-add accepts the same parameters as the -chardev command line switch.
+
+ETEXI
+
+ {
+ .name = "chardev-change",
+ .args_type = "id:s,args:s",
+ .params = "id args",
+ .help = "change chardev",
+ .cmd = hmp_chardev_change,
+ },
+
+STEXI
+@item chardev-change args
+@findex chardev-change
+chardev-change accepts existing chardev @var{id} and then the same arguments
+as the -chardev command line switch (except for "id").
ETEXI
diff --git a/hmp.c b/hmp.c
index 3e1e766593..b42ae59a29 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1130,37 +1130,12 @@ void hmp_ringbuf_read(Monitor *mon, const QDict *qdict)
g_free(data);
}
-static void hmp_cont_cb(void *opaque, int err)
-{
- if (!err) {
- qmp_cont(NULL);
- }
-}
-
-static bool key_is_missing(const BlockInfo *bdev)
-{
- return (bdev->inserted && bdev->inserted->encryption_key_missing);
-}
-
void hmp_cont(Monitor *mon, const QDict *qdict)
{
- BlockInfoList *bdev_list, *bdev;
Error *err = NULL;
- bdev_list = qmp_query_block(NULL);
- for (bdev = bdev_list; bdev; bdev = bdev->next) {
- if (key_is_missing(bdev->value)) {
- monitor_read_block_device_key(mon, bdev->value->device,
- hmp_cont_cb, NULL);
- goto out;
- }
- }
-
qmp_cont(&err);
hmp_handle_error(mon, &err);
-
-out:
- qapi_free_BlockInfoList(bdev_list);
}
void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
@@ -1783,12 +1758,6 @@ void hmp_change(Monitor *mon, const QDict *qdict)
qmp_blockdev_change_medium(true, device, false, NULL, target,
!!arg, arg, !!read_only, read_only_mode,
&err);
- if (err &&
- error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
- error_free(err);
- monitor_read_block_device_key(mon, device, NULL, NULL);
- return;
- }
}
hmp_handle_error(mon, &err);
@@ -2270,6 +2239,40 @@ void hmp_chardev_add(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, &err);
}
+void hmp_chardev_change(Monitor *mon, const QDict *qdict)
+{
+ const char *args = qdict_get_str(qdict, "args");
+ const char *id;
+ Error *err = NULL;
+ ChardevBackend *backend = NULL;
+ ChardevReturn *ret = NULL;
+ QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), args,
+ true);
+ if (!opts) {
+ error_setg(&err, "Parsing chardev args failed");
+ goto end;
+ }
+
+ id = qdict_get_str(qdict, "id");
+ if (qemu_opts_id(opts)) {
+ error_setg(&err, "Unexpected 'id' parameter");
+ goto end;
+ }
+
+ backend = qemu_chr_parse_opts(opts, &err);
+ if (!backend) {
+ goto end;
+ }
+
+ ret = qmp_chardev_change(id, backend, &err);
+
+end:
+ qapi_free_ChardevReturn(ret);
+ qapi_free_ChardevBackend(backend);
+ qemu_opts_del(opts);
+ hmp_handle_error(mon, &err);
+}
+
void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
{
Error *local_err = NULL;
diff --git a/hmp.h b/hmp.h
index 214b2617e7..1ff455295e 100644
--- a/hmp.h
+++ b/hmp.h
@@ -102,6 +102,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
void hmp_chardev_add(Monitor *mon, const QDict *qdict);
+void hmp_chardev_change(Monitor *mon, const QDict *qdict);
void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
void hmp_chardev_send_break(Monitor *mon, const QDict *qdict);
void hmp_qemu_io(Monitor *mon, const QDict *qdict);
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 6c92bad5b3..333dbb6f8e 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -2376,7 +2376,7 @@ static void coroutine_fn v9fs_flush(void *opaque)
trace_v9fs_flush(pdu->tag, pdu->id, tag);
if (pdu->tag == tag) {
- error_report("Warning: the guest sent a self-referencing 9P flush request");
+ warn_report("the guest sent a self-referencing 9P flush request");
} else {
QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
if (cancel_pdu->tag == tag) {
diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c
index c1cf7802a4..ae11e012c7 100644
--- a/hw/alpha/typhoon.c
+++ b/hw/alpha/typhoon.c
@@ -17,6 +17,7 @@
#define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
+#define TYPE_TYPHOON_IOMMU_MEMORY_REGION "typhoon-iommu-memory-region"
typedef struct TyphoonCchip {
MemoryRegion region;
@@ -41,7 +42,7 @@ typedef struct TyphoonPchip {
MemoryRegion reg_conf;
AddressSpace iommu_as;
- MemoryRegion iommu;
+ IOMMUMemoryRegion iommu;
uint64_t ctl;
TyphoonWindow win[4];
@@ -663,7 +664,8 @@ static bool window_translate(TyphoonWindow *win, hwaddr addr,
/* Handle PCI-to-system address translation. */
/* TODO: A translation failure here ought to set PCI error codes on the
Pchip and generate a machine check interrupt. */
-static IOMMUTLBEntry typhoon_translate_iommu(MemoryRegion *iommu, hwaddr addr,
+static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
+ hwaddr addr,
IOMMUAccessFlags flag)
{
TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
@@ -724,10 +726,6 @@ static IOMMUTLBEntry typhoon_translate_iommu(MemoryRegion *iommu, hwaddr addr,
return ret;
}
-static const MemoryRegionIOMMUOps typhoon_iommu_ops = {
- .translate = typhoon_translate_iommu,
-};
-
static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
{
TyphoonState *s = opaque;
@@ -891,9 +889,11 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
qdev_init_nofail(dev);
/* Host memory as seen from the PCI side, via the IOMMU. */
- memory_region_init_iommu(&s->pchip.iommu, OBJECT(s), &typhoon_iommu_ops,
+ memory_region_init_iommu(&s->pchip.iommu, sizeof(s->pchip.iommu),
+ TYPE_TYPHOON_IOMMU_MEMORY_REGION, OBJECT(s),
"iommu-typhoon", UINT64_MAX);
- address_space_init(&s->pchip.iommu_as, &s->pchip.iommu, "pchip0-pci");
+ address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu),
+ "pchip0-pci");
pci_setup_iommu(b, typhoon_pci_dma_iommu, s);
/* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */
@@ -951,9 +951,24 @@ static const TypeInfo typhoon_pcihost_info = {
.class_init = typhoon_pcihost_class_init,
};
+static void typhoon_iommu_memory_region_class_init(ObjectClass *klass,
+ void *data)
+{
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
+
+ imrc->translate = typhoon_translate_iommu;
+}
+
+static const TypeInfo typhoon_iommu_memory_region_info = {
+ .parent = TYPE_IOMMU_MEMORY_REGION,
+ .name = TYPE_TYPHOON_IOMMU_MEMORY_REGION,
+ .class_init = typhoon_iommu_memory_region_class_init,
+};
+
static void typhoon_register_types(void)
{
type_register_static(&typhoon_pcihost_info);
+ type_register_static(&typhoon_iommu_memory_region_info);
}
type_init(typhoon_register_types)
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index db3f6d20c6..0c5635f300 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -216,7 +216,7 @@ static void aspeed_board_init(MachineState *machine,
* SoC and 128MB for the AST2500 SoC, which is twice as big as
* needed by the flash modules of the Aspeed machines.
*/
- memory_region_init_rom(boot_rom, OBJECT(bmc), "aspeed.boot_rom",
+ memory_region_init_rom_nomigrate(boot_rom, OBJECT(bmc), "aspeed.boot_rom",
fl->size, &error_abort);
memory_region_add_subregion(get_system_memory(), FIRMWARE_ADDR,
boot_rom);
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
index 3034849c80..5529024edf 100644
--- a/hw/arm/aspeed_soc.c
+++ b/hw/arm/aspeed_soc.c
@@ -211,7 +211,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
}
/* SRAM */
- memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram",
+ memory_region_init_ram_nomigrate(&s->sram, OBJECT(dev), "aspeed.sram",
sc->info->sram_size, &err);
if (err) {
error_propagate(errp, err);
diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index ee851e3ae5..f9e79f3ebb 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -281,7 +281,6 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem)
/* Internal ROM */
memory_region_init_ram(&s->irom_mem, NULL, "exynos4210.irom",
EXYNOS4210_IROM_SIZE, &error_fatal);
- vmstate_register_ram_global(&s->irom_mem);
memory_region_set_readonly(&s->irom_mem, true);
memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR,
&s->irom_mem);
@@ -297,7 +296,6 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem)
/* Internal RAM */
memory_region_init_ram(&s->iram_mem, NULL, "exynos4210.iram",
EXYNOS4210_IRAM_SIZE, &error_fatal);
- vmstate_register_ram_global(&s->iram_mem);
memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR,
&s->iram_mem);
diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c
index 6240b26839..7c03ed32b7 100644
--- a/hw/arm/exynos4_boards.c
+++ b/hw/arm/exynos4_boards.c
@@ -113,7 +113,6 @@ static void exynos4_boards_init_ram(Exynos4BoardState *s,
memory_region_init_ram(&s->dram1_mem, NULL, "exynos4210.dram1",
mem_size - EXYNOS4210_DRAM_MAX_SIZE,
&error_fatal);
- vmstate_register_ram_global(&s->dram1_mem);
memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR,
&s->dram1_mem);
mem_size = EXYNOS4210_DRAM_MAX_SIZE;
@@ -121,7 +120,6 @@ static void exynos4_boards_init_ram(Exynos4BoardState *s,
memory_region_init_ram(&s->dram0_mem, NULL, "exynos4210.dram0", mem_size,
&error_fatal);
- vmstate_register_ram_global(&s->dram0_mem);
memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR,
&s->dram0_mem);
}
diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
index 40666b68a3..8cff3c1f7b 100644
--- a/hw/arm/fsl-imx25.c
+++ b/hw/arm/fsl-imx25.c
@@ -249,7 +249,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
}
/* initialize 2 x 16 KB ROM */
- memory_region_init_rom(&s->rom[0], NULL,
+ memory_region_init_rom_nomigrate(&s->rom[0], NULL,
"imx25.rom0", FSL_IMX25_ROM0_SIZE, &err);
if (err) {
error_propagate(errp, err);
@@ -257,7 +257,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
}
memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR,
&s->rom[0]);
- memory_region_init_rom(&s->rom[1], NULL,
+ memory_region_init_rom_nomigrate(&s->rom[1], NULL,
"imx25.rom1", FSL_IMX25_ROM1_SIZE, &err);
if (err) {
error_propagate(errp, err);
@@ -275,7 +275,6 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
}
memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ADDR,
&s->iram);
- vmstate_register_ram_global(&s->iram);
/* internal RAM (128 KB) is aliased over 128 MB - 128 KB */
memory_region_init_alias(&s->iram_alias, NULL, "imx25.iram_alias",
diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c
index c30130667e..90278758f9 100644
--- a/hw/arm/fsl-imx31.c
+++ b/hw/arm/fsl-imx31.c
@@ -219,7 +219,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
}
/* On a real system, the first 16k is a `secure boot rom' */
- memory_region_init_rom(&s->secure_rom, NULL, "imx31.secure_rom",
+ memory_region_init_rom_nomigrate(&s->secure_rom, NULL, "imx31.secure_rom",
FSL_IMX31_SECURE_ROM_SIZE, &err);
if (err) {
error_propagate(errp, err);
@@ -229,7 +229,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
&s->secure_rom);
/* There is also a 16k ROM */
- memory_region_init_rom(&s->rom, NULL, "imx31.rom",
+ memory_region_init_rom_nomigrate(&s->rom, NULL, "imx31.rom",
FSL_IMX31_ROM_SIZE, &err);
if (err) {
error_propagate(errp, err);
@@ -247,7 +247,6 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
}
memory_region_add_subregion(get_system_memory(), FSL_IMX31_IRAM_ADDR,
&s->iram);
- vmstate_register_ram_global(&s->iram);
/* internal RAM (16 KB) is aliased over 256 MB - 16 KB */
memory_region_init_alias(&s->iram_alias, NULL, "imx31.iram_alias",
diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c
index 27773c9c47..576c6631a1 100644
--- a/hw/arm/fsl-imx6.c
+++ b/hw/arm/fsl-imx6.c
@@ -399,7 +399,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
FSL_IMX6_ENET_MAC_1588_IRQ));
/* ROM memory */
- memory_region_init_rom(&s->rom, NULL, "imx6.rom",
+ memory_region_init_rom_nomigrate(&s->rom, NULL, "imx6.rom",
FSL_IMX6_ROM_SIZE, &err);
if (err) {
error_propagate(errp, err);
@@ -409,7 +409,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
&s->rom);
/* CAAM memory */
- memory_region_init_rom(&s->caam, NULL, "imx6.caam",
+ memory_region_init_rom_nomigrate(&s->caam, NULL, "imx6.caam",
FSL_IMX6_CAAM_MEM_SIZE, &err);
if (err) {
error_propagate(errp, err);
@@ -427,7 +427,6 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
}
memory_region_add_subregion(get_system_memory(), FSL_IMX6_OCRAM_ADDR,
&s->ocram);
- vmstate_register_ram_global(&s->ocram);
/* internal OCRAM (256 KB) is aliased over 1 MB */
memory_region_init_alias(&s->ocram_alias, NULL, "imx6.ocram_alias",
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index d209b97dee..20e60f15c4 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -276,7 +276,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
memory_region_add_subregion(sysmem, 0, dram);
sysram = g_new(MemoryRegion, 1);
- memory_region_init_ram(sysram, NULL, "highbank.sysram", 0x8000,
+ memory_region_init_ram_nomigrate(sysram, NULL, "highbank.sysram", 0x8000,
&error_fatal);
memory_region_add_subregion(sysmem, 0xfff88000, sysram);
if (bios_name != NULL) {
@@ -383,9 +383,9 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
highbank_binfo.write_board_setup = hb_write_board_setup;
highbank_binfo.secure_board_setup = true;
} else {
- error_report("WARNING: cannot load built-in Monitor support "
- "if KVM is enabled. Some guests (such as Linux) "
- "may not boot.");
+ warn_report("cannot load built-in Monitor support "
+ "if KVM is enabled. Some guests (such as Linux) "
+ "may not boot.");
}
arm_load_kernel(ARM_CPU(first_cpu), &highbank_binfo);
diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c
index 44e741fde3..7d42c74001 100644
--- a/hw/arm/imx25_pdk.c
+++ b/hw/arm/imx25_pdk.c
@@ -80,9 +80,9 @@ static void imx25_pdk_init(MachineState *machine)
/* We need to initialize our memory */
if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) {
- error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, "
- "reduced to %x", machine->ram_size,
- FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE);
+ warn_report("RAM size " RAM_ADDR_FMT " above max supported, "
+ "reduced to %x", machine->ram_size,
+ FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE);
machine->ram_size = FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE;
}
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
index ca3eca1d16..d79221d166 100644
--- a/hw/arm/integratorcp.c
+++ b/hw/arm/integratorcp.c
@@ -276,7 +276,7 @@ static void integratorcm_init(Object *obj)
s->cm_init = 0x00000112;
s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
1000);
- memory_region_init_ram(&s->flash, obj, "integrator.flash", 0x100000,
+ memory_region_init_ram_nomigrate(&s->flash, obj, "integrator.flash", 0x100000,
&error_fatal);
vmstate_register_ram_global(&s->flash);
diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c
index 2c96ee33b6..3ed6577a55 100644
--- a/hw/arm/kzm.c
+++ b/hw/arm/kzm.c
@@ -79,9 +79,9 @@ static void kzm_init(MachineState *machine)
/* Check the amount of memory is compatible with the SOC */
if (machine->ram_size > (FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE)) {
- error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, "
- "reduced to %x", machine->ram_size,
- FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE);
+ warn_report("RAM size " RAM_ADDR_FMT " above max supported, "
+ "reduced to %x", machine->ram_size,
+ FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE);
machine->ram_size = FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE;
}
diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c
index f962236cf4..fb268e691e 100644
--- a/hw/arm/mainstone.c
+++ b/hw/arm/mainstone.c
@@ -130,7 +130,6 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
mpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model);
memory_region_init_ram(rom, NULL, "mainstone.rom", MAINSTONE_ROM,
&error_fatal);
- vmstate_register_ram_global(rom);
memory_region_set_readonly(rom, true);
memory_region_add_subregion(address_space_mem, 0, rom);
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 9c710f74b4..7e8ab3184c 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -1606,7 +1606,6 @@ static void musicpal_init(MachineState *machine)
memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE,
&error_fatal);
- vmstate_register_ram_global(sram);
memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram);
dev = sysbus_create_simple(TYPE_MV88W8618_PIC, MP_PIC_BASE,
diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c
index 54582bd148..3d15ff6779 100644
--- a/hw/arm/omap1.c
+++ b/hw/arm/omap1.c
@@ -3882,7 +3882,6 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram);
memory_region_init_ram(&s->imif_ram, NULL, "omap1.sram", s->sram_size,
&error_fatal);
- vmstate_register_ram_global(&s->imif_ram);
memory_region_add_subregion(system_memory, OMAP_IMIF_BASE, &s->imif_ram);
omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s);
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c
index 91f573338c..bbf0b7e188 100644
--- a/hw/arm/omap2.c
+++ b/hw/arm/omap2.c
@@ -2280,7 +2280,6 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
memory_region_add_subregion(sysmem, OMAP2_Q2_BASE, &s->sdram);
memory_region_init_ram(&s->sram, NULL, "omap2.sram", s->sram_size,
&error_fatal);
- vmstate_register_ram_global(&s->sram);
memory_region_add_subregion(sysmem, OMAP2_SRAM_BASE, &s->sram);
s->l4 = omap_l4_init(sysmem, OMAP2_L4_BASE, 54);
diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c
index 5d74026cb2..9809106617 100644
--- a/hw/arm/omap_sx1.c
+++ b/hw/arm/omap_sx1.c
@@ -125,7 +125,6 @@ static void sx1_init(MachineState *machine, const int version)
/* External Flash (EMIFS) */
memory_region_init_ram(flash, NULL, "omap_sx1.flash0-0", flash_size,
&error_fatal);
- vmstate_register_ram_global(flash);
memory_region_set_readonly(flash, true);
memory_region_add_subregion(address_space, OMAP_CS0_BASE, flash);
@@ -167,9 +166,8 @@ static void sx1_init(MachineState *machine, const int version)
if ((version == 1) &&
(dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
MemoryRegion *flash_1 = g_new(MemoryRegion, 1);
- memory_region_init_ram(flash_1, NULL, "omap_sx1.flash1-0", flash1_size,
- &error_fatal);
- vmstate_register_ram_global(flash_1);
+ memory_region_init_ram(flash_1, NULL, "omap_sx1.flash1-0",
+ flash1_size, &error_fatal);
memory_region_set_readonly(flash_1, true);
memory_region_add_subregion(address_space, OMAP_CS1_BASE, flash_1);
diff --git a/hw/arm/palm.c b/hw/arm/palm.c
index 7f460732e3..64cf8ca921 100644
--- a/hw/arm/palm.c
+++ b/hw/arm/palm.c
@@ -216,7 +216,6 @@ static void palmte_init(MachineState *machine)
/* External Flash (EMIFS) */
memory_region_init_ram(flash, NULL, "palmte.flash", flash_size,
&error_fatal);
- vmstate_register_ram_global(flash);
memory_region_set_readonly(flash, true);
memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash);
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 629e6c64e6..194b0bc808 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1970,7 +1970,8 @@ static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
PXA2xxFIrState *s = PXA2XX_FIR(dev);
qemu_chr_fe_set_handlers(&s->chr, pxa2xx_fir_is_empty,
- pxa2xx_fir_rx, pxa2xx_fir_event, s, NULL, true);
+ pxa2xx_fir_rx, pxa2xx_fir_event, NULL, s, NULL,
+ true);
}
static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id)
@@ -2075,11 +2076,9 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space,
/* SDRAM & Internal Memory Storage */
memory_region_init_ram(&s->sdram, NULL, "pxa270.sdram", sdram_size,
&error_fatal);
- vmstate_register_ram_global(&s->sdram);
memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
memory_region_init_ram(&s->internal, NULL, "pxa270.internal", 0x40000,
&error_fatal);
- vmstate_register_ram_global(&s->internal);
memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
&s->internal);
@@ -2207,11 +2206,9 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
/* SDRAM & Internal Memory Storage */
memory_region_init_ram(&s->sdram, NULL, "pxa255.sdram", sdram_size,
&error_fatal);
- vmstate_register_ram_global(&s->sdram);
memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
memory_region_init_ram(&s->internal, NULL, "pxa255.internal",
PXA2XX_INTERNAL_SIZE, &error_fatal);
- vmstate_register_ram_global(&s->internal);
memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
&s->internal);
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
index b7d4753400..76ff5579bc 100644
--- a/hw/arm/realview.c
+++ b/hw/arm/realview.c
@@ -145,13 +145,11 @@ static void realview_init(MachineState *machine,
ram_size = 0x20000000;
memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size,
&error_fatal);
- vmstate_register_ram_global(ram_lo);
memory_region_add_subregion(sysmem, 0x20000000, ram_lo);
}
memory_region_init_ram(ram_hi, NULL, "realview.highmem", ram_size,
&error_fatal);
- vmstate_register_ram_global(ram_hi);
low_ram_size = ram_size;
if (low_ram_size > 0x10000000)
low_ram_size = 0x10000000;
@@ -347,7 +345,6 @@ static void realview_init(MachineState *machine,
until after Linux boots the secondary CPUs. */
memory_region_init_ram(ram_hack, NULL, "realview.hack", 0x1000,
&error_fatal);
- vmstate_register_ram_global(ram_hack);
memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
realview_binfo.ram_size = ram_size;
diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c
index 93bde14743..7f588cea21 100644
--- a/hw/arm/spitz.c
+++ b/hw/arm/spitz.c
@@ -920,7 +920,6 @@ static void spitz_common_init(MachineState *machine,
sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
memory_region_init_ram(rom, NULL, "spitz.rom", SPITZ_ROM, &error_fatal);
- vmstate_register_ram_global(rom);
memory_region_set_readonly(rom, true);
memory_region_add_subregion(address_space_mem, 0, rom);
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index cf6e7be083..408c1a14d3 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -1290,13 +1290,11 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
/* Flash programming is done via the SCU, so pretend it is ROM. */
memory_region_init_ram(flash, NULL, "stellaris.flash", flash_size,
&error_fatal);
- vmstate_register_ram_global(flash);
memory_region_set_readonly(flash, true);
memory_region_add_subregion(system_memory, 0, flash);
memory_region_init_ram(sram, NULL, "stellaris.sram", sram_size,
&error_fatal);
- vmstate_register_ram_global(sram);
memory_region_add_subregion(system_memory, 0x20000000, sram);
nvic = armv7m_init(system_memory, flash_size, NUM_IRQ_LINES,
diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c
index 6e1260d2ed..f61e735f0f 100644
--- a/hw/arm/stm32f205_soc.c
+++ b/hw/arm/stm32f205_soc.c
@@ -100,8 +100,6 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
memory_region_init_alias(flash_alias, NULL, "STM32F205.flash.alias",
flash, 0, FLASH_SIZE);
- vmstate_register_ram_global(flash);
-
memory_region_set_readonly(flash, true);
memory_region_set_readonly(flash_alias, true);
@@ -110,7 +108,6 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
memory_region_init_ram(sram, NULL, "STM32F205.sram", SRAM_SIZE,
&error_fatal);
- vmstate_register_ram_global(sram);
memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram);
armv7m = DEVICE(&s->armv7m);
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index 7683edc9e5..6a45dcc009 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -1106,7 +1106,7 @@ static void strongarm_uart_tx(void *opaque)
if (s->utcr3 & UTCR3_LBM) /* loopback */ {
strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1);
- } else if (qemu_chr_fe_get_driver(&s->chr)) {
+ } else if (qemu_chr_fe_backend_connected(&s->chr)) {
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(&s->chr, &s->tx_fifo[s->tx_start], 1);
@@ -1247,7 +1247,7 @@ static void strongarm_uart_realize(DeviceState *dev, Error **errp)
strongarm_uart_can_receive,
strongarm_uart_receive,
strongarm_uart_event,
- s, NULL, true);
+ NULL, s, NULL, true);
}
static void strongarm_uart_reset(DeviceState *dev)
diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c
index 2421b8150d..8b757ff6a3 100644
--- a/hw/arm/tosa.c
+++ b/hw/arm/tosa.c
@@ -235,7 +235,6 @@ static void tosa_init(MachineState *machine)
mpu = pxa255_init(address_space_mem, tosa_binfo.ram_size);
memory_region_init_ram(rom, NULL, "tosa.rom", TOSA_ROM, &error_fatal);
- vmstate_register_ram_global(rom);
memory_region_set_readonly(rom, true);
memory_region_add_subregion(address_space_mem, 0, rom);
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index c6b1e674b4..528c65ddb6 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -392,7 +392,6 @@ static void a15_daughterboard_init(const VexpressMachineState *vms,
/* 0x2e000000: system SRAM */
memory_region_init_ram(sram, NULL, "vexpress.a15sram", 0x10000,
&error_fatal);
- vmstate_register_ram_global(sram);
memory_region_add_subregion(sysmem, 0x2e000000, sram);
/* 0x7ffb0000: DMA330 DMA controller: not modelled */
@@ -675,13 +674,11 @@ static void vexpress_common_init(MachineState *machine)
sram_size = 0x2000000;
memory_region_init_ram(sram, NULL, "vexpress.sram", sram_size,
&error_fatal);
- vmstate_register_ram_global(sram);
memory_region_add_subregion(sysmem, map[VE_SRAM], sram);
vram_size = 0x800000;
memory_region_init_ram(vram, NULL, "vexpress.vram", vram_size,
&error_fatal);
- vmstate_register_ram_global(vram);
memory_region_add_subregion(sysmem, map[VE_VIDEORAM], vram);
/* 0x4e000000 LAN9118 Ethernet */
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 010f7244bf..31739d75a3 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1155,8 +1155,8 @@ static void create_secure_ram(VirtMachineState *vms,
hwaddr base = vms->memmap[VIRT_SECURE_MEM].base;
hwaddr size = vms->memmap[VIRT_SECURE_MEM].size;
- memory_region_init_ram(secram, NULL, "virt.secure-ram", size, &error_fatal);
- vmstate_register_ram_global(secram);
+ memory_region_init_ram(secram, NULL, "virt.secure-ram", size,
+ &error_fatal);
memory_region_add_subregion(secure_sysmem, base, secram);
nodename = g_strdup_printf("/secram@%" PRIx64, base);
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 3985356fc2..6b11a75e67 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -206,7 +206,6 @@ static void zynq_init(MachineState *machine)
/* 256K of on-chip memory */
memory_region_init_ram(ocm_ram, NULL, "zynq.ocm_ram", 256 << 10,
&error_fatal);
- vmstate_register_ram_global(ocm_ram);
memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram);
DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 64f52f80a5..9eceadbdc8 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -228,7 +228,6 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
memory_region_init_ram(&s->ocm_ram[i], NULL, ocm_name,
XLNX_ZYNQMP_OCM_RAM_SIZE, &error_fatal);
- vmstate_register_ram_global(&s->ocm_ram[i]);
memory_region_add_subregion(get_system_memory(),
XLNX_ZYNQMP_OCM_RAM_0_ADDRESS +
i * XLNX_ZYNQMP_OCM_RAM_SIZE,
diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c
index c6e0f10c16..97b876c7e0 100644
--- a/hw/audio/adlib.c
+++ b/hw/audio/adlib.c
@@ -74,8 +74,6 @@ typedef struct {
PortioList port_list;
} AdlibState;
-static AdlibState *glob_adlib;
-
static void adlib_stop_opl_timer (AdlibState *s, size_t n)
{
OPLTimerOver (s->opl, n);
@@ -130,9 +128,9 @@ static uint32_t adlib_read(void *opaque, uint32_t nport)
return data;
}
-static void timer_handler (int c, double interval_Sec)
+static void timer_handler (void *opaque, int c, double interval_Sec)
{
- AdlibState *s = glob_adlib;
+ AdlibState *s = opaque;
unsigned n = c & 1;
#ifdef DEBUG
double interval;
@@ -259,19 +257,13 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
AdlibState *s = ADLIB(dev);
struct audsettings as;
- if (glob_adlib) {
- error_setg (errp, "Cannot create more than 1 adlib device");
- return;
- }
- glob_adlib = s;
-
s->opl = OPLCreate (3579545, s->freq);
if (!s->opl) {
error_setg (errp, "OPLCreate %d failed", s->freq);
return;
}
else {
- OPLSetTimerHandler (s->opl, timer_handler, 0);
+ OPLSetTimerHandler(s->opl, timer_handler, s);
s->enabled = 1;
}
diff --git a/hw/audio/fmopl.c b/hw/audio/fmopl.c
index 202f752c5d..5cfb6a96dd 100644
--- a/hw/audio/fmopl.c
+++ b/hw/audio/fmopl.c
@@ -788,14 +788,18 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
{
double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0;
OPL->st[1] = st2;
- if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval);
+ if (OPL->TimerHandler) {
+ (OPL->TimerHandler)(OPL->TimerParam, 1, interval);
+ }
}
/* timer 1 */
if(OPL->st[0] != st1)
{
double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0;
OPL->st[0] = st1;
- if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval);
+ if (OPL->TimerHandler) {
+ (OPL->TimerHandler)(OPL->TimerParam, 0, interval);
+ }
}
}
return;
@@ -1128,10 +1132,11 @@ void OPLDestroy(FM_OPL *OPL)
/* ---------- Option handlers ---------- */
-void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset)
+void OPLSetTimerHandler(FM_OPL *OPL, OPL_TIMERHANDLER TimerHandler,
+ void *param)
{
OPL->TimerHandler = TimerHandler;
- OPL->TimerParam = channelOffset;
+ OPL->TimerParam = param;
}
/* ---------- YM3812 I/O interface ---------- */
@@ -1197,6 +1202,9 @@ int OPLTimerOver(FM_OPL *OPL,int c)
}
}
/* reload timer */
- if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase);
+ if (OPL->TimerHandler) {
+ (OPL->TimerHandler)(OPL->TimerParam, c,
+ (double)OPL->T[c] * OPL->TimerBase);
+ }
return OPL->status>>7;
}
diff --git a/hw/audio/fmopl.h b/hw/audio/fmopl.h
index fc9f16b58a..f4065f425c 100644
--- a/hw/audio/fmopl.h
+++ b/hw/audio/fmopl.h
@@ -3,7 +3,7 @@
#include <stdint.h>
-typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
+typedef void (*OPL_TIMERHANDLER)(void *param, int channel, double interval_Sec);
/* !!!!! here is private section , do not access there member direct !!!!! */
@@ -87,13 +87,14 @@ typedef struct fm_opl_f {
uint8_t wavesel;
/* external event callback handler */
OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
- int TimerParam; /* TIMER parameter */
+ void *TimerParam; /* TIMER parameter */
} FM_OPL;
/* ---------- Generic interface section ---------- */
FM_OPL *OPLCreate(int clock, int rate);
void OPLDestroy(FM_OPL *OPL);
-void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
+void OPLSetTimerHandler(FM_OPL *OPL, OPL_TIMERHANDLER TimerHandler,
+ void *param);
int OPLWrite(FM_OPL *OPL,int a,int v);
unsigned char OPLRead(FM_OPL *OPL,int a);
diff --git a/hw/block/onenand.c b/hw/block/onenand.c
index ddf5492426..b7423607d9 100644
--- a/hw/block/onenand.c
+++ b/hw/block/onenand.c
@@ -807,7 +807,7 @@ static int onenand_initfn(SysBusDevice *sbd)
}
s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
0xff, (64 + 2) << PAGE_SHIFT);
- memory_region_init_ram(&s->ram, OBJECT(s), "onenand.ram",
+ memory_region_init_ram_nomigrate(&s->ram, OBJECT(s), "onenand.ram",
0xc000 << s->shift, &error_fatal);
vmstate_register_ram_global(&s->ram);
ram = memory_region_get_ram_ptr(&s->ram);
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 594d4cf6fe..1113ab1ccf 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -753,7 +753,6 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
return;
}
- vmstate_register_ram(&pfl->mem, DEVICE(pfl));
pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index e6c5c6c25d..c81ddd3a99 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -629,7 +629,6 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
return;
}
- vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
pfl->chip_len = chip_len;
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index c0bd247b37..b750bd8b53 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -983,10 +983,6 @@ static void virtio_blk_instance_init(Object *obj)
{
VirtIOBlock *s = VIRTIO_BLK(obj);
- object_property_add_link(obj, "iothread", TYPE_IOTHREAD,
- (Object **)&s->conf.iothread,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
device_add_bootindex_property(obj, &s->conf.conf.bootindex,
"bootindex", "/disk@0,0",
DEVICE(obj), NULL);
@@ -1014,6 +1010,8 @@ static Property virtio_blk_properties[] = {
DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
true),
DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1),
+ DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD,
+ IOThread *),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c
index 4d46ad60ae..370dc7e296 100644
--- a/hw/char/bcm2835_aux.c
+++ b/hw/char/bcm2835_aux.c
@@ -279,7 +279,7 @@ static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
BCM2835AuxState *s = BCM2835_AUX(dev);
qemu_chr_fe_set_handlers(&s->chr, bcm2835_aux_can_receive,
- bcm2835_aux_receive, NULL, s, NULL, true);
+ bcm2835_aux_receive, NULL, NULL, s, NULL, true);
}
static Property bcm2835_aux_props[] = {
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index 4a2c124104..6143494060 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -279,7 +279,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
int ret;
/* instant drain the fifo when there's no back-end */
- if (!qemu_chr_fe_get_driver(&s->chr)) {
+ if (!qemu_chr_fe_backend_connected(&s->chr)) {
s->tx_count = 0;
return FALSE;
}
@@ -485,7 +485,7 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp)
fifo_trigger_update, s);
qemu_chr_fe_set_handlers(&s->chr, uart_can_receive, uart_receive,
- uart_event, s, NULL, true);
+ uart_event, NULL, s, NULL, true);
}
static void cadence_uart_init(Object *obj)
diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c
index 762e3d8ada..95ccec6f8b 100644
--- a/hw/char/debugcon.c
+++ b/hw/char/debugcon.c
@@ -87,12 +87,12 @@ static const MemoryRegionOps debugcon_ops = {
static void debugcon_realize_core(DebugconState *s, Error **errp)
{
- if (!qemu_chr_fe_get_driver(&s->chr)) {
+ if (!qemu_chr_fe_backend_connected(&s->chr)) {
error_setg(errp, "Can't create debugcon device, empty char device");
return;
}
- qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, s, NULL, true);
+ qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL, s, NULL, true);
}
static void debugcon_isa_realizefn(DeviceState *dev, Error **errp)
diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c
index 34306e11ff..6ebcb87a40 100644
--- a/hw/char/digic-uart.c
+++ b/hw/char/digic-uart.c
@@ -146,7 +146,7 @@ static void digic_uart_realize(DeviceState *dev, Error **errp)
DigicUartState *s = DIGIC_UART(dev);
qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
- uart_event, s, NULL, true);
+ uart_event, NULL, s, NULL, true);
}
static void digic_uart_init(Object *obj)
diff --git a/hw/char/escc.c b/hw/char/escc.c
index 3f787632c7..89ae9eb997 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -417,7 +417,7 @@ static void escc_update_parameters(ChannelState *s)
int speed, parity, data_bits, stop_bits;
QEMUSerialSetParams ssp;
- if (!qemu_chr_fe_get_driver(&s->chr) || s->type != ser)
+ if (!qemu_chr_fe_backend_connected(&s->chr) || s->type != ser)
return;
if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
@@ -557,7 +557,7 @@ static void escc_mem_write(void *opaque, hwaddr addr,
trace_escc_mem_writeb_data(CHN_C(s), val);
s->tx = val;
if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
- if (qemu_chr_fe_get_driver(&s->chr)) {
+ if (qemu_chr_fe_backend_connected(&s->chr)) {
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(&s->chr, &s->tx, 1);
@@ -1013,10 +1013,10 @@ static void escc_realize(DeviceState *dev, Error **errp)
ESCC_SIZE << s->it_shift);
for (i = 0; i < 2; i++) {
- if (qemu_chr_fe_get_driver(&s->chn[i].chr)) {
+ if (qemu_chr_fe_backend_connected(&s->chn[i].chr)) {
s->chn[i].clock = s->frequency / 2;
qemu_chr_fe_set_handlers(&s->chn[i].chr, serial_can_receive,
- serial_receive1, serial_event,
+ serial_receive1, serial_event, NULL,
&s->chn[i], NULL, true);
}
}
diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c
index c1fba9f50f..a184026410 100644
--- a/hw/char/etraxfs_ser.c
+++ b/hw/char/etraxfs_ser.c
@@ -233,7 +233,7 @@ static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
qemu_chr_fe_set_handlers(&s->chr,
serial_can_receive, serial_receive,
- serial_event, s, NULL, true);
+ serial_event, NULL, s, NULL, true);
}
static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index b51d44a321..3957e78abf 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -380,7 +380,7 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
break;
case UTXH:
- if (qemu_chr_fe_get_driver(&s->chr)) {
+ if (qemu_chr_fe_backend_connected(&s->chr)) {
s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY |
UTRSTAT_Tx_BUFFER_EMPTY);
ch = (uint8_t)val;
@@ -645,7 +645,7 @@ static void exynos4210_uart_realize(DeviceState *dev, Error **errp)
qemu_chr_fe_set_handlers(&s->chr, exynos4210_uart_can_receive,
exynos4210_uart_receive, exynos4210_uart_event,
- s, NULL, true);
+ NULL, s, NULL, true);
}
static Property exynos4210_uart_properties[] = {
diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c
index 32d98edf49..bac11bec58 100644
--- a/hw/char/grlib_apbuart.c
+++ b/hw/char/grlib_apbuart.c
@@ -201,7 +201,7 @@ static void grlib_apbuart_write(void *opaque, hwaddr addr,
case DATA_OFFSET:
case DATA_OFFSET + 3: /* When only one byte write */
/* Transmit when character device available and transmitter enabled */
- if (qemu_chr_fe_get_driver(&uart->chr) &&
+ if (qemu_chr_fe_backend_connected(&uart->chr) &&
(uart->control & UART_TRANSMIT_ENABLE)) {
c = value & 0xFF;
/* XXX this blocks entire thread. Rewrite to use
@@ -247,7 +247,7 @@ static int grlib_apbuart_init(SysBusDevice *dev)
grlib_apbuart_can_receive,
grlib_apbuart_receive,
grlib_apbuart_event,
- uart, NULL, true);
+ NULL, uart, NULL, true);
sysbus_init_irq(dev, &uart->irq);
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
index af250305be..70405ccf8b 100644
--- a/hw/char/imx_serial.c
+++ b/hw/char/imx_serial.c
@@ -315,7 +315,7 @@ static void imx_serial_realize(DeviceState *dev, Error **errp)
DPRINTF("char dev for uart: %p\n", qemu_chr_fe_get_driver(&s->chr));
qemu_chr_fe_set_handlers(&s->chr, imx_can_receive, imx_receive,
- imx_event, s, NULL, true);
+ imx_event, NULL, s, NULL, true);
}
static void imx_serial_init(Object *obj)
diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c
index 337a3e566a..5e09caf851 100644
--- a/hw/char/ipoctal232.c
+++ b/hw/char/ipoctal232.c
@@ -542,10 +542,10 @@ static void ipoctal_realize(DeviceState *dev, Error **errp)
ch->ipoctal = s;
/* Redirect IP-Octal channels to host character devices */
- if (qemu_chr_fe_get_driver(&ch->dev)) {
+ if (qemu_chr_fe_backend_connected(&ch->dev)) {
qemu_chr_fe_set_handlers(&ch->dev, hostdev_can_receive,
hostdev_receive, hostdev_event,
- ch, NULL, true);
+ NULL, ch, NULL, true);
DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label);
} else {
DPRINTF("Could not redirect channel %u, no chardev set\n", i);
diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c
index 3948dcd332..d75c835ad2 100644
--- a/hw/char/lm32_juart.c
+++ b/hw/char/lm32_juart.c
@@ -119,7 +119,7 @@ static void lm32_juart_realize(DeviceState *dev, Error **errp)
LM32JuartState *s = LM32_JUART(dev);
qemu_chr_fe_set_handlers(&s->chr, juart_can_rx, juart_rx,
- juart_event, s, NULL, true);
+ juart_event, NULL, s, NULL, true);
}
static const VMStateDescription vmstate_lm32_juart = {
diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c
index cff8c38f90..c4a3b9b275 100644
--- a/hw/char/lm32_uart.c
+++ b/hw/char/lm32_uart.c
@@ -266,7 +266,7 @@ static void lm32_uart_realize(DeviceState *dev, Error **errp)
LM32UartState *s = LM32_UART(dev);
qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
- uart_event, s, NULL, true);
+ uart_event, NULL, s, NULL, true);
}
static const VMStateDescription vmstate_lm32_uart = {
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index fe12ad5ccb..56fa402b58 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -305,7 +305,7 @@ static void mcf_uart_realize(DeviceState *dev, Error **errp)
mcf_uart_state *s = MCF_UART(dev);
qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive, mcf_uart_receive,
- mcf_uart_event, s, NULL, true);
+ mcf_uart_event, NULL, s, NULL, true);
}
static Property mcf_uart_properties[] = {
diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c
index e19d0f6520..548ee27bca 100644
--- a/hw/char/milkymist-uart.c
+++ b/hw/char/milkymist-uart.c
@@ -199,7 +199,7 @@ static void milkymist_uart_realize(DeviceState *dev, Error **errp)
MilkymistUartState *s = MILKYMIST_UART(dev);
qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
- uart_event, s, NULL, true);
+ uart_event, NULL, s, NULL, true);
}
static void milkymist_uart_init(Object *obj)
diff --git a/hw/char/parallel.c b/hw/char/parallel.c
index 75a1a2f55e..f79dc76543 100644
--- a/hw/char/parallel.c
+++ b/hw/char/parallel.c
@@ -503,6 +503,10 @@ static const VMStateDescription vmstate_parallel_isa = {
}
};
+static int parallel_can_receive(void *opaque)
+{
+ return 1;
+}
static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
{
@@ -513,7 +517,7 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
int base;
uint8_t dummy;
- if (!qemu_chr_fe_get_driver(&s->chr)) {
+ if (!qemu_chr_fe_backend_connected(&s->chr)) {
error_setg(errp, "Can't create parallel device, empty char device");
return;
}
@@ -535,6 +539,8 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
isa_init_irq(isadev, &s->irq, isa->isairq);
qemu_register_reset(parallel_reset, s);
+ qemu_chr_fe_set_handlers(&s->chr, parallel_can_receive, NULL,
+ NULL, NULL, s, NULL, true);
if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
s->hw_driver = 1;
s->status = dummy;
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index 33802f00c8..2aa277fc4f 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -329,7 +329,7 @@ static void pl011_realize(DeviceState *dev, Error **errp)
PL011State *s = PL011(dev);
qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
- pl011_event, s, NULL, true);
+ pl011_event, NULL, s, NULL, true);
}
static void pl011_class_init(ObjectClass *oc, void *data)
diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c
index 1b15046690..c500bdaf29 100644
--- a/hw/char/sclpconsole-lm.c
+++ b/hw/char/sclpconsole-lm.c
@@ -195,7 +195,7 @@ static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
{
SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
- if (!qemu_chr_fe_get_driver(&scon->chr)) {
+ if (!qemu_chr_fe_backend_connected(&scon->chr)) {
/* If there's no backend, we can just say we consumed all data. */
return len;
}
@@ -313,7 +313,7 @@ static int console_init(SCLPEvent *event)
console_available = true;
qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
- chr_read, NULL, scon, NULL, true);
+ chr_read, NULL, NULL, scon, NULL, true);
return 0;
}
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
index 4a107a268d..d0265dfa7a 100644
--- a/hw/char/sclpconsole.c
+++ b/hw/char/sclpconsole.c
@@ -163,7 +163,7 @@ static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
{
SCLPConsole *scon = SCLP_CONSOLE(event);
- if (!qemu_chr_fe_get_driver(&scon->chr)) {
+ if (!qemu_chr_fe_backend_connected(&scon->chr)) {
/* If there's no backend, we can just say we consumed all data. */
return len;
}
@@ -228,7 +228,7 @@ static int console_init(SCLPEvent *event)
}
console_available = true;
qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
- chr_read, NULL, scon, NULL, true);
+ chr_read, NULL, NULL, scon, NULL, true);
return 0;
}
diff --git a/hw/char/serial.c b/hw/char/serial.c
index e1f12507bf..9aec6c60d8 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -312,6 +312,24 @@ static void serial_write_fcr(SerialState *s, uint8_t val)
}
}
+static void serial_update_tiocm(SerialState *s)
+{
+ int flags;
+
+ qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
+
+ flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR);
+
+ if (s->mcr & UART_MCR_RTS) {
+ flags |= CHR_TIOCM_RTS;
+ }
+ if (s->mcr & UART_MCR_DTR) {
+ flags |= CHR_TIOCM_DTR;
+ }
+
+ qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
+}
+
static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
@@ -426,24 +444,13 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
break;
case 4:
{
- int flags;
int old_mcr = s->mcr;
s->mcr = val & 0x1f;
if (val & UART_MCR_LOOP)
break;
if (s->poll_msl >= 0 && old_mcr != s->mcr) {
-
- qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
-
- flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR);
-
- if (val & UART_MCR_RTS)
- flags |= CHR_TIOCM_RTS;
- if (val & UART_MCR_DTR)
- flags |= CHR_TIOCM_DTR;
-
- qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
+ serial_update_tiocm(s);
/* Update the modem status after a one-character-send wait-time, since there may be a response
from the device/computer at the other end of the serial line */
timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time);
@@ -884,9 +891,37 @@ static void serial_reset(void *opaque)
s->msr &= ~UART_MSR_ANY_DELTA;
}
+static int serial_be_change(void *opaque)
+{
+ SerialState *s = opaque;
+
+ qemu_chr_fe_set_handlers(&s->chr, serial_can_receive1, serial_receive1,
+ serial_event, serial_be_change, s, NULL, true);
+
+ serial_update_parameters(s);
+
+ qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
+ &s->last_break_enable);
+
+ s->poll_msl = (s->ier & UART_IER_MSI) ? 1 : 0;
+ serial_update_msl(s);
+
+ if (s->poll_msl >= 0 && !(s->mcr & UART_MCR_LOOP)) {
+ serial_update_tiocm(s);
+ }
+
+ if (s->watch_tag > 0) {
+ g_source_remove(s->watch_tag);
+ s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
+ serial_watch_cb, s);
+ }
+
+ return 0;
+}
+
void serial_realize_core(SerialState *s, Error **errp)
{
- if (!qemu_chr_fe_get_driver(&s->chr)) {
+ if (!qemu_chr_fe_backend_connected(&s->chr)) {
error_setg(errp, "Can't create serial device, empty char device");
return;
}
@@ -897,7 +932,7 @@ void serial_realize_core(SerialState *s, Error **errp)
qemu_register_reset(serial_reset, s);
qemu_chr_fe_set_handlers(&s->chr, serial_can_receive1, serial_receive1,
- serial_event, s, NULL, true);
+ serial_event, serial_be_change, s, NULL, true);
fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
serial_reset(s);
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index ca9816d045..835b5378a0 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -110,7 +110,7 @@ static void sh_serial_write(void *opaque, hwaddr offs,
}
return;
case 0x0c: /* FTDR / TDR */
- if (qemu_chr_fe_get_driver(&s->chr)) {
+ if (qemu_chr_fe_backend_connected(&s->chr)) {
ch = val;
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
@@ -400,7 +400,7 @@ void sh_serial_init(MemoryRegion *sysmem,
qemu_chr_fe_init(&s->chr, chr, &error_abort);
qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1,
sh_serial_receive1,
- sh_serial_event, s, NULL, true);
+ sh_serial_event, NULL, s, NULL, true);
}
s->eri = eri_source;
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index 8f02f3a612..0fa416ca6b 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -78,13 +78,13 @@ static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
{
VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
- if (!qemu_chr_fe_get_driver(&dev->chardev)) {
+ if (!qemu_chr_fe_backend_connected(&dev->chardev)) {
error_setg(errp, "chardev property not set");
return;
}
qemu_chr_fe_set_handlers(&dev->chardev, vty_can_receive,
- vty_receive, NULL, dev, NULL, true);
+ vty_receive, NULL, NULL, dev, NULL, true);
}
/* Forward declaration */
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
index 59872e6d3b..268e435338 100644
--- a/hw/char/stm32f2xx_usart.c
+++ b/hw/char/stm32f2xx_usart.c
@@ -207,7 +207,8 @@ static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp)
STM32F2XXUsartState *s = STM32F2XX_USART(dev);
qemu_chr_fe_set_handlers(&s->chr, stm32f2xx_usart_can_receive,
- stm32f2xx_usart_receive, NULL, s, NULL, true);
+ stm32f2xx_usart_receive, NULL, NULL,
+ s, NULL, true);
}
static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)
diff --git a/hw/char/terminal3270.c b/hw/char/terminal3270.c
index 7b10a04f18..28f599111d 100644
--- a/hw/char/terminal3270.c
+++ b/hw/char/terminal3270.c
@@ -179,7 +179,7 @@ static void terminal_init(EmulatedCcw3270Device *dev, Error **errp)
}
terminal_available = true;
qemu_chr_fe_set_handlers(&t->chr, terminal_can_read,
- terminal_read, chr_event, t, NULL, true);
+ terminal_read, chr_event, NULL, t, NULL, true);
}
static int read_payload_3270(EmulatedCcw3270Device *dev, uint32_t cda,
@@ -239,7 +239,7 @@ static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd,
return 0;
}
}
- if (!qemu_chr_fe_get_driver(&t->chr)) {
+ if (!qemu_chr_fe_backend_connected(&t->chr)) {
/* We just say we consumed all data if there's no backend. */
return count;
}
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index 0cb1668c8a..198b2a89c0 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -49,7 +49,7 @@ static ssize_t flush_buf(VirtIOSerialPort *port,
VirtConsole *vcon = VIRTIO_CONSOLE(port);
ssize_t ret;
- if (!qemu_chr_fe_get_driver(&vcon->chr)) {
+ if (!qemu_chr_fe_backend_connected(&vcon->chr)) {
/* If there's no backend, we can just say we consumed all data. */
return len;
}
@@ -163,12 +163,35 @@ static void chr_event(void *opaque, int event)
}
}
+static int chr_be_change(void *opaque)
+{
+ VirtConsole *vcon = opaque;
+ VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon);
+ VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
+
+ if (k->is_console) {
+ qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
+ NULL, chr_be_change, vcon, NULL, true);
+ } else {
+ qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
+ chr_event, chr_be_change, vcon, NULL, false);
+ }
+
+ if (vcon->watch) {
+ g_source_remove(vcon->watch);
+ vcon->watch = qemu_chr_fe_add_watch(&vcon->chr,
+ G_IO_OUT | G_IO_HUP,
+ chr_write_unblocked, vcon);
+ }
+
+ return 0;
+}
+
static void virtconsole_realize(DeviceState *dev, Error **errp)
{
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
VirtConsole *vcon = VIRTIO_CONSOLE(dev);
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev);
- Chardev *chr = qemu_chr_fe_get_driver(&vcon->chr);
if (port->id == 0 && !k->is_console) {
error_setg(errp, "Port number 0 on virtio-serial devices reserved "
@@ -176,7 +199,7 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
return;
}
- if (chr) {
+ if (qemu_chr_fe_backend_connected(&vcon->chr)) {
/*
* For consoles we don't block guest data transfer just
* because nothing is connected - we'll just let it go
@@ -188,11 +211,13 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
*/
if (k->is_console) {
qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
- NULL, vcon, NULL, true);
+ NULL, chr_be_change,
+ vcon, NULL, true);
virtio_serial_open(port);
} else {
qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
- chr_event, vcon, NULL, false);
+ chr_event, chr_be_change,
+ vcon, NULL, false);
}
}
}
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index f9af8cadf4..3643dfe067 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -150,7 +150,7 @@ static void xencons_send(struct XenConsole *con)
ssize_t len, size;
size = con->buffer.size - con->buffer.consumed;
- if (qemu_chr_fe_get_driver(&con->chr)) {
+ if (qemu_chr_fe_backend_connected(&con->chr)) {
len = qemu_chr_fe_write(&con->chr,
con->buffer.data + con->buffer.consumed,
size);
@@ -246,7 +246,7 @@ static int con_initialise(struct XenDevice *xendev)
xen_be_bind_evtchn(&con->xendev);
qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive,
- xencons_receive, NULL, con, NULL, true);
+ xencons_receive, NULL, NULL, con, NULL, true);
xen_pv_printf(xendev, 1,
"ring mfn %d, remote port %d, local port %d, limit %zd\n",
diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c
index 71ed2fc1be..2a8bc1e497 100644
--- a/hw/char/xilinx_uartlite.c
+++ b/hw/char/xilinx_uartlite.c
@@ -212,7 +212,7 @@ static void xilinx_uartlite_realize(DeviceState *dev, Error **errp)
XilinxUARTLite *s = XILINX_UARTLITE(dev);
qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
- uart_event, s, NULL, true);
+ uart_event, NULL, s, NULL, true);
}
static void xilinx_uartlite_init(Object *obj)
diff --git a/hw/core/loader.c b/hw/core/loader.c
index f72930ca4a..c17ace0a2e 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -150,7 +150,9 @@ int load_image_targphys_as(const char *filename,
return -1;
}
if (size > 0) {
- rom_add_file_fixed_as(filename, addr, -1, as);
+ if (rom_add_file_fixed_as(filename, addr, -1, as) < 0) {
+ return -1;
+ }
}
return size;
}
@@ -478,6 +480,7 @@ int load_elf_ram(const char *filename,
}
if (target_data_order != e_ident[EI_DATA]) {
+ fprintf(stderr, "%s: wrong endianness\n", filename);
ret = ELF_LOAD_WRONG_ENDIAN;
goto fail;
}
diff --git a/hw/core/machine.c b/hw/core/machine.c
index ecb55528e8..dc431fabf5 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -741,11 +741,11 @@ static void machine_numa_finish_init(MachineState *machine)
}
}
if (s->len && !qtest_enabled()) {
- error_report("warning: CPU(s) not present in any NUMA nodes: %s",
- s->str);
- error_report("warning: All CPU(s) up to maxcpus should be described "
- "in NUMA config, ability to start up with partial NUMA "
- "mappings is obsoleted and will be removed in future");
+ warn_report("CPU(s) not present in any NUMA nodes: %s",
+ s->str);
+ warn_report("All CPU(s) up to maxcpus should be described "
+ "in NUMA config, ability to start up with partial NUMA "
+ "mappings is obsoleted and will be removed in future");
}
g_string_free(s, true);
}
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 3bef41914d..ec10da7424 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -159,7 +159,7 @@ static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
set_pointer(obj, v, opaque, parse_drive, name, errp);
}
-PropertyInfo qdev_prop_drive = {
+const PropertyInfo qdev_prop_drive = {
.name = "str",
.description = "Node name or ID of a block device to use as a backend",
.get = get_drive,
@@ -228,7 +228,7 @@ static void release_chr(Object *obj, const char *name, void *opaque)
qemu_chr_fe_deinit(be, false);
}
-PropertyInfo qdev_prop_chr = {
+const PropertyInfo qdev_prop_chr = {
.name = "str",
.description = "ID of a chardev to use as a backend",
.get = get_chr,
@@ -313,7 +313,7 @@ out:
g_free(str);
}
-PropertyInfo qdev_prop_netdev = {
+const PropertyInfo qdev_prop_netdev = {
.name = "str",
.description = "ID of a netdev to use as a backend",
.get = get_netdev,
@@ -393,7 +393,7 @@ static void set_vlan(Object *obj, Visitor *v, const char *name, void *opaque,
*ptr = hubport;
}
-PropertyInfo qdev_prop_vlan = {
+const PropertyInfo qdev_prop_vlan = {
.name = "int32",
.description = "Integer VLAN id to connect to",
.print = print_vlan,
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index f11d57831b..dcecdf03e5 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -25,7 +25,8 @@ void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
}
}
-void qdev_prop_allow_set_link_before_realize(Object *obj, const char *name,
+void qdev_prop_allow_set_link_before_realize(const Object *obj,
+ const char *name,
Object *val, Error **errp)
{
DeviceState *dev = DEVICE(obj);
@@ -131,7 +132,7 @@ static void set_default_value_bool(Object *obj, const Property *prop)
object_property_set_bool(obj, prop->defval.u, prop->name, &error_abort);
}
-PropertyInfo qdev_prop_bit = {
+const PropertyInfo qdev_prop_bit = {
.name = "bool",
.description = "on/off",
.get = prop_get_bit,
@@ -190,7 +191,7 @@ static void prop_set_bit64(Object *obj, Visitor *v, const char *name,
bit64_prop_set(dev, prop, value);
}
-PropertyInfo qdev_prop_bit64 = {
+const PropertyInfo qdev_prop_bit64 = {
.name = "bool",
.description = "on/off",
.get = prop_get_bit64,
@@ -225,7 +226,7 @@ static void set_bool(Object *obj, Visitor *v, const char *name, void *opaque,
visit_type_bool(v, name, ptr, errp);
}
-PropertyInfo qdev_prop_bool = {
+const PropertyInfo qdev_prop_bool = {
.name = "bool",
.get = get_bool,
.set = set_bool,
@@ -269,7 +270,7 @@ static void set_default_value_uint(Object *obj, const Property *prop)
object_property_set_uint(obj, prop->defval.u, prop->name, &error_abort);
}
-PropertyInfo qdev_prop_uint8 = {
+const PropertyInfo qdev_prop_uint8 = {
.name = "uint8",
.get = get_uint8,
.set = set_uint8,
@@ -303,7 +304,7 @@ static void set_uint16(Object *obj, Visitor *v, const char *name,
visit_type_uint16(v, name, ptr, errp);
}
-PropertyInfo qdev_prop_uint16 = {
+const PropertyInfo qdev_prop_uint16 = {
.name = "uint16",
.get = get_uint16,
.set = set_uint16,
@@ -362,14 +363,14 @@ static void set_int32(Object *obj, Visitor *v, const char *name, void *opaque,
visit_type_int32(v, name, ptr, errp);
}
-PropertyInfo qdev_prop_uint32 = {
+const PropertyInfo qdev_prop_uint32 = {
.name = "uint32",
.get = get_uint32,
.set = set_uint32,
.set_default_value = set_default_value_uint,
};
-PropertyInfo qdev_prop_int32 = {
+const PropertyInfo qdev_prop_int32 = {
.name = "int32",
.get = get_int32,
.set = set_int32,
@@ -403,7 +404,7 @@ static void set_uint64(Object *obj, Visitor *v, const char *name,
visit_type_uint64(v, name, ptr, errp);
}
-PropertyInfo qdev_prop_uint64 = {
+const PropertyInfo qdev_prop_uint64 = {
.name = "uint64",
.get = get_uint64,
.set = set_uint64,
@@ -456,7 +457,7 @@ static void set_string(Object *obj, Visitor *v, const char *name,
*ptr = str;
}
-PropertyInfo qdev_prop_string = {
+const PropertyInfo qdev_prop_string = {
.name = "str",
.release = release_string,
.get = get_string,
@@ -466,7 +467,7 @@ PropertyInfo qdev_prop_string = {
/* --- pointer --- */
/* Not a proper property, just for dirty hacks. TODO Remove it! */
-PropertyInfo qdev_prop_ptr = {
+const PropertyInfo qdev_prop_ptr = {
.name = "ptr",
};
@@ -540,7 +541,7 @@ inval:
g_free(str);
}
-PropertyInfo qdev_prop_macaddr = {
+const PropertyInfo qdev_prop_macaddr = {
.name = "str",
.description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56",
.get = get_mac,
@@ -549,7 +550,7 @@ PropertyInfo qdev_prop_macaddr = {
/* --- on/off/auto --- */
-PropertyInfo qdev_prop_on_off_auto = {
+const PropertyInfo qdev_prop_on_off_auto = {
.name = "OnOffAuto",
.description = "on/off/auto",
.enum_table = OnOffAuto_lookup,
@@ -562,7 +563,7 @@ PropertyInfo qdev_prop_on_off_auto = {
QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
-PropertyInfo qdev_prop_losttickpolicy = {
+const PropertyInfo qdev_prop_losttickpolicy = {
.name = "LostTickPolicy",
.enum_table = LostTickPolicy_lookup,
.get = get_enum,
@@ -574,7 +575,7 @@ PropertyInfo qdev_prop_losttickpolicy = {
QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int));
-PropertyInfo qdev_prop_blockdev_on_error = {
+const PropertyInfo qdev_prop_blockdev_on_error = {
.name = "BlockdevOnError",
.description = "Error handling policy, "
"report/ignore/enospc/stop/auto",
@@ -588,7 +589,7 @@ PropertyInfo qdev_prop_blockdev_on_error = {
QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
-PropertyInfo qdev_prop_bios_chs_trans = {
+const PropertyInfo qdev_prop_bios_chs_trans = {
.name = "BiosAtaTranslation",
.description = "Logical CHS translation algorithm, "
"auto/none/lba/large/rechs",
@@ -600,7 +601,7 @@ PropertyInfo qdev_prop_bios_chs_trans = {
/* --- FDC default drive types */
-PropertyInfo qdev_prop_fdc_drive_type = {
+const PropertyInfo qdev_prop_fdc_drive_type = {
.name = "FdcDriveType",
.description = "FDC drive type, "
"144/288/120/none/auto",
@@ -676,7 +677,7 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest,
}
}
-PropertyInfo qdev_prop_pci_devfn = {
+const PropertyInfo qdev_prop_pci_devfn = {
.name = "int32",
.description = "Slot and optional function number, example: 06.0 or 06",
.print = print_pci_devfn,
@@ -725,7 +726,7 @@ static void set_blocksize(Object *obj, Visitor *v, const char *name,
*ptr = value;
}
-PropertyInfo qdev_prop_blocksize = {
+const PropertyInfo qdev_prop_blocksize = {
.name = "uint16",
.description = "A power of two between 512 and 32768",
.get = get_uint16,
@@ -840,7 +841,7 @@ inval:
g_free(str);
}
-PropertyInfo qdev_prop_pci_host_devaddr = {
+const PropertyInfo qdev_prop_pci_host_devaddr = {
.name = "str",
.description = "Address (bus/device/function) of "
"the host device, example: 04:10.0",
@@ -949,7 +950,7 @@ static void set_prop_arraylen(Object *obj, Visitor *v, const char *name,
}
}
-PropertyInfo qdev_prop_arraylen = {
+const PropertyInfo qdev_prop_arraylen = {
.name = "uint32",
.get = get_uint32,
.set = set_prop_arraylen,
@@ -1132,15 +1133,15 @@ int qdev_prop_check_globals(void)
oc = object_class_by_name(prop->driver);
oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
if (!oc) {
- error_report("Warning: global %s.%s has invalid class name",
- prop->driver, prop->property);
+ warn_report("global %s.%s has invalid class name",
+ prop->driver, prop->property);
ret = 1;
continue;
}
dc = DEVICE_CLASS(oc);
if (!dc->hotpluggable && !prop->used) {
- error_report("Warning: global %s.%s=%s not used",
- prop->driver, prop->property, prop->value);
+ warn_report("global %s.%s=%s not used",
+ prop->driver, prop->property, prop->value);
ret = 1;
continue;
}
@@ -1169,7 +1170,7 @@ static void qdev_prop_set_globals_for_type(DeviceState *dev,
error_propagate(prop->errp, err);
} else {
assert(prop->user_provided);
- error_reportf_err(err, "Warning: ");
+ warn_report_err(err);
}
}
}
@@ -1207,9 +1208,27 @@ static void set_size(Object *obj, Visitor *v, const char *name, void *opaque,
visit_type_size(v, name, ptr, errp);
}
-PropertyInfo qdev_prop_size = {
+const PropertyInfo qdev_prop_size = {
.name = "size",
.get = get_size,
.set = set_size,
.set_default_value = set_default_value_uint,
};
+
+/* --- object link property --- */
+
+static void create_link_property(Object *obj, Property *prop, Error **errp)
+{
+ Object **child = qdev_get_prop_ptr(DEVICE(obj), prop);
+
+ object_property_add_link(obj, prop->name, prop->link_type,
+ child,
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_UNREF_ON_RELEASE,
+ errp);
+}
+
+const PropertyInfo qdev_prop_link = {
+ .name = "link",
+ .create = create_link_property,
+};
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 849952a8d4..ec63fe0354 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -744,6 +744,10 @@ static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
return;
}
+ if (prop->info->create) {
+ return;
+ }
+
name = g_strdup_printf("legacy-%s", prop->name);
object_property_add(OBJECT(dev), name, "str",
prop->info->print ? qdev_get_legacy_property : prop->info->get,
@@ -770,20 +774,23 @@ void qdev_property_add_static(DeviceState *dev, Property *prop,
Error *local_err = NULL;
Object *obj = OBJECT(dev);
- /*
- * TODO qdev_prop_ptr does not have getters or setters. It must
- * go now that it can be replaced with links. The test should be
- * removed along with it: all static properties are read/write.
- */
- if (!prop->info->get && !prop->info->set) {
- return;
+ if (prop->info->create) {
+ prop->info->create(obj, prop, &local_err);
+ } else {
+ /*
+ * TODO qdev_prop_ptr does not have getters or setters. It must
+ * go now that it can be replaced with links. The test should be
+ * removed along with it: all static properties are read/write.
+ */
+ if (!prop->info->get && !prop->info->set) {
+ return;
+ }
+ object_property_add(obj, prop->name, prop->info->name,
+ prop->info->get, prop->info->set,
+ prop->info->release,
+ prop, &local_err);
}
- object_property_add(obj, prop->name, prop->info->name,
- prop->info->get, prop->info->set,
- prop->info->release,
- prop, &local_err);
-
if (local_err) {
error_propagate(errp, local_err);
return;
diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c
index 60df8877c1..80674f6bbb 100644
--- a/hw/cris/axis_dev88.c
+++ b/hw/cris/axis_dev88.c
@@ -281,9 +281,8 @@ void axisdev88_init(MachineState *machine)
/* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the
internal memory. */
- memory_region_init_ram(phys_intmem, NULL, "axisdev88.chipram", INTMEM_SIZE,
- &error_fatal);
- vmstate_register_ram_global(phys_intmem);
+ memory_region_init_ram(phys_intmem, NULL, "axisdev88.chipram",
+ INTMEM_SIZE, &error_fatal);
memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem);
/* Attach a NAND flash to CS1. */
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index 1de15a1d34..e069c4484c 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -283,7 +283,7 @@ static void cg3_initfn(Object *obj)
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
CG3State *s = CG3(obj);
- memory_region_init_ram(&s->rom, obj, "cg3.prom", FCODE_MAX_ROM_SIZE,
+ memory_region_init_ram_nomigrate(&s->rom, obj, "cg3.prom", FCODE_MAX_ROM_SIZE,
&error_fatal);
memory_region_set_readonly(&s->rom, true);
sysbus_init_mmio(sbd, &s->rom);
@@ -314,7 +314,6 @@ static void cg3_realizefn(DeviceState *dev, Error **errp)
memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size,
&error_fatal);
memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA);
- vmstate_register_ram_global(&s->vram_mem);
sysbus_init_mmio(sbd, &s->vram_mem);
sysbus_init_irq(sbd, &s->irq);
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 3c1688e7cb..7f8c73b56d 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -2091,14 +2091,12 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp)
qxl->rom_size = qxl_rom_size();
memory_region_init_ram(&qxl->rom_bar, OBJECT(qxl), "qxl.vrom",
qxl->rom_size, &error_fatal);
- vmstate_register_ram(&qxl->rom_bar, &qxl->pci.qdev);
init_qxl_rom(qxl);
init_qxl_ram(qxl);
qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces);
memory_region_init_ram(&qxl->vram_bar, OBJECT(qxl), "qxl.vram",
qxl->vram_size, &error_fatal);
- vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev);
memory_region_init_alias(&qxl->vram32_bar, OBJECT(qxl), "qxl.vram32",
&qxl->vram_bar, 0, qxl->vram32_size);
@@ -2200,7 +2198,6 @@ static void qxl_realize_secondary(PCIDevice *dev, Error **errp)
qxl_init_ramsize(qxl);
memory_region_init_ram(&qxl->vga.vram, OBJECT(dev), "qxl.vgavram",
qxl->vga.vram_size, &error_fatal);
- vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 9d254ef2e1..af792c533b 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -1578,7 +1578,7 @@ static void sm501_init(SM501State *s, DeviceState *dev,
s->local_mem_size_index);
/* local memory */
- memory_region_init_ram(&s->local_mem_region, OBJECT(dev), "sm501.local",
+ memory_region_init_ram_nomigrate(&s->local_mem_region, OBJECT(dev), "sm501.local",
get_local_mem_size(s), &error_fatal);
vmstate_register_ram_global(&s->local_mem_region);
memory_region_set_log(&s->local_mem_region, true, DIRTY_MEMORY_VGA);
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
index 92f7120acc..74d10af3d4 100644
--- a/hw/display/tc6393xb.c
+++ b/hw/display/tc6393xb.c
@@ -588,7 +588,6 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
memory_region_init_ram(&s->vram, NULL, "tc6393xb.vram", 0x100000,
&error_fatal);
- vmstate_register_ram_global(&s->vram);
s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
s->scr_width = 480;
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index 6593c1d6af..daa93e0929 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -752,7 +752,7 @@ static void tcx_initfn(Object *obj)
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
TCXState *s = TCX(obj);
- memory_region_init_ram(&s->rom, obj, "tcx.prom", FCODE_MAX_ROM_SIZE,
+ memory_region_init_ram_nomigrate(&s->rom, obj, "tcx.prom", FCODE_MAX_ROM_SIZE,
&error_fatal);
memory_region_set_readonly(&s->rom, true);
sysbus_init_mmio(sbd, &s->rom);
@@ -812,7 +812,7 @@ static void tcx_realizefn(DeviceState *dev, Error **errp)
uint8_t *vram_base;
char *fcode_filename;
- memory_region_init_ram(&s->vram_mem, OBJECT(s), "tcx.vram",
+ memory_region_init_ram_nomigrate(&s->vram_mem, OBJECT(s), "tcx.vram",
s->vram_size * (1 + 4 + 4), &error_fatal);
vmstate_register_ram_global(&s->vram_mem);
memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA);
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 80508b83f4..63421f9ee8 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -2166,7 +2166,7 @@ void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
}
s->is_vbe_vmstate = 1;
- memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size,
+ memory_region_init_ram_nomigrate(&s->vram, obj, "vga.vram", s->vram_size,
&error_fatal);
vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj));
xen_register_framebuffer(&s->vram);
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index c989cef1cd..4a64b41259 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1241,7 +1241,6 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
s->fifo_size = SVGA_FIFO_SIZE;
memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size,
&error_fatal);
- vmstate_register_ram_global(&s->fifo_ram);
s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram);
vga_common_init(&s->vga, OBJECT(dev), true);
diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c
index a77d7db22f..561f828e7a 100644
--- a/hw/display/xlnx_dp.c
+++ b/hw/display/xlnx_dp.c
@@ -515,7 +515,7 @@ static void xlnx_dp_aux_set_command(XlnxDPState *s, uint32_t value)
s->core_registers[DP_INTERRUPT_SIGNAL_STATE] |= 0x04;
}
-static void xlnx_dp_set_dpdma(Object *obj, const char *name, Object *val,
+static void xlnx_dp_set_dpdma(const Object *obj, const char *name, Object *val,
Error **errp)
{
XlnxDPState *s = XLNX_DP(obj);
diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c
index edf9432051..5d4833eeca 100644
--- a/hw/dma/rc4030.c
+++ b/hw/dma/rc4030.c
@@ -54,6 +54,8 @@ typedef struct dma_pagetable_entry {
#define RC4030(obj) \
OBJECT_CHECK(rc4030State, (obj), TYPE_RC4030)
+#define TYPE_RC4030_IOMMU_MEMORY_REGION "rc4030-iommu-memory-region"
+
typedef struct rc4030State
{
SysBusDevice parent;
@@ -90,7 +92,7 @@ typedef struct rc4030State
qemu_irq jazz_bus_irq;
/* whole DMA memory region, root of DMA address space */
- MemoryRegion dma_mr;
+ IOMMUMemoryRegion dma_mr;
AddressSpace dma_as;
MemoryRegion iomem_chipset;
@@ -488,7 +490,7 @@ static const MemoryRegionOps jazzio_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static IOMMUTLBEntry rc4030_dma_translate(MemoryRegion *iommu, hwaddr addr,
+static IOMMUTLBEntry rc4030_dma_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag)
{
rc4030State *s = container_of(iommu, rc4030State, dma_mr);
@@ -516,10 +518,6 @@ static IOMMUTLBEntry rc4030_dma_translate(MemoryRegion *iommu, hwaddr addr,
return ret;
}
-static const MemoryRegionIOMMUOps rc4030_dma_ops = {
- .translate = rc4030_dma_translate,
-};
-
static void rc4030_reset(DeviceState *dev)
{
rc4030State *s = RC4030(dev);
@@ -677,9 +675,10 @@ static void rc4030_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&s->iomem_jazzio, NULL, &jazzio_ops, s,
"rc4030.jazzio", 0x00001000);
- memory_region_init_iommu(&s->dma_mr, o, &rc4030_dma_ops,
- "rc4030.dma", UINT32_MAX);
- address_space_init(&s->dma_as, &s->dma_mr, "rc4030-dma");
+ memory_region_init_iommu(&s->dma_mr, sizeof(s->dma_mr),
+ TYPE_RC4030_IOMMU_MEMORY_REGION,
+ o, "rc4030.dma", UINT32_MAX);
+ address_space_init(&s->dma_as, MEMORY_REGION(&s->dma_mr), "rc4030-dma");
}
static void rc4030_unrealize(DeviceState *dev, Error **errp)
@@ -710,14 +709,29 @@ static const TypeInfo rc4030_info = {
.class_init = rc4030_class_init,
};
+static void rc4030_iommu_memory_region_class_init(ObjectClass *klass,
+ void *data)
+{
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
+
+ imrc->translate = rc4030_dma_translate;
+}
+
+static const TypeInfo rc4030_iommu_memory_region_info = {
+ .parent = TYPE_IOMMU_MEMORY_REGION,
+ .name = TYPE_RC4030_IOMMU_MEMORY_REGION,
+ .class_init = rc4030_iommu_memory_region_class_init,
+};
+
static void rc4030_register_types(void)
{
type_register_static(&rc4030_info);
+ type_register_static(&rc4030_iommu_memory_region_info);
}
type_init(rc4030_register_types)
-DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr)
+DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr)
{
DeviceState *dev;
diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
index 6065689ad1..3987b5ff96 100644
--- a/hw/dma/xilinx_axidma.c
+++ b/hw/dma/xilinx_axidma.c
@@ -554,9 +554,7 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
return;
xilinx_axidma_realize_fail:
- if (!*errp) {
- *errp = local_err;
- }
+ error_propagate(errp, local_err);
}
static void xilinx_axidma_init(Object *obj)
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 5464977424..6b7bade183 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -2766,17 +2766,17 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
ACPI_BUILD_ALIGN_SIZE);
if (tables_blob->len > legacy_table_size) {
/* Should happen only with PCI bridges and -M pc-i440fx-2.0. */
- error_report("Warning: migration may not work.");
+ warn_report("migration may not work.");
}
g_array_set_size(tables_blob, legacy_table_size);
} else {
/* Make sure we have a buffer in case we need to resize the tables. */
if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
/* As of QEMU 2.1, this fires with 160 VCPUs and 255 memory slots. */
- error_report("Warning: ACPI tables are larger than 64k.");
- error_report("Warning: migration may not work.");
- error_report("Warning: please remove CPUs, NUMA nodes, "
- "memory slots or PCI bridges.");
+ warn_report("ACPI tables are larger than 64k.");
+ warn_report("migration may not work.");
+ warn_report("please remove CPUs, NUMA nodes, "
+ "memory slots or PCI bridges.");
}
acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE);
}
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index d93ffc2a15..334938a280 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -52,7 +52,7 @@ struct AMDVIAddressSpace {
uint8_t bus_num; /* bus number */
uint8_t devfn; /* device function */
AMDVIState *iommu_state; /* AMDVI - one per machine */
- MemoryRegion iommu; /* Device's address translation region */
+ IOMMUMemoryRegion iommu; /* Device's address translation region */
MemoryRegion iommu_ir; /* Device's interrupt remapping region */
AddressSpace as; /* device's corresponding address space */
};
@@ -987,7 +987,7 @@ static inline bool amdvi_is_interrupt_addr(hwaddr addr)
return addr >= AMDVI_INT_ADDR_FIRST && addr <= AMDVI_INT_ADDR_LAST;
}
-static IOMMUTLBEntry amdvi_translate(MemoryRegion *iommu, hwaddr addr,
+static IOMMUTLBEntry amdvi_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag)
{
AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu);
@@ -1044,9 +1044,13 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
iommu_as[devfn]->devfn = (uint8_t)devfn;
iommu_as[devfn]->iommu_state = s;
- memory_region_init_iommu(&iommu_as[devfn]->iommu, OBJECT(s),
- &s->iommu_ops, "amd-iommu", UINT64_MAX);
- address_space_init(&iommu_as[devfn]->as, &iommu_as[devfn]->iommu,
+ memory_region_init_iommu(&iommu_as[devfn]->iommu,
+ sizeof(iommu_as[devfn]->iommu),
+ TYPE_AMD_IOMMU_MEMORY_REGION,
+ OBJECT(s),
+ "amd-iommu", UINT64_MAX);
+ address_space_init(&iommu_as[devfn]->as,
+ MEMORY_REGION(&iommu_as[devfn]->iommu),
"amd-iommu");
}
return &iommu_as[devfn]->as;
@@ -1067,7 +1071,7 @@ static const MemoryRegionOps mmio_mem_ops = {
}
};
-static void amdvi_iommu_notify_flag_changed(MemoryRegion *iommu,
+static void amdvi_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old,
IOMMUNotifierFlag new)
{
@@ -1085,8 +1089,6 @@ static void amdvi_init(AMDVIState *s)
{
amdvi_iotlb_reset(s);
- s->iommu_ops.translate = amdvi_translate;
- s->iommu_ops.notify_flag_changed = amdvi_iommu_notify_flag_changed;
s->devtab_len = 0;
s->cmdbuf_len = 0;
s->cmdbuf_head = 0;
@@ -1227,10 +1229,25 @@ static const TypeInfo amdviPCI = {
.instance_size = sizeof(AMDVIPCIState),
};
+static void amdvi_iommu_memory_region_class_init(ObjectClass *klass, void *data)
+{
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
+
+ imrc->translate = amdvi_translate;
+ imrc->notify_flag_changed = amdvi_iommu_notify_flag_changed;
+}
+
+static const TypeInfo amdvi_iommu_memory_region_info = {
+ .parent = TYPE_IOMMU_MEMORY_REGION,
+ .name = TYPE_AMD_IOMMU_MEMORY_REGION,
+ .class_init = amdvi_iommu_memory_region_class_init,
+};
+
static void amdviPCI_register_types(void)
{
type_register_static(&amdviPCI);
type_register_static(&amdvi);
+ type_register_static(&amdvi_iommu_memory_region_info);
}
type_init(amdviPCI_register_types);
diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h
index 0d3dc6a9f2..d370ae3549 100644
--- a/hw/i386/amd_iommu.h
+++ b/hw/i386/amd_iommu.h
@@ -220,6 +220,8 @@
#define TYPE_AMD_IOMMU_PCI "AMDVI-PCI"
+#define TYPE_AMD_IOMMU_MEMORY_REGION "amd-iommu-iommu-memory-region"
+
typedef struct AMDVIAddressSpace AMDVIAddressSpace;
/* functions to steal PCI config space */
@@ -276,9 +278,6 @@ typedef struct AMDVIState {
uint8_t romask[AMDVI_MMIO_SIZE]; /* MMIO read/only mask */
bool mmio_enabled;
- /* IOMMU function */
- MemoryRegionIOMMUOps iommu_ops;
-
/* for each served device */
AMDVIAddressSpace **address_spaces[PCI_BUS_MAX];
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 88dc042b5c..e398746b4b 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -972,9 +972,9 @@ static bool vtd_switch_address_space(VTDAddressSpace *as)
/* Turn off first then on the other */
if (use_iommu) {
memory_region_set_enabled(&as->sys_alias, false);
- memory_region_set_enabled(&as->iommu, true);
+ memory_region_set_enabled(MEMORY_REGION(&as->iommu), true);
} else {
- memory_region_set_enabled(&as->iommu, false);
+ memory_region_set_enabled(MEMORY_REGION(&as->iommu), false);
memory_region_set_enabled(&as->sys_alias, true);
}
@@ -1366,7 +1366,7 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)
static int vtd_page_invalidate_notify_hook(IOMMUTLBEntry *entry,
void *private)
{
- memory_region_notify_iommu((MemoryRegion *)private, *entry);
+ memory_region_notify_iommu((IOMMUMemoryRegion *)private, *entry);
return 0;
}
@@ -2264,7 +2264,7 @@ static void vtd_mem_write(void *opaque, hwaddr addr,
}
}
-static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr,
+static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag)
{
VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
@@ -2303,7 +2303,7 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr,
return iotlb;
}
-static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu,
+static void vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old,
IOMMUNotifierFlag new)
{
@@ -2718,8 +2718,9 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
* vtd_sys_alias and intel_iommu regions. IR region is always
* enabled.
*/
- memory_region_init_iommu(&vtd_dev_as->iommu, OBJECT(s),
- &s->iommu_ops, "intel_iommu_dmar",
+ memory_region_init_iommu(&vtd_dev_as->iommu, sizeof(vtd_dev_as->iommu),
+ TYPE_INTEL_IOMMU_MEMORY_REGION, OBJECT(s),
+ "intel_iommu_dmar",
UINT64_MAX);
memory_region_init_alias(&vtd_dev_as->sys_alias, OBJECT(s),
"vtd_sys_alias", get_system_memory(),
@@ -2736,7 +2737,8 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
memory_region_add_subregion_overlap(&vtd_dev_as->root, 0,
&vtd_dev_as->sys_alias, 1);
memory_region_add_subregion_overlap(&vtd_dev_as->root, 0,
- &vtd_dev_as->iommu, 1);
+ MEMORY_REGION(&vtd_dev_as->iommu),
+ 1);
vtd_switch_address_space(vtd_dev_as);
}
return vtd_dev_as;
@@ -2816,9 +2818,9 @@ static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private)
return 0;
}
-static void vtd_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n)
+static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
{
- VTDAddressSpace *vtd_as = container_of(mr, VTDAddressSpace, iommu);
+ VTDAddressSpace *vtd_as = container_of(iommu_mr, VTDAddressSpace, iommu);
IntelIOMMUState *s = vtd_as->iommu_state;
uint8_t bus_n = pci_bus_num(vtd_as->bus);
VTDContextEntry ce;
@@ -2856,9 +2858,6 @@ static void vtd_init(IntelIOMMUState *s)
memset(s->w1cmask, 0, DMAR_REG_SIZE);
memset(s->womask, 0, DMAR_REG_SIZE);
- s->iommu_ops.translate = vtd_iommu_translate;
- s->iommu_ops.notify_flag_changed = vtd_iommu_notify_flag_changed;
- s->iommu_ops.replay = vtd_iommu_replay;
s->root = 0;
s->root_extended = false;
s->dmar_enabled = false;
@@ -3073,9 +3072,26 @@ static const TypeInfo vtd_info = {
.class_init = vtd_class_init,
};
+static void vtd_iommu_memory_region_class_init(ObjectClass *klass,
+ void *data)
+{
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
+
+ imrc->translate = vtd_iommu_translate;
+ imrc->notify_flag_changed = vtd_iommu_notify_flag_changed;
+ imrc->replay = vtd_iommu_replay;
+}
+
+static const TypeInfo vtd_iommu_memory_region_info = {
+ .parent = TYPE_IOMMU_MEMORY_REGION,
+ .name = TYPE_INTEL_IOMMU_MEMORY_REGION,
+ .class_init = vtd_iommu_memory_region_class_init,
+};
+
static void vtd_register_types(void)
{
type_register_static(&vtd_info);
+ type_register_static(&vtd_iommu_memory_region_info);
}
type_init(vtd_register_types)
diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c
index 9f2615cbe0..33e20cb3e8 100644
--- a/hw/i386/kvm/pci-assign.c
+++ b/hw/i386/kvm/pci-assign.c
@@ -1353,9 +1353,9 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp)
PCI_CAP_ID_EXP);
return -EINVAL;
} else if (size != 0x3c) {
- error_report("WARNING, %s: PCIe cap-id 0x%x has "
- "non-standard size 0x%x; std size should be 0x3c",
- __func__, PCI_CAP_ID_EXP, size);
+ warn_report("%s: PCIe cap-id 0x%x has "
+ "non-standard size 0x%x; std size should be 0x3c",
+ __func__, PCI_CAP_ID_EXP, size);
}
} else if (version == 0) {
uint16_t vid, did;
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index 0d9ef77580..fc962c5fbc 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -383,8 +383,7 @@ static void patch_byte(X86CPU *cpu, target_ulong addr, uint8_t byte)
cpu_memory_rw_debug(CPU(cpu), addr, &byte, 1, 1);
}
-static void patch_call(VAPICROMState *s, X86CPU *cpu, target_ulong ip,
- uint32_t target)
+static void patch_call(X86CPU *cpu, target_ulong ip, uint32_t target)
{
uint32_t offset;
@@ -393,77 +392,71 @@ static void patch_call(VAPICROMState *s, X86CPU *cpu, target_ulong ip,
cpu_memory_rw_debug(CPU(cpu), ip + 1, (void *)&offset, sizeof(offset), 1);
}
-static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
+typedef struct PatchInfo {
+ VAPICHandlers *handler;
+ target_ulong ip;
+} PatchInfo;
+
+static void do_patch_instruction(CPUState *cs, run_on_cpu_data data)
{
- CPUState *cs = CPU(cpu);
- CPUX86State *env = &cpu->env;
- VAPICHandlers *handlers;
+ X86CPU *x86_cpu = X86_CPU(cs);
+ PatchInfo *info = (PatchInfo *) data.host_ptr;
+ VAPICHandlers *handlers = info->handler;
+ target_ulong ip = info->ip;
uint8_t opcode[2];
uint32_t imm32 = 0;
- target_ulong current_pc = 0;
- target_ulong current_cs_base = 0;
- uint32_t current_flags = 0;
-
- if (smp_cpus == 1) {
- handlers = &s->rom_state.up;
- } else {
- handlers = &s->rom_state.mp;
- }
-
- if (tcg_enabled()) {
- cpu_restore_state(cs, cs->mem_io_pc);
- cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
- &current_flags);
- /* Account this instruction, because we will exit the tb.
- This is the first instruction in the block. Therefore
- there is no need in restoring CPU state. */
- if (use_icount) {
- --cs->icount_decr.u16.low;
- }
- }
-
- pause_all_vcpus();
cpu_memory_rw_debug(cs, ip, opcode, sizeof(opcode), 0);
switch (opcode[0]) {
case 0x89: /* mov r32 to r/m32 */
- patch_byte(cpu, ip, 0x50 + modrm_reg(opcode[1])); /* push reg */
- patch_call(s, cpu, ip + 1, handlers->set_tpr);
+ patch_byte(x86_cpu, ip, 0x50 + modrm_reg(opcode[1])); /* push reg */
+ patch_call(x86_cpu, ip + 1, handlers->set_tpr);
break;
case 0x8b: /* mov r/m32 to r32 */
- patch_byte(cpu, ip, 0x90);
- patch_call(s, cpu, ip + 1, handlers->get_tpr[modrm_reg(opcode[1])]);
+ patch_byte(x86_cpu, ip, 0x90);
+ patch_call(x86_cpu, ip + 1, handlers->get_tpr[modrm_reg(opcode[1])]);
break;
case 0xa1: /* mov abs to eax */
- patch_call(s, cpu, ip, handlers->get_tpr[0]);
+ patch_call(x86_cpu, ip, handlers->get_tpr[0]);
break;
case 0xa3: /* mov eax to abs */
- patch_call(s, cpu, ip, handlers->set_tpr_eax);
+ patch_call(x86_cpu, ip, handlers->set_tpr_eax);
break;
case 0xc7: /* mov imm32, r/m32 (c7/0) */
- patch_byte(cpu, ip, 0x68); /* push imm32 */
+ patch_byte(x86_cpu, ip, 0x68); /* push imm32 */
cpu_memory_rw_debug(cs, ip + 6, (void *)&imm32, sizeof(imm32), 0);
cpu_memory_rw_debug(cs, ip + 1, (void *)&imm32, sizeof(imm32), 1);
- patch_call(s, cpu, ip + 5, handlers->set_tpr);
+ patch_call(x86_cpu, ip + 5, handlers->set_tpr);
break;
case 0xff: /* push r/m32 */
- patch_byte(cpu, ip, 0x50); /* push eax */
- patch_call(s, cpu, ip + 1, handlers->get_tpr_stack);
+ patch_byte(x86_cpu, ip, 0x50); /* push eax */
+ patch_call(x86_cpu, ip + 1, handlers->get_tpr_stack);
break;
default:
abort();
}
- resume_all_vcpus();
+ g_free(info);
+}
+
+static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
+{
+ CPUState *cs = CPU(cpu);
+ VAPICHandlers *handlers;
+ PatchInfo *info;
- if (tcg_enabled()) {
- /* Both tb_lock and iothread_mutex will be reset when
- * longjmps back into the cpu_exec loop. */
- tb_lock();
- tb_gen_code(cs, current_pc, current_cs_base, current_flags, 1);
- cpu_loop_exit_noexc(cs);
+ if (smp_cpus == 1) {
+ handlers = &s->rom_state.up;
+ } else {
+ handlers = &s->rom_state.mp;
}
+
+ info = g_new(PatchInfo, 1);
+ info->handler = handlers;
+ info->ip = ip;
+
+ async_safe_run_on_cpu(cs, do_patch_instruction, RUN_ON_CPU_HOST_PTR(info));
}
void vapic_report_tpr_access(DeviceState *dev, CPUState *cs, target_ulong ip,
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 224fe58fe7..22e16031b0 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -381,8 +381,8 @@ ISADevice *pc_find_fdc0(void)
}
if (state.multiple) {
- error_report("warning: multiple floppy disk controllers with "
- "iobase=0x3f0 have been found");
+ warn_report("multiple floppy disk controllers with "
+ "iobase=0x3f0 have been found");
error_printf("the one being picked for CMOS setup might not reflect "
"your intent\n");
}
@@ -1320,8 +1320,7 @@ void pc_acpi_init(const char *default_dsdt)
acpi_table_add_builtin(opts, &err);
if (err) {
- error_reportf_err(err, "WARNING: failed to load %s: ",
- filename);
+ warn_reportf_err(err, "failed to load %s: ", filename);
}
g_free(filename);
}
@@ -1444,7 +1443,6 @@ void pc_memory_init(PCMachineState *pcms,
option_rom_mr = g_malloc(sizeof(*option_rom_mr));
memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
&error_fatal);
- vmstate_register_ram_global(option_rom_mr);
memory_region_add_subregion_overlap(rom_memory,
PC_ROM_MIN_VGA,
option_rom_mr,
@@ -2087,9 +2085,9 @@ static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v,
}
if (value < (1ULL << 20)) {
- error_report("Warning: small max_ram_below_4g(%"PRIu64
- ") less than 1M. BIOS may not work..",
- value);
+ warn_report("small max_ram_below_4g(%"PRIu64
+ ") less than 1M. BIOS may not work..",
+ value);
}
pcms->max_ram_below_4g = value;
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 22dbef64c6..11b4336a42 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -131,10 +131,10 @@ static void pc_init1(MachineState *machine,
lowmem = 0xc0000000;
}
if (lowmem & ((1ULL << 30) - 1)) {
- error_report("Warning: Large machine and max_ram_below_4g "
- "(%" PRIu64 ") not a multiple of 1G; "
- "possible bad performance.",
- pcms->max_ram_below_4g);
+ warn_report("Large machine and max_ram_below_4g "
+ "(%" PRIu64 ") not a multiple of 1G; "
+ "possible bad performance.",
+ pcms->max_ram_below_4g);
}
}
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 8f696b7cb6..1653a47f0a 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -101,9 +101,9 @@ static void pc_q35_init(MachineState *machine)
lowmem = pcms->max_ram_below_4g;
if (machine->ram_size - lowmem > lowmem &&
lowmem & ((1ULL << 30) - 1)) {
- error_report("Warning: Large machine and max_ram_below_4g(%"PRIu64
- ") not a multiple of 1G; possible bad performance.",
- pcms->max_ram_below_4g);
+ warn_report("Large machine and max_ram_below_4g(%"PRIu64
+ ") not a multiple of 1G; possible bad performance.",
+ pcms->max_ram_below_4g);
}
}
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index f915ad0a36..6b183747fc 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -59,7 +59,6 @@ static void pc_isa_bios_init(MemoryRegion *rom_memory,
isa_bios = g_malloc(sizeof(*isa_bios));
memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size,
&error_fatal);
- vmstate_register_ram_global(isa_bios);
memory_region_add_subregion_overlap(rom_memory,
0x100000 - isa_bios_size,
isa_bios,
@@ -196,7 +195,6 @@ static void old_pc_system_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw)
}
bios = g_malloc(sizeof(*bios));
memory_region_init_ram(bios, NULL, "pc.bios", bios_size, &error_fatal);
- vmstate_register_ram_global(bios);
if (!isapc_ram_fw) {
memory_region_set_readonly(bios, true);
}
diff --git a/hw/i386/pci-assign-load-rom.c b/hw/i386/pci-assign-load-rom.c
index fd59076e7a..43429b66be 100644
--- a/hw/i386/pci-assign-load-rom.c
+++ b/hw/i386/pci-assign-load-rom.c
@@ -59,7 +59,7 @@ void *pci_assign_dev_load_option_rom(PCIDevice *dev, struct Object *owner,
fseek(fp, 0, SEEK_SET);
snprintf(name, sizeof(name), "%s.rom", object_get_typename(owner));
- memory_region_init_ram(&dev->rom, owner, name, st.st_size, &error_abort);
+ memory_region_init_ram_nomigrate(&dev->rom, owner, name, st.st_size, &error_abort);
vmstate_register_ram(&dev->rom, &dev->qdev);
ptr = memory_region_get_ram_ptr(&dev->rom);
memset(ptr, 0xff, st.st_size);
diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c
index cffa7e2017..3d951a3794 100644
--- a/hw/i386/xen/xen-hvm.c
+++ b/hw/i386/xen/xen-hvm.c
@@ -215,7 +215,6 @@ static void xen_ram_init(PCMachineState *pcms,
memory_region_init_ram(&ram_memory, NULL, "xen.ram", block_len,
&error_fatal);
*ram_memory_p = &ram_memory;
- vmstate_register_ram_global(&ram_memory);
memory_region_init_alias(&ram_640k, NULL, "xen.ram.640k",
&ram_memory, 0, 0xa0000);
diff --git a/hw/input/milkymist-softusb.c b/hw/input/milkymist-softusb.c
index 40dfca157f..ef8f47cd83 100644
--- a/hw/input/milkymist-softusb.c
+++ b/hw/input/milkymist-softusb.c
@@ -256,12 +256,12 @@ static int milkymist_softusb_init(SysBusDevice *dev)
sysbus_init_mmio(dev, &s->regs_region);
/* register pmem and dmem */
- memory_region_init_ram(&s->pmem, OBJECT(s), "milkymist-softusb.pmem",
+ memory_region_init_ram_nomigrate(&s->pmem, OBJECT(s), "milkymist-softusb.pmem",
s->pmem_size, &error_fatal);
vmstate_register_ram_global(&s->pmem);
s->pmem_ptr = memory_region_get_ram_ptr(&s->pmem);
sysbus_init_mmio(dev, &s->pmem);
- memory_region_init_ram(&s->dmem, OBJECT(s), "milkymist-softusb.dmem",
+ memory_region_init_ram_nomigrate(&s->dmem, OBJECT(s), "milkymist-softusb.dmem",
s->dmem_size, &error_fatal);
vmstate_register_ram_global(&s->dmem);
s->dmem_ptr = memory_region_get_ram_ptr(&s->dmem);
diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c
index 837158bdaf..6eaf178d79 100644
--- a/hw/intc/s390_flic.c
+++ b/hw/intc/s390_flic.c
@@ -13,8 +13,11 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "hw/sysbus.h"
+#include "hw/s390x/ioinst.h"
#include "hw/s390x/s390_flic.h"
+#include "hw/s390x/css.h"
#include "trace.h"
+#include "cpu.h"
#include "hw/qdev.h"
#include "qapi/error.h"
#include "hw/s390x/s390-virtio-ccw.h"
@@ -48,7 +51,7 @@ void s390_flic_init(void)
static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
uint8_t isc, bool swap,
- bool is_maskable)
+ bool is_maskable, uint8_t flags)
{
/* nothing to do */
return 0;
@@ -79,15 +82,91 @@ static int qemu_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
return -ENOSYS;
}
+static int qemu_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc,
+ uint16_t mode)
+{
+ QEMUS390FLICState *flic = QEMU_S390_FLIC(fs);
+
+ switch (mode) {
+ case SIC_IRQ_MODE_ALL:
+ flic->simm &= ~AIS_MODE_MASK(isc);
+ flic->nimm &= ~AIS_MODE_MASK(isc);
+ break;
+ case SIC_IRQ_MODE_SINGLE:
+ flic->simm |= AIS_MODE_MASK(isc);
+ flic->nimm &= ~AIS_MODE_MASK(isc);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int qemu_s390_inject_airq(S390FLICState *fs, uint8_t type,
+ uint8_t isc, uint8_t flags)
+{
+ QEMUS390FLICState *flic = QEMU_S390_FLIC(fs);
+ bool flag = flags & S390_ADAPTER_SUPPRESSIBLE;
+ uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;
+
+ if (flag && (flic->nimm & AIS_MODE_MASK(isc))) {
+ trace_qemu_s390_airq_suppressed(type, isc);
+ return 0;
+ }
+
+ s390_io_interrupt(0, 0, 0, io_int_word);
+
+ if (flag && (flic->simm & AIS_MODE_MASK(isc))) {
+ flic->nimm |= AIS_MODE_MASK(isc);
+ trace_qemu_s390_suppress_airq(isc, "Single-Interruption Mode",
+ "NO-Interruptions Mode");
+ }
+
+ return 0;
+}
+
+static void qemu_s390_flic_reset(DeviceState *dev)
+{
+ QEMUS390FLICState *flic = QEMU_S390_FLIC(dev);
+
+ flic->simm = 0;
+ flic->nimm = 0;
+}
+
+bool ais_needed(void *opaque)
+{
+ S390FLICState *s = opaque;
+
+ return s->ais_supported;
+}
+
+static const VMStateDescription qemu_s390_flic_vmstate = {
+ .name = "qemu-s390-flic",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = ais_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(simm, QEMUS390FLICState),
+ VMSTATE_UINT8(nimm, QEMUS390FLICState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
{
+ DeviceClass *dc = DEVICE_CLASS(oc);
S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
+ dc->reset = qemu_s390_flic_reset;
+ dc->vmsd = &qemu_s390_flic_vmstate;
fsc->register_io_adapter = qemu_s390_register_io_adapter;
fsc->io_adapter_map = qemu_s390_io_adapter_map;
fsc->add_adapter_routes = qemu_s390_add_adapter_routes;
fsc->release_adapter_routes = qemu_s390_release_adapter_routes;
fsc->clear_io_irq = qemu_s390_clear_io_flic;
+ fsc->modify_ais_mode = qemu_s390_modify_ais_mode;
+ fsc->inject_airq = qemu_s390_inject_airq;
}
static Property s390_flic_common_properties[] = {
@@ -98,12 +177,16 @@ static Property s390_flic_common_properties[] = {
static void s390_flic_common_realize(DeviceState *dev, Error **errp)
{
- uint32_t max_batch = S390_FLIC_COMMON(dev)->adapter_routes_max_batch;
+ S390FLICState *fs = S390_FLIC_COMMON(dev);
+ uint32_t max_batch = fs->adapter_routes_max_batch;
if (max_batch > ADAPTER_ROUTES_MAX_GSI) {
error_setg(errp, "flic property adapter_routes_max_batch too big"
" (%d > %d)", max_batch, ADAPTER_ROUTES_MAX_GSI);
+ return;
}
+
+ fs->ais_supported = s390_has_feat(S390_FEAT_ADAPTER_INT_SUPPRESSION);
}
static void s390_flic_class_init(ObjectClass *oc, void *data)
@@ -138,6 +221,22 @@ static void qemu_s390_flic_register_types(void)
type_init(qemu_s390_flic_register_types)
+static bool adapter_info_so_needed(void *opaque)
+{
+ return css_migration_enabled();
+}
+
+const VMStateDescription vmstate_adapter_info_so = {
+ .name = "s390_adapter_info/summary_offset",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = adapter_info_so_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(summary_offset, AdapterInfo),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
const VMStateDescription vmstate_adapter_info = {
.name = "s390_adapter_info",
.version_id = 1,
@@ -151,6 +250,10 @@ const VMStateDescription vmstate_adapter_info = {
*/
VMSTATE_END_OF_LIST()
},
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_adapter_info_so,
+ NULL
+ }
};
const VMStateDescription vmstate_adapter_routes = {
diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c
index 0bcd49f08b..be3fd00a57 100644
--- a/hw/intc/s390_flic_kvm.c
+++ b/hw/intc/s390_flic_kvm.c
@@ -20,6 +20,7 @@
#include "sysemu/kvm.h"
#include "hw/s390x/s390_flic.h"
#include "hw/s390x/adapter.h"
+#include "hw/s390x/css.h"
#include "trace.h"
#define FLIC_SAVE_INITIAL_SIZE getpagesize()
@@ -149,6 +150,43 @@ static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
return rc ? -errno : 0;
}
+static int kvm_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc,
+ uint16_t mode)
+{
+ KVMS390FLICState *flic = KVM_S390_FLIC(fs);
+ struct kvm_s390_ais_req req = {
+ .isc = isc,
+ .mode = mode,
+ };
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_AISM,
+ .addr = (uint64_t)&req,
+ };
+
+ if (!fs->ais_supported) {
+ return -ENOSYS;
+ }
+
+ return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
+}
+
+static int kvm_s390_inject_airq(S390FLICState *fs, uint8_t type,
+ uint8_t isc, uint8_t flags)
+{
+ KVMS390FLICState *flic = KVM_S390_FLIC(fs);
+ uint32_t id = css_get_adapter_id(type, isc);
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_AIRQ_INJECT,
+ .attr = id,
+ };
+
+ if (!fs->ais_supported) {
+ return -ENOSYS;
+ }
+
+ return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
+}
+
/**
* __get_all_irqs - store all pending irqs in buffer
* @flic: pointer to flic device state
@@ -186,13 +224,14 @@ static int __get_all_irqs(KVMS390FLICState *flic,
static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
uint8_t isc, bool swap,
- bool is_maskable)
+ bool is_maskable, uint8_t flags)
{
struct kvm_s390_io_adapter adapter = {
.id = id,
.isc = isc,
.maskable = is_maskable,
.swap = swap,
+ .flags = flags,
};
KVMS390FLICState *flic = KVM_S390_FLIC(fs);
int r;
@@ -374,7 +413,84 @@ out:
return r;
}
+typedef struct KVMS390FLICStateMigTmp {
+ KVMS390FLICState *parent;
+ uint8_t simm;
+ uint8_t nimm;
+} KVMS390FLICStateMigTmp;
+
+static void kvm_flic_ais_pre_save(void *opaque)
+{
+ KVMS390FLICStateMigTmp *tmp = opaque;
+ KVMS390FLICState *flic = tmp->parent;
+ struct kvm_s390_ais_all ais;
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_AISM_ALL,
+ .addr = (uint64_t)&ais,
+ .attr = sizeof(ais),
+ };
+
+ if (ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr)) {
+ error_report("Failed to retrieve kvm flic ais states");
+ return;
+ }
+
+ tmp->simm = ais.simm;
+ tmp->nimm = ais.nimm;
+}
+
+static int kvm_flic_ais_post_load(void *opaque, int version_id)
+{
+ KVMS390FLICStateMigTmp *tmp = opaque;
+ KVMS390FLICState *flic = tmp->parent;
+ struct kvm_s390_ais_all ais = {
+ .simm = tmp->simm,
+ .nimm = tmp->nimm,
+ };
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_AISM_ALL,
+ .addr = (uint64_t)&ais,
+ };
+
+ /* This can happen when the user mis-configures its guests in an
+ * incompatible fashion or without a CPU model. For example using
+ * qemu with -cpu host (which is not migration safe) and do a
+ * migration from a host that has AIS to a host that has no AIS.
+ * In that case the target system will reject the migration here.
+ */
+ if (!ais_needed(flic)) {
+ return -ENOSYS;
+ }
+
+ return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
+}
+
+static const VMStateDescription kvm_s390_flic_ais_tmp = {
+ .name = "s390-flic-ais-tmp",
+ .pre_save = kvm_flic_ais_pre_save,
+ .post_load = kvm_flic_ais_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(simm, KVMS390FLICStateMigTmp),
+ VMSTATE_UINT8(nimm, KVMS390FLICStateMigTmp),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription kvm_s390_flic_vmstate_ais = {
+ .name = "s390-flic/ais",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = ais_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_WITH_TMP(KVMS390FLICState, KVMS390FLICStateMigTmp,
+ kvm_s390_flic_ais_tmp),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription kvm_s390_flic_vmstate = {
+ /* should have been like kvm-s390-flic,
+ * can't change without breaking compat */
.name = "s390-flic",
.version_id = FLIC_SAVEVM_VERSION,
.minimum_version_id = FLIC_SAVEVM_VERSION,
@@ -389,6 +505,10 @@ static const VMStateDescription kvm_s390_flic_vmstate = {
.flags = VMS_SINGLE,
},
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * []) {
+ &kvm_s390_flic_vmstate_ais,
+ NULL
}
};
@@ -436,7 +556,6 @@ static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
test_attr.group = KVM_DEV_FLIC_CLEAR_IO_IRQ;
flic_state->clear_io_supported = !ioctl(flic_state->fd,
KVM_HAS_DEVICE_ATTR, test_attr);
-
return;
fail:
error_propagate(errp, errp_local);
@@ -445,10 +564,12 @@ fail:
static void kvm_s390_flic_reset(DeviceState *dev)
{
KVMS390FLICState *flic = KVM_S390_FLIC(dev);
+ S390FLICState *fs = S390_FLIC_COMMON(dev);
struct kvm_device_attr attr = {
.group = KVM_DEV_FLIC_CLEAR_IRQS,
};
int rc = 0;
+ uint8_t isc;
if (flic->fd == -1) {
return;
@@ -456,6 +577,16 @@ static void kvm_s390_flic_reset(DeviceState *dev)
flic_disable_wait_pfault(flic);
+ if (fs->ais_supported) {
+ for (isc = 0; isc <= MAX_ISC; isc++) {
+ rc = kvm_s390_modify_ais_mode(fs, isc, SIC_IRQ_MODE_ALL);
+ if (rc) {
+ error_report("Failed to reset ais mode for isc %d: %s",
+ isc, strerror(-rc));
+ }
+ }
+ }
+
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
if (rc) {
trace_flic_reset_failed(errno);
@@ -478,6 +609,8 @@ static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
fsc->clear_io_irq = kvm_s390_clear_io_flic;
+ fsc->modify_ais_mode = kvm_s390_modify_ais_mode;
+ fsc->inject_airq = kvm_s390_inject_airq;
}
static const TypeInfo kvm_s390_flic_info = {
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 729c1288f1..c586714d89 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -73,6 +73,10 @@ flic_create_device(int err) "flic: create device failed %d"
flic_no_device_api(int err) "flic: no Device Contral API support %d"
flic_reset_failed(int err) "flic: reset failed %d"
+# hw/intc/s390_flic.c
+qemu_s390_airq_suppressed(uint8_t type, uint8_t isc) "flic: adapter I/O interrupt suppressed (type %x isc %x)"
+qemu_s390_suppress_airq(uint8_t isc, const char *from, const char *to) "flic: for isc %x, suppress airq by modifying ais mode from %s to %s"
+
# hw/intc/aspeed_vic.c
aspeed_vic_set_irq(int irq, int level) "Enabling IRQ %d: %d"
aspeed_vic_update_fiq(int flags) "Raising FIQ: %d"
diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c
index afafe1400f..b27babd504 100644
--- a/hw/ipmi/ipmi.c
+++ b/hw/ipmi/ipmi.c
@@ -90,7 +90,7 @@ static TypeInfo ipmi_interface_type_info = {
.class_init = ipmi_interface_class_init,
};
-static void isa_ipmi_bmc_check(Object *obj, const char *name,
+static void isa_ipmi_bmc_check(const Object *obj, const char *name,
Object *val, Error **errp)
{
IPMIBmc *bmc = IPMI_BMC(val);
diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c
index 329b03e17f..abab3bba4f 100644
--- a/hw/ipmi/ipmi_bmc_extern.c
+++ b/hw/ipmi/ipmi_bmc_extern.c
@@ -447,13 +447,13 @@ static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp)
{
IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(dev);
- if (!qemu_chr_fe_get_driver(&ibe->chr)) {
+ if (!qemu_chr_fe_backend_connected(&ibe->chr)) {
error_setg(errp, "IPMI external bmc requires chardev attribute");
return;
}
qemu_chr_fe_set_handlers(&ibe->chr, can_receive, receive,
- chr_event, ibe, NULL, true);
+ chr_event, NULL, ibe, NULL, true);
}
static int ipmi_bmc_extern_post_migrate(void *opaque, int version_id)
diff --git a/hw/m68k/an5206.c b/hw/m68k/an5206.c
index 142bab98c9..c76244176f 100644
--- a/hw/m68k/an5206.c
+++ b/hw/m68k/an5206.c
@@ -61,7 +61,6 @@ static void an5206_init(MachineState *machine)
/* Internal SRAM. */
memory_region_init_ram(sram, NULL, "an5206.sram", 512, &error_fatal);
- vmstate_register_ram_global(sram);
memory_region_add_subregion(address_space_mem, AN5206_RAMBAR_ADDR, sram);
mcf5206_init(address_space_mem, AN5206_MBAR_ADDR, cpu);
diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c
index 656351834e..f4b1387c0d 100644
--- a/hw/m68k/mcf5208.c
+++ b/hw/m68k/mcf5208.c
@@ -249,7 +249,6 @@ static void mcf5208evb_init(MachineState *machine)
/* Internal SRAM. */
memory_region_init_ram(sram, NULL, "mcf5208.sram", 16384, &error_fatal);
- vmstate_register_ram_global(sram);
memory_region_add_subregion(address_space_mem, 0x80000000, sram);
/* Internal peripherals. */
diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c
index b72258e28f..ea67b461c2 100644
--- a/hw/mem/pc-dimm.c
+++ b/hw/mem/pc-dimm.c
@@ -350,6 +350,8 @@ static Property pc_dimm_properties[] = {
DEFINE_PROP_UINT32(PC_DIMM_NODE_PROP, PCDIMMDevice, node, 0),
DEFINE_PROP_INT32(PC_DIMM_SLOT_PROP, PCDIMMDevice, slot,
PC_DIMM_UNASSIGNED_SLOT),
+ DEFINE_PROP_LINK(PC_DIMM_MEMDEV_PROP, PCDIMMDevice, hostmem,
+ TYPE_MEMORY_BACKEND, HostMemoryBackend *),
DEFINE_PROP_END_OF_LIST(),
};
@@ -367,33 +369,10 @@ static void pc_dimm_get_size(Object *obj, Visitor *v, const char *name,
visit_type_uint64(v, name, &value, errp);
}
-static void pc_dimm_check_memdev_is_busy(Object *obj, const char *name,
- Object *val, Error **errp)
-{
- Error *local_err = NULL;
-
- if (host_memory_backend_is_mapped(MEMORY_BACKEND(val))) {
- char *path = object_get_canonical_path_component(val);
- error_setg(&local_err, "can't use already busy memdev: %s", path);
- g_free(path);
- } else {
- qdev_prop_allow_set_link_before_realize(obj, name, val, &local_err);
- }
-
- error_propagate(errp, local_err);
-}
-
static void pc_dimm_init(Object *obj)
{
- PCDIMMDevice *dimm = PC_DIMM(obj);
-
object_property_add(obj, PC_DIMM_SIZE_PROP, "uint64", pc_dimm_get_size,
NULL, NULL, NULL, &error_abort);
- object_property_add_link(obj, PC_DIMM_MEMDEV_PROP, TYPE_MEMORY_BACKEND,
- (Object **)&dimm->hostmem,
- pc_dimm_check_memdev_is_busy,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
}
static void pc_dimm_realize(DeviceState *dev, Error **errp)
@@ -404,6 +383,11 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp)
if (!dimm->hostmem) {
error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set");
return;
+ } else if (host_memory_backend_is_mapped(dimm->hostmem)) {
+ char *path = object_get_canonical_path_component(OBJECT(dimm->hostmem));
+ error_setg(errp, "can't use already busy memdev: %s", path);
+ g_free(path);
+ return;
}
if (((nb_numa_nodes > 0) && (dimm->node >= nb_numa_nodes)) ||
(!nb_numa_nodes && dimm->node)) {
diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c
index 4968bdbb28..b664dc0f9c 100644
--- a/hw/microblaze/petalogix_ml605_mmu.c
+++ b/hw/microblaze/petalogix_ml605_mmu.c
@@ -98,12 +98,10 @@ petalogix_ml605_init(MachineState *machine)
/* Attach emulated BRAM through the LMB. */
memory_region_init_ram(phys_lmb_bram, NULL, "petalogix_ml605.lmb_bram",
LMB_BRAM_SIZE, &error_fatal);
- vmstate_register_ram_global(phys_lmb_bram);
memory_region_add_subregion(address_space_mem, 0x00000000, phys_lmb_bram);
memory_region_init_ram(phys_ram, NULL, "petalogix_ml605.ram", ram_size,
&error_fatal);
- vmstate_register_ram_global(phys_ram);
memory_region_add_subregion(address_space_mem, MEMORY_BASEADDR, phys_ram);
dinfo = drive_get(IF_PFLASH, 0, 0);
diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c
index 423bcd7f6c..5cb4deb69e 100644
--- a/hw/microblaze/petalogix_s3adsp1800_mmu.c
+++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c
@@ -78,12 +78,10 @@ petalogix_s3adsp1800_init(MachineState *machine)
memory_region_init_ram(phys_lmb_bram, NULL,
"petalogix_s3adsp1800.lmb_bram", LMB_BRAM_SIZE,
&error_fatal);
- vmstate_register_ram_global(phys_lmb_bram);
memory_region_add_subregion(sysmem, 0x00000000, phys_lmb_bram);
memory_region_init_ram(phys_ram, NULL, "petalogix_s3adsp1800.ram",
ram_size, &error_fatal);
- vmstate_register_ram_global(phys_ram);
memory_region_add_subregion(sysmem, ddr_base, phys_ram);
dinfo = drive_get(IF_PFLASH, 0, 0);
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
index a4677f7da4..7985c60dde 100644
--- a/hw/mips/boston.c
+++ b/hw/mips/boston.c
@@ -484,7 +484,7 @@ static void boston_mach_init(MachineState *machine)
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s->cps), 0, 0, 1);
flash = g_new(MemoryRegion, 1);
- memory_region_init_rom_device(flash, NULL, &boston_flash_ops, s,
+ memory_region_init_rom_device_nomigrate(flash, NULL, &boston_flash_ops, s,
"boston.flash", 128 * M_BYTE, &err);
memory_region_add_subregion_overlap(sys_mem, 0x18000000, flash, 0);
@@ -533,7 +533,7 @@ static void boston_mach_init(MachineState *machine)
chr = qemu_chr_new("lcd", "vc:320x240");
qemu_chr_fe_init(&s->lcd_display, chr, NULL);
qemu_chr_fe_set_handlers(&s->lcd_display, NULL, NULL,
- boston_lcd_event, s, NULL, true);
+ boston_lcd_event, NULL, s, NULL, true);
ahci = pci_create_simple_multifunction(&PCI_BRIDGE(&pcie2->root)->sec_bus,
PCI_DEVFN(0, 0),
diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c
index dbe2805acb..3f3cb32651 100644
--- a/hw/mips/mips_fulong2e.c
+++ b/hw/mips/mips_fulong2e.c
@@ -296,7 +296,6 @@ static void mips_fulong2e_init(MachineState *machine)
memory_region_allocate_system_memory(ram, NULL, "fulong2e.ram", ram_size);
memory_region_init_ram(bios, NULL, "fulong2e.bios", bios_size,
&error_fatal);
- vmstate_register_ram_global(bios);
memory_region_set_readonly(bios, true);
memory_region_add_subregion(address_space_mem, 0, ram);
diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c
index 1cef581878..df2262a2a8 100644
--- a/hw/mips/mips_jazz.c
+++ b/hw/mips/mips_jazz.c
@@ -130,7 +130,7 @@ static void mips_jazz_init(MachineState *machine,
CPUMIPSState *env;
qemu_irq *i8259;
rc4030_dma *dmas;
- MemoryRegion *rc4030_dma_mr;
+ IOMMUMemoryRegion *rc4030_dma_mr;
MemoryRegion *isa_mem = g_new(MemoryRegion, 1);
MemoryRegion *isa_io = g_new(MemoryRegion, 1);
MemoryRegion *rtc = g_new(MemoryRegion, 1);
@@ -177,7 +177,6 @@ static void mips_jazz_init(MachineState *machine,
memory_region_init_ram(bios, NULL, "mips_jazz.bios", MAGNUM_BIOS_SIZE,
&error_fatal);
- vmstate_register_ram_global(bios);
memory_region_set_readonly(bios, true);
memory_region_init_alias(bios2, NULL, "mips_jazz.bios", bios,
0, MAGNUM_BIOS_SIZE);
@@ -244,7 +243,6 @@ static void mips_jazz_init(MachineState *machine,
MemoryRegion *rom_mr = g_new(MemoryRegion, 1);
memory_region_init_ram(rom_mr, NULL, "g364fb.rom", 0x80000,
&error_fatal);
- vmstate_register_ram_global(rom_mr);
memory_region_set_readonly(rom_mr, true);
uint8_t *rom = memory_region_get_ram_ptr(rom_mr);
memory_region_add_subregion(address_space, 0x60000000, rom_mr);
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index 95cdabb2dd..3487d16f61 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -570,7 +570,7 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
chr = qemu_chr_new("fpga", "vc:320x200");
qemu_chr_fe_init(&s->display, chr, NULL);
qemu_chr_fe_set_handlers(&s->display, NULL, NULL,
- malta_fgpa_display_event, s, NULL, true);
+ malta_fgpa_display_event, NULL, s, NULL, true);
s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
230400, uart_chr, DEVICE_NATIVE_ENDIAN);
@@ -841,8 +841,9 @@ static int64_t load_kernel (void)
if (loaderparams.initrd_filename) {
initrd_size = get_image_size (loaderparams.initrd_filename);
if (initrd_size > 0) {
- initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK;
- if (initrd_offset + initrd_size > ram_size) {
+ initrd_offset = (loaderparams.ram_low_size - initrd_size
+ - ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK;
+ if (kernel_high >= initrd_offset) {
fprintf(stderr,
"qemu: memory too small for initial ram disk '%s'\n",
loaderparams.initrd_filename);
@@ -1177,7 +1178,7 @@ void mips_malta_init(MachineState *machine)
* handled by an overlapping region as the resulting ROM code subpage
* regions are not executable.
*/
- memory_region_init_ram(bios_copy, NULL, "bios.1fc", BIOS_SIZE,
+ memory_region_init_ram_nomigrate(bios_copy, NULL, "bios.1fc", BIOS_SIZE,
&error_fatal);
if (!rom_copy(memory_region_get_ram_ptr(bios_copy),
FLASH_ADDRESS, BIOS_SIZE)) {
diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mips_mipssim.c
index 1b91195006..6990b1b0dd 100644
--- a/hw/mips/mips_mipssim.c
+++ b/hw/mips/mips_mipssim.c
@@ -179,7 +179,6 @@ mips_mipssim_init(MachineState *machine)
ram_size);
memory_region_init_ram(bios, NULL, "mips_mipssim.bios", BIOS_SIZE,
&error_fatal);
- vmstate_register_ram_global(bios);
memory_region_set_readonly(bios, true);
memory_region_add_subregion(address_space_mem, 0, ram);
diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c
index f4de9fc343..690874be2b 100644
--- a/hw/mips/mips_r4k.c
+++ b/hw/mips/mips_r4k.c
@@ -238,7 +238,6 @@ void mips_r4k_init(MachineState *machine)
bios = g_new(MemoryRegion, 1);
memory_region_init_ram(bios, NULL, "mips_r4k.bios", BIOS_SIZE,
&error_fatal);
- vmstate_register_ram_global(bios);
memory_region_set_readonly(bios, true);
memory_region_add_subregion(get_system_memory(), 0x1fc00000, bios);
diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
index 5f3ac0b6f6..f0b3053fae 100644
--- a/hw/misc/aspeed_sdmc.c
+++ b/hw/misc/aspeed_sdmc.c
@@ -157,8 +157,8 @@ static int ast2400_rambits(AspeedSDMCState *s)
}
/* use a common default */
- error_report("warning: Invalid RAM size 0x%" PRIx64
- ". Using default 256M", s->ram_size);
+ warn_report("Invalid RAM size 0x%" PRIx64 ". Using default 256M",
+ s->ram_size);
s->ram_size = 256 << 20;
return ASPEED_SDMC_DRAM_256MB;
}
@@ -179,8 +179,8 @@ static int ast2500_rambits(AspeedSDMCState *s)
}
/* use a common default */
- error_report("warning: Invalid RAM size 0x%" PRIx64
- ". Using default 512M", s->ram_size);
+ warn_report("Invalid RAM size 0x%" PRIx64 ". Using default 512M",
+ s->ram_size);
s->ram_size = 512 << 20;
return ASPEED_SDMC_AST2500_512MB;
}
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 2f0819d977..a58f9ee579 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -894,7 +894,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
}
qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive,
- ivshmem_read, NULL, s, NULL, true);
+ ivshmem_read, NULL, NULL, s, NULL, true);
if (ivshmem_setup_interrupts(s, errp) < 0) {
error_prepend(errp, "Failed to initialize interrupts: ");
@@ -1009,18 +1009,6 @@ static const TypeInfo ivshmem_common_info = {
.class_init = ivshmem_common_class_init,
};
-static void ivshmem_check_memdev_is_busy(Object *obj, const char *name,
- Object *val, Error **errp)
-{
- if (host_memory_backend_is_mapped(MEMORY_BACKEND(val))) {
- char *path = object_get_canonical_path_component(val);
- error_setg(errp, "can't use already busy memdev: %s", path);
- g_free(path);
- } else {
- qdev_prop_allow_set_link_before_realize(obj, name, val, errp);
- }
-}
-
static const VMStateDescription ivshmem_plain_vmsd = {
.name = TYPE_IVSHMEM_PLAIN,
.version_id = 0,
@@ -1037,6 +1025,8 @@ static const VMStateDescription ivshmem_plain_vmsd = {
static Property ivshmem_plain_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("master", IVShmemState, master, ON_OFF_AUTO_OFF),
+ DEFINE_PROP_LINK("memdev", IVShmemState, hostmem, TYPE_MEMORY_BACKEND,
+ HostMemoryBackend *),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1044,11 +1034,6 @@ static void ivshmem_plain_init(Object *obj)
{
IVShmemState *s = IVSHMEM_PLAIN(obj);
- object_property_add_link(obj, "memdev", TYPE_MEMORY_BACKEND,
- (Object **)&s->hostmem,
- ivshmem_check_memdev_is_busy,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
s->not_legacy_32bit = 1;
}
@@ -1059,6 +1044,11 @@ static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
if (!s->hostmem) {
error_setg(errp, "You must specify a 'memdev'");
return;
+ } else if (host_memory_backend_is_mapped(s->hostmem)) {
+ char *path = object_get_canonical_path_component(OBJECT(s->hostmem));
+ error_setg(errp, "can't use already busy memdev: %s", path);
+ g_free(path);
+ return;
}
ivshmem_common_realize(dev, errp);
@@ -1128,7 +1118,7 @@ static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp)
{
IVShmemState *s = IVSHMEM_COMMON(dev);
- if (!qemu_chr_fe_get_driver(&s->server_chr)) {
+ if (!qemu_chr_fe_backend_connected(&s->server_chr)) {
error_setg(errp, "You must specify a 'chardev'");
return;
}
@@ -1257,7 +1247,7 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp)
" or ivshmem-doorbell instead");
}
- if (!!qemu_chr_fe_get_driver(&s->server_chr) + !!s->shmobj != 1) {
+ if (qemu_chr_fe_backend_connected(&s->server_chr) + !!s->shmobj != 1) {
error_setg(errp, "You must specify either 'shm' or 'chardev'");
return;
}
diff --git a/hw/misc/mips_cmgcr.c b/hw/misc/mips_cmgcr.c
index a1edb53f95..211f6097fd 100644
--- a/hw/misc/mips_cmgcr.c
+++ b/hw/misc/mips_cmgcr.c
@@ -181,18 +181,6 @@ static void mips_gcr_init(Object *obj)
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
MIPSGCRState *s = MIPS_GCR(obj);
- object_property_add_link(obj, "gic", TYPE_MEMORY_REGION,
- (Object **)&s->gic_mr,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
-
- object_property_add_link(obj, "cpc", TYPE_MEMORY_REGION,
- (Object **)&s->cpc_mr,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &error_abort);
-
memory_region_init_io(&s->iomem, OBJECT(s), &gcr_ops, s,
"mips-gcr", GCR_ADDRSPACE_SZ);
sysbus_init_mmio(sbd, &s->iomem);
@@ -227,6 +215,10 @@ static Property mips_gcr_properties[] = {
DEFINE_PROP_INT32("num-vp", MIPSGCRState, num_vps, 1),
DEFINE_PROP_INT32("gcr-rev", MIPSGCRState, gcr_rev, 0x800),
DEFINE_PROP_UINT64("gcr-base", MIPSGCRState, gcr_base, GCR_BASE_ADDR),
+ DEFINE_PROP_LINK("gic", MIPSGCRState, gic_mr, TYPE_MEMORY_REGION,
+ MemoryRegion *),
+ DEFINE_PROP_LINK("cpc", MIPSGCRState, cpc_mr, TYPE_MEMORY_REGION,
+ MemoryRegion *),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c
index 3069834cf4..df3f1249ae 100644
--- a/hw/moxie/moxiesim.c
+++ b/hw/moxie/moxiesim.c
@@ -129,11 +129,9 @@ static void moxiesim_init(MachineState *machine)
/* Allocate RAM. */
memory_region_init_ram(ram, NULL, "moxiesim.ram", ram_size, &error_fatal);
- vmstate_register_ram_global(ram);
memory_region_add_subregion(address_space_mem, ram_base, ram);
- memory_region_init_ram(rom, NULL, "moxie.rom", 128*0x1000, &error_fatal);
- vmstate_register_ram_global(rom);
+ memory_region_init_ram(rom, NULL, "moxie.rom", 128 * 0x1000, &error_fatal);
memory_region_add_subregion(get_system_memory(), 0x1000, rom);
if (kernel_filename) {
diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index b53fcaa8bc..f2d2ce344c 100644
--- a/hw/net/dp8393x.c
+++ b/hw/net/dp8393x.c
@@ -887,7 +887,7 @@ static void dp8393x_realize(DeviceState *dev, Error **errp)
s->watchdog = timer_new_ns(QEMU_CLOCK_VIRTUAL, dp8393x_watchdog, s);
s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
- memory_region_init_ram(&s->prom, OBJECT(dev),
+ memory_region_init_ram_nomigrate(&s->prom, OBJECT(dev),
"dp8393x-prom", SONIC_PROM_SIZE, &local_err);
if (local_err) {
error_propagate(errp, local_err);
diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c
index c3a12e1197..3eaa19dfde 100644
--- a/hw/net/milkymist-minimac2.c
+++ b/hw/net/milkymist-minimac2.c
@@ -466,7 +466,7 @@ static int milkymist_minimac2_init(SysBusDevice *sbd)
sysbus_init_mmio(sbd, &s->regs_region);
/* register buffers memory */
- memory_region_init_ram(&s->buffers, OBJECT(dev), "milkymist-minimac2.buffers",
+ memory_region_init_ram_nomigrate(&s->buffers, OBJECT(dev), "milkymist-minimac2.buffers",
buffers_size, &error_fatal);
vmstate_register_ram_global(&s->buffers);
s->rx0_buf = memory_region_get_ram_ptr(&s->buffers);
diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c
index b6701844d3..5ffa739f68 100644
--- a/hw/net/xilinx_axienet.c
+++ b/hw/net/xilinx_axienet.c
@@ -981,9 +981,7 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp)
return;
xilinx_enet_realize_fail:
- if (!*errp) {
- *errp = local_err;
- }
+ error_propagate(errp, local_err);
}
static void xilinx_enet_init(Object *obj)
diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c
index 051be73e9a..b6868b8233 100644
--- a/hw/nios2/10m50_devboard.c
+++ b/hw/nios2/10m50_devboard.c
@@ -57,19 +57,19 @@ static void nios2_10m50_ghrd_init(MachineState *machine)
int i;
/* Physical TCM (tb_ram_1k) with alias at 0xc0000000 */
- memory_region_init_ram(phys_tcm, NULL, "nios2.tcm", tcm_size, &error_abort);
+ memory_region_init_ram(phys_tcm, NULL, "nios2.tcm", tcm_size,
+ &error_abort);
memory_region_init_alias(phys_tcm_alias, NULL, "nios2.tcm.alias",
phys_tcm, 0, tcm_size);
- vmstate_register_ram_global(phys_tcm);
memory_region_add_subregion(address_space_mem, tcm_base, phys_tcm);
memory_region_add_subregion(address_space_mem, 0xc0000000 + tcm_base,
phys_tcm_alias);
/* Physical DRAM with alias at 0xc0000000 */
- memory_region_init_ram(phys_ram, NULL, "nios2.ram", ram_size, &error_abort);
+ memory_region_init_ram(phys_ram, NULL, "nios2.ram", ram_size,
+ &error_abort);
memory_region_init_alias(phys_ram_alias, NULL, "nios2.ram.alias",
phys_ram, 0, ram_size);
- vmstate_register_ram_global(phys_ram);
memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
memory_region_add_subregion(address_space_mem, 0xc0000000 + ram_base,
phys_ram_alias);
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 99bdbc2233..e881e3b812 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -781,7 +781,7 @@ static int get_fw_cfg_order(FWCfgState *s, const char *name)
}
/* Stick unknown stuff at the end. */
- error_report("warning: Unknown firmware file in legacy mode: %s", name);
+ warn_report("Unknown firmware file in legacy mode: %s", name);
return FW_CFG_ORDER_OVERRIDE_LAST;
}
diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c
index fc0d0967b7..e1eeffc490 100644
--- a/hw/openrisc/openrisc_sim.c
+++ b/hw/openrisc/openrisc_sim.c
@@ -120,7 +120,6 @@ static void openrisc_sim_init(MachineState *machine)
ram = g_malloc(sizeof(*ram));
memory_region_init_ram(ram, NULL, "openrisc.ram", ram_size, &error_fatal);
- vmstate_register_ram_global(ram);
memory_region_add_subregion(get_system_memory(), 0, ram);
cpu_openrisc_pic_init(cpu);
diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c
index 326f5ef024..96e5d0b60d 100644
--- a/hw/pci-host/apb.c
+++ b/hw/pci-host/apb.c
@@ -123,7 +123,7 @@ do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0)
typedef struct IOMMUState {
AddressSpace iommu_as;
- MemoryRegion iommu;
+ IOMMUMemoryRegion iommu;
uint64_t regs[IOMMU_NREGS];
} IOMMUState;
@@ -133,6 +133,8 @@ typedef struct IOMMUState {
#define APB_DEVICE(obj) \
OBJECT_CHECK(APBState, (obj), TYPE_APB)
+#define TYPE_APB_IOMMU_MEMORY_REGION "pbm-iommu-memory-region"
+
typedef struct APBState {
PCIHostState parent_obj;
@@ -208,7 +210,7 @@ static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
}
/* Called from RCU critical section */
-static IOMMUTLBEntry pbm_translate_iommu(MemoryRegion *iommu, hwaddr addr,
+static IOMMUTLBEntry pbm_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag)
{
IOMMUState *is = container_of(iommu, IOMMUState, iommu);
@@ -322,10 +324,6 @@ static IOMMUTLBEntry pbm_translate_iommu(MemoryRegion *iommu, hwaddr addr,
return ret;
}
-static MemoryRegionIOMMUOps pbm_iommu_ops = {
- .translate = pbm_translate_iommu,
-};
-
static void iommu_config_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
@@ -697,9 +695,10 @@ PCIBus *pci_apb_init(hwaddr special_base,
is = &d->iommu;
memset(is, 0, sizeof(IOMMUState));
- memory_region_init_iommu(&is->iommu, OBJECT(dev), &pbm_iommu_ops,
+ memory_region_init_iommu(&is->iommu, sizeof(is->iommu),
+ TYPE_APB_IOMMU_MEMORY_REGION, OBJECT(dev),
"iommu-apb", UINT64_MAX);
- address_space_init(&is->iommu_as, &is->iommu, "pbm-as");
+ address_space_init(&is->iommu_as, MEMORY_REGION(&is->iommu), "pbm-as");
pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is);
/* APB secondary busses */
@@ -860,11 +859,25 @@ static const TypeInfo pbm_pci_bridge_info = {
.class_init = pbm_pci_bridge_class_init,
};
+static void pbm_iommu_memory_region_class_init(ObjectClass *klass, void *data)
+{
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
+
+ imrc->translate = pbm_translate_iommu;
+}
+
+static const TypeInfo pbm_iommu_memory_region_info = {
+ .parent = TYPE_IOMMU_MEMORY_REGION,
+ .name = TYPE_APB_IOMMU_MEMORY_REGION,
+ .class_init = pbm_iommu_memory_region_class_init,
+};
+
static void pbm_register_types(void)
{
type_register_static(&pbm_host_info);
type_register_static(&pbm_pci_host_info);
type_register_static(&pbm_pci_bridge_info);
+ type_register_static(&pbm_iommu_memory_region_info);
}
type_init(pbm_register_types)
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index a2c1033dbe..072a04e318 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -307,7 +307,7 @@ static void i440fx_realize(PCIDevice *dev, Error **errp)
dev->config[I440FX_SMRAM] = 0x02;
if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) {
- error_report("warning: i440fx doesn't support emulated iommu");
+ warn_report("i440fx doesn't support emulated iommu");
}
}
diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c
index 900a6edfcf..8b293ba0f1 100644
--- a/hw/pci-host/prep.c
+++ b/hw/pci-host/prep.c
@@ -304,7 +304,7 @@ static void raven_realize(PCIDevice *d, Error **errp)
d->config[0x0D] = 0x10; // latency_timer
d->config[0x34] = 0x00; // capabilities_pointer
- memory_region_init_ram(&s->bios, OBJECT(s), "bios", BIOS_SIZE,
+ memory_region_init_ram_nomigrate(&s->bios, OBJECT(s), "bios", BIOS_SIZE,
&error_fatal);
memory_region_set_readonly(&s->bios, true);
memory_region_add_subregion(get_system_memory(), (uint32_t)(-BIOS_SIZE),
diff --git a/hw/pci-host/xilinx-pcie.c b/hw/pci-host/xilinx-pcie.c
index 2c78dcfc26..4613dda1d2 100644
--- a/hw/pci-host/xilinx-pcie.c
+++ b/hw/pci-host/xilinx-pcie.c
@@ -120,7 +120,7 @@ static void xilinx_pcie_host_realize(DeviceState *dev, Error **errp)
memory_region_set_enabled(&s->mmio, false);
/* dummy I/O region */
- memory_region_init_ram(&s->io, OBJECT(s), "io", 16, NULL);
+ memory_region_init_ram_nomigrate(&s->io, OBJECT(s), "io", 16, NULL);
memory_region_set_enabled(&s->io, false);
/* interrupt out */
diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c
index 36d2c430c5..ecad664946 100644
--- a/hw/pci/pci-stub.c
+++ b/hw/pci/pci-stub.c
@@ -24,6 +24,9 @@
#include "qapi/qmp/qerror.h"
#include "hw/pci/pci.h"
#include "qmp-commands.h"
+#include "hw/pci/msi.h"
+
+bool msi_nonbroken;
PciInfoList *qmp_query_pci(Error **errp)
{
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 0c6f74a347..258fbe51e2 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -2236,7 +2236,6 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom,
}
pdev->has_rom = true;
memory_region_init_rom(&pdev->rom, OBJECT(pdev), name, size, &error_fatal);
- vmstate_register_ram(&pdev->rom, &pdev->qdev);
ptr = memory_region_get_ram_ptr(&pdev->rom);
load_image(path, ptr);
g_free(path);
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index bae1c0ac99..3056d5f075 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -206,7 +206,6 @@ static void ppc_core99_init(MachineState *machine)
/* allocate and load BIOS */
memory_region_init_ram(bios, NULL, "ppc_core99.bios", BIOS_SIZE,
&error_fatal);
- vmstate_register_ram_global(bios);
if (bios_name == NULL)
bios_name = PROM_FILENAME;
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 97bb8541d7..f2ae60a360 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -143,7 +143,6 @@ static void ppc_heathrow_init(MachineState *machine)
/* allocate and load BIOS */
memory_region_init_ram(bios, NULL, "ppc_heathrow.bios", BIOS_SIZE,
&error_fatal);
- vmstate_register_ram_global(bios);
if (bios_name == NULL)
bios_name = PROM_FILENAME;
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index a4cd733cba..47221158d4 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -160,13 +160,13 @@ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
_FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
pcc->l1_dcache_size)));
} else {
- error_report("Warning: Unknown L1 dcache size for cpu");
+ warn_report("Unknown L1 dcache size for cpu");
}
if (pcc->l1_icache_size) {
_FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
pcc->l1_icache_size)));
} else {
- error_report("Warning: Unknown L1 icache size for cpu");
+ warn_report("Unknown L1 icache size for cpu");
}
_FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
@@ -556,7 +556,7 @@ static void ppc_powernv_init(MachineState *machine)
/* allocate RAM */
if (machine->ram_size < (1 * G_BYTE)) {
- error_report("Warning: skiboot may not work with < 1GB of RAM");
+ warn_report("skiboot may not work with < 1GB of RAM");
}
ram = g_new(MemoryRegion, 1);
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
index d01798f245..e92db2c66a 100644
--- a/hw/ppc/ppc405_boards.c
+++ b/hw/ppc/ppc405_boards.c
@@ -220,7 +220,6 @@ static void ref405ep_init(MachineState *machine)
sram_size = 512 * 1024;
memory_region_init_ram(sram, NULL, "ef405ep.sram", sram_size,
&error_fatal);
- vmstate_register_ram_global(sram);
memory_region_add_subregion(sysmem, 0xFFF00000, sram);
/* allocate and load BIOS */
#ifdef DEBUG_BOARD_INIT
@@ -255,7 +254,6 @@ static void ref405ep_init(MachineState *machine)
bios = g_new(MemoryRegion, 1);
memory_region_init_ram(bios, NULL, "ef405ep.bios", BIOS_SIZE,
&error_fatal);
- vmstate_register_ram_global(bios);
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
@@ -556,7 +554,6 @@ static void taihu_405ep_init(MachineState *machine)
bios = g_new(MemoryRegion, 1);
memory_region_init_ram(bios, NULL, "taihu_405ep.bios", BIOS_SIZE,
&error_fatal);
- vmstate_register_ram_global(bios);
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (filename) {
bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
index fc32e96bf4..f6fe3e6f5e 100644
--- a/hw/ppc/ppc405_uc.c
+++ b/hw/ppc/ppc405_uc.c
@@ -980,7 +980,6 @@ static void ppc405_ocm_init(CPUPPCState *env)
/* XXX: Size is 4096 or 0x04000000 */
memory_region_init_ram(&ocm->isarc_ram, NULL, "ppc405.ocm", 4096,
&error_fatal);
- vmstate_register_ram_global(&ocm->isarc_ram);
memory_region_init_alias(&ocm->dsarc_ram, NULL, "ppc405.dsarc", &ocm->isarc_ram,
0, 4096);
qemu_register_reset(&ocm_reset, ocm);
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index d38563d9a4..970093e6b5 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -98,8 +98,6 @@
#define PHANDLE_XICP 0x00001111
-#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
-
static ICSState *spapr_ics_create(sPAPRMachineState *spapr,
const char *type_ics,
int nr_irqs, Error **errp)
@@ -534,13 +532,13 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
_FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
pcc->l1_dcache_size)));
} else {
- error_report("Warning: Unknown L1 dcache size for cpu");
+ warn_report("Unknown L1 dcache size for cpu");
}
if (pcc->l1_icache_size) {
_FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
pcc->l1_icache_size)));
} else {
- error_report("Warning: Unknown L1 icache size for cpu");
+ warn_report("Unknown L1 icache size for cpu");
}
_FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
@@ -874,6 +872,11 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt)
if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
add_str(hypertas, "hcall-multi-tce");
}
+
+ if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
+ add_str(hypertas, "hcall-hpt-resize");
+ }
+
_FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions",
hypertas->str, hypertas->len));
g_string_free(hypertas, TRUE);
@@ -1264,7 +1267,7 @@ static void spapr_store_hpte(PPCVirtualHypervisor *vhyp, hwaddr ptex,
}
}
-static int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
+int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
{
int shift;
@@ -1285,8 +1288,8 @@ void spapr_free_hpt(sPAPRMachineState *spapr)
close_htab_fd(spapr);
}
-static void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
- Error **errp)
+void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
+ Error **errp)
{
long rc;
@@ -1334,9 +1337,17 @@ static void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
void spapr_setup_hpt_and_vrma(sPAPRMachineState *spapr)
{
- spapr_reallocate_hpt(spapr,
- spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size),
- &error_fatal);
+ int hpt_shift;
+
+ if ((spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED)
+ || (spapr->cas_reboot
+ && !spapr_ovec_test(spapr->ov5_cas, OV5_HPT_RESIZE))) {
+ hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size);
+ } else {
+ hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->ram_size);
+ }
+ spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
+
if (spapr->vrma_adjust) {
spapr->rma_size = kvmppc_rma_size(spapr_node0_size(),
spapr->htab_shift);
@@ -1517,6 +1528,37 @@ static bool version_before_3(void *opaque, int version_id)
return version_id < 3;
}
+static bool spapr_pending_events_needed(void *opaque)
+{
+ sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
+ return !QTAILQ_EMPTY(&spapr->pending_events);
+}
+
+static const VMStateDescription vmstate_spapr_event_entry = {
+ .name = "spapr_event_log_entry",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(summary, sPAPREventLogEntry),
+ VMSTATE_UINT32(extended_length, sPAPREventLogEntry),
+ VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, sPAPREventLogEntry, 0,
+ NULL, extended_length),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const VMStateDescription vmstate_spapr_pending_events = {
+ .name = "spapr_pending_events",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = spapr_pending_events_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_QTAILQ_V(pending_events, sPAPRMachineState, 1,
+ vmstate_spapr_event_entry, sPAPREventLogEntry, next),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static bool spapr_ov5_cas_needed(void *opaque)
{
sPAPRMachineState *spapr = opaque;
@@ -1615,6 +1657,7 @@ static const VMStateDescription vmstate_spapr = {
.subsections = (const VMStateDescription*[]) {
&vmstate_spapr_ov5_cas,
&vmstate_spapr_patb_entry,
+ &vmstate_spapr_pending_events,
NULL
}
};
@@ -2116,12 +2159,41 @@ static void ppc_spapr_init(MachineState *machine)
hwaddr node0_size = spapr_node0_size();
long load_limit, fw_size;
char *filename;
+ Error *resize_hpt_err = NULL;
msi_nonbroken = true;
QLIST_INIT(&spapr->phbs);
QTAILQ_INIT(&spapr->pending_dimm_unplugs);
+ /* Check HPT resizing availability */
+ kvmppc_check_papr_resize_hpt(&resize_hpt_err);
+ if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) {
+ /*
+ * If the user explicitly requested a mode we should either
+ * supply it, or fail completely (which we do below). But if
+ * it's not set explicitly, we reset our mode to something
+ * that works
+ */
+ if (resize_hpt_err) {
+ spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
+ error_free(resize_hpt_err);
+ resize_hpt_err = NULL;
+ } else {
+ spapr->resize_hpt = smc->resize_hpt_default;
+ }
+ }
+
+ assert(spapr->resize_hpt != SPAPR_RESIZE_HPT_DEFAULT);
+
+ if ((spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) && resize_hpt_err) {
+ /*
+ * User requested HPT resize, but this host can't supply it. Bail out
+ */
+ error_report_err(resize_hpt_err);
+ exit(1);
+ }
+
/* Allocate RMA if necessary */
rma_alloc_size = kvmppc_alloc_rma(&rma);
@@ -2190,6 +2262,11 @@ static void ppc_spapr_init(MachineState *machine)
spapr_ovec_set(spapr->ov5, OV5_HP_EVT);
}
+ /* advertise support for HPT resizing */
+ if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
+ spapr_ovec_set(spapr->ov5, OV5_HPT_RESIZE);
+ }
+
/* init CPUs */
if (machine->cpu_model == NULL) {
machine->cpu_model = kvm_enabled() ? "host" : smc->tcg_default_cpu;
@@ -2547,6 +2624,40 @@ static void spapr_set_modern_hotplug_events(Object *obj, bool value,
spapr->use_hotplug_event_source = value;
}
+static char *spapr_get_resize_hpt(Object *obj, Error **errp)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+
+ switch (spapr->resize_hpt) {
+ case SPAPR_RESIZE_HPT_DEFAULT:
+ return g_strdup("default");
+ case SPAPR_RESIZE_HPT_DISABLED:
+ return g_strdup("disabled");
+ case SPAPR_RESIZE_HPT_ENABLED:
+ return g_strdup("enabled");
+ case SPAPR_RESIZE_HPT_REQUIRED:
+ return g_strdup("required");
+ }
+ g_assert_not_reached();
+}
+
+static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+
+ if (strcmp(value, "default") == 0) {
+ spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT;
+ } else if (strcmp(value, "disabled") == 0) {
+ spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
+ } else if (strcmp(value, "enabled") == 0) {
+ spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED;
+ } else if (strcmp(value, "required") == 0) {
+ spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED;
+ } else {
+ error_setg(errp, "Bad value for \"resize-hpt\" property");
+ }
+}
+
static void spapr_machine_initfn(Object *obj)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
@@ -2571,6 +2682,12 @@ static void spapr_machine_initfn(Object *obj)
ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr,
"Maximum permitted CPU compatibility mode",
&error_fatal);
+
+ object_property_add_str(obj, "resize-hpt",
+ spapr_get_resize_hpt, spapr_set_resize_hpt, NULL);
+ object_property_set_description(obj, "resize-hpt",
+ "Resizing of the Hash Page Table (enabled, disabled, required)",
+ NULL);
}
static void spapr_machine_finalizefn(Object *obj)
@@ -2604,6 +2721,7 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
int i, fdt_offset, fdt_size;
void *fdt;
uint64_t addr = addr_start;
+ bool hotplugged = spapr_drc_hotplugged(dev);
Error *local_err = NULL;
for (i = 0; i < nr_lmbs; i++) {
@@ -2621,18 +2739,21 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
addr -= SPAPR_MEMORY_BLOCK_SIZE;
drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
addr / SPAPR_MEMORY_BLOCK_SIZE);
- spapr_drc_detach(drc, dev, NULL);
+ spapr_drc_detach(drc);
}
g_free(fdt);
error_propagate(errp, local_err);
return;
}
+ if (!hotplugged) {
+ spapr_drc_reset(drc);
+ }
addr += SPAPR_MEMORY_BLOCK_SIZE;
}
/* send hotplug notification to the
* guest only in case of hotplugged memory
*/
- if (dev->hotplugged) {
+ if (hotplugged) {
if (dedicated_hp_event_source) {
drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
addr_start / SPAPR_MEMORY_BLOCK_SIZE);
@@ -2780,8 +2901,10 @@ static sPAPRDIMMState *spapr_recover_pending_dimm_state(sPAPRMachineState *ms,
/* Callback to be called during DRC release. */
void spapr_lmb_release(DeviceState *dev)
{
- HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
- sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl);
+ sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_hotplug_handler(dev));
+ PCDIMMDevice *dimm = PC_DIMM(dev);
+ PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
+ MemoryRegion *mr = ddc->get_memory_region(dimm);
sPAPRDIMMState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
/* This information will get lost if a migration occurs
@@ -2802,18 +2925,7 @@ void spapr_lmb_release(DeviceState *dev)
* Now that all the LMBs have been removed by the guest, call the
* pc-dimm unplug handler to cleanup up the pc-dimm device.
*/
- hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
-}
-
-static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
-{
- sPAPRMachineState *ms = SPAPR_MACHINE(hotplug_dev);
- PCDIMMDevice *dimm = PC_DIMM(dev);
- PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
- MemoryRegion *mr = ddc->get_memory_region(dimm);
-
- pc_dimm_memory_unplug(dev, &ms->hotplug_memory, mr);
+ pc_dimm_memory_unplug(dev, &spapr->hotplug_memory, mr);
object_unparent(OBJECT(dev));
}
@@ -2849,7 +2961,7 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
addr / SPAPR_MEMORY_BLOCK_SIZE);
g_assert(drc);
- spapr_drc_detach(drc, dev, errp);
+ spapr_drc_detach(drc);
addr += SPAPR_MEMORY_BLOCK_SIZE;
}
@@ -2882,10 +2994,10 @@ static void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
return fdt;
}
-static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
+/* Callback to be called during DRC release. */
+void spapr_core_release(DeviceState *dev)
{
- MachineState *ms = MACHINE(qdev_get_machine());
+ MachineState *ms = MACHINE(qdev_get_hotplug_handler(dev));
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
CPUCore *cc = CPU_CORE(dev);
CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
@@ -2909,22 +3021,12 @@ static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
object_unparent(OBJECT(dev));
}
-/* Callback to be called during DRC release. */
-void spapr_core_release(DeviceState *dev)
-{
- HotplugHandler *hotplug_ctrl;
-
- hotplug_ctrl = qdev_get_hotplug_handler(dev);
- hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
-}
-
static
void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
int index;
sPAPRDRConnector *drc;
- Error *local_err = NULL;
CPUCore *cc = CPU_CORE(dev);
int smt = kvmppc_smt_threads();
@@ -2941,11 +3043,7 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index * smt);
g_assert(drc);
- spapr_drc_detach(drc, dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
+ spapr_drc_detach(drc);
spapr_hotplug_req_remove_by_index(drc);
}
@@ -2961,11 +3059,10 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
CPUState *cs = CPU(core->threads);
sPAPRDRConnector *drc;
Error *local_err = NULL;
- void *fdt = NULL;
- int fdt_offset = 0;
int smt = kvmppc_smt_threads();
CPUArchId *core_slot;
int index;
+ bool hotplugged = spapr_drc_hotplugged(dev);
core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
if (!core_slot) {
@@ -2977,24 +3074,30 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
g_assert(drc || !mc->has_hotpluggable_cpus);
- fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr);
-
if (drc) {
+ void *fdt;
+ int fdt_offset;
+
+ fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr);
+
spapr_drc_attach(drc, dev, fdt, fdt_offset, &local_err);
if (local_err) {
g_free(fdt);
error_propagate(errp, local_err);
return;
}
- }
- if (dev->hotplugged) {
- /*
- * Send hotplug notification interrupt to the guest only in case
- * of hotplugged CPUs.
- */
- spapr_hotplug_req_add_by_index(drc);
+ if (hotplugged) {
+ /*
+ * Send hotplug notification interrupt to the guest only
+ * in case of hotplugged CPUs.
+ */
+ spapr_hotplug_req_add_by_index(drc);
+ } else {
+ spapr_drc_reset(drc);
+ }
}
+
core_slot->cpu = OBJECT(dev);
if (smc->pre_2_10_has_unused_icps) {
@@ -3047,9 +3150,9 @@ static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
* total vcpus not a multiple of threads-per-core.
*/
if (mc->has_hotpluggable_cpus && (cc->nr_threads != smp_threads)) {
- error_setg(errp, "invalid nr-threads %d, must be %d",
+ error_setg(&local_err, "invalid nr-threads %d, must be %d",
cc->nr_threads, smp_threads);
- return;
+ goto out;
}
core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
@@ -3119,27 +3222,6 @@ static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
}
}
-static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- sPAPRMachineState *sms = SPAPR_MACHINE(qdev_get_machine());
- MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
-
- if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) {
- spapr_memory_unplug(hotplug_dev, dev, errp);
- } else {
- error_setg(errp, "Memory hot unplug not supported for this guest");
- }
- } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
- if (!mc->has_hotpluggable_cpus) {
- error_setg(errp, "CPU hot unplug not supported on this machine");
- return;
- }
- spapr_core_unplug(hotplug_dev, dev, errp);
- }
-}
-
static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
@@ -3357,7 +3439,6 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
mc->get_hotplug_handler = spapr_get_hotplug_handler;
hc->pre_plug = spapr_machine_device_pre_plug;
hc->plug = spapr_machine_device_plug;
- hc->unplug = spapr_machine_device_unplug;
mc->cpu_index_to_instance_props = spapr_cpu_index_to_props;
mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids;
hc->unplug_request = spapr_machine_device_unplug_request;
@@ -3365,6 +3446,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
smc->dr_lmb_enabled = true;
smc->tcg_default_cpu = "POWER8";
mc->has_hotpluggable_cpus = true;
+ smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
fwc->get_dev_path = spapr_get_fw_dev_path;
nc->nmi_monitor_handler = spapr_nmi;
smc->phb_placement = spapr_phb_placement;
@@ -3471,6 +3553,7 @@ static void spapr_machine_2_9_class_options(MachineClass *mc)
SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_9);
mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
smc->pre_2_10_has_unused_icps = true;
+ smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
}
DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index f34355dad1..0ffcec6fb2 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -48,40 +48,40 @@ uint32_t spapr_drc_index(sPAPRDRConnector *drc)
static uint32_t drc_isolate_physical(sPAPRDRConnector *drc)
{
- /* if the guest is configuring a device attached to this DRC, we
- * should reset the configuration state at this point since it may
- * no longer be reliable (guest released device and needs to start
- * over, or unplug occurred so the FDT is no longer valid)
- */
- g_free(drc->ccs);
- drc->ccs = NULL;
+ switch (drc->state) {
+ case SPAPR_DRC_STATE_PHYSICAL_POWERON:
+ return RTAS_OUT_SUCCESS; /* Nothing to do */
+ case SPAPR_DRC_STATE_PHYSICAL_CONFIGURED:
+ break; /* see below */
+ case SPAPR_DRC_STATE_PHYSICAL_UNISOLATE:
+ return RTAS_OUT_PARAM_ERROR; /* not allowed */
+ default:
+ g_assert_not_reached();
+ }
- drc->isolation_state = SPAPR_DR_ISOLATION_STATE_ISOLATED;
+ drc->state = SPAPR_DRC_STATE_PHYSICAL_POWERON;
- /* if we're awaiting release, but still in an unconfigured state,
- * it's likely the guest is still in the process of configuring
- * the device and is transitioning the devices to an ISOLATED
- * state as a part of that process. so we only complete the
- * removal when this transition happens for a device in a
- * configured state, as suggested by the state diagram from PAPR+
- * 2.7, 13.4
- */
- if (drc->awaiting_release) {
+ if (drc->unplug_requested) {
uint32_t drc_index = spapr_drc_index(drc);
- if (drc->configured) {
- trace_spapr_drc_set_isolation_state_finalizing(drc_index);
- spapr_drc_detach(drc, DEVICE(drc->dev), NULL);
- } else {
- trace_spapr_drc_set_isolation_state_deferring(drc_index);
- }
+ trace_spapr_drc_set_isolation_state_finalizing(drc_index);
+ spapr_drc_detach(drc);
}
- drc->configured = false;
return RTAS_OUT_SUCCESS;
}
static uint32_t drc_unisolate_physical(sPAPRDRConnector *drc)
{
+ switch (drc->state) {
+ case SPAPR_DRC_STATE_PHYSICAL_UNISOLATE:
+ case SPAPR_DRC_STATE_PHYSICAL_CONFIGURED:
+ return RTAS_OUT_SUCCESS; /* Nothing to do */
+ case SPAPR_DRC_STATE_PHYSICAL_POWERON:
+ break; /* see below */
+ default:
+ g_assert_not_reached();
+ }
+
/* cannot unisolate a non-existent resource, and, or resources
* which are in an 'UNUSABLE' allocation state. (PAPR 2.7,
* 13.5.3.5)
@@ -90,20 +90,26 @@ static uint32_t drc_unisolate_physical(sPAPRDRConnector *drc)
return RTAS_OUT_NO_SUCH_INDICATOR;
}
- drc->isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED;
+ drc->state = SPAPR_DRC_STATE_PHYSICAL_UNISOLATE;
+ drc->ccs_offset = drc->fdt_start_offset;
+ drc->ccs_depth = 0;
return RTAS_OUT_SUCCESS;
}
static uint32_t drc_isolate_logical(sPAPRDRConnector *drc)
{
- /* if the guest is configuring a device attached to this DRC, we
- * should reset the configuration state at this point since it may
- * no longer be reliable (guest released device and needs to start
- * over, or unplug occurred so the FDT is no longer valid)
- */
- g_free(drc->ccs);
- drc->ccs = NULL;
+ switch (drc->state) {
+ case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
+ case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
+ return RTAS_OUT_SUCCESS; /* Nothing to do */
+ case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
+ break; /* see below */
+ case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
+ return RTAS_OUT_PARAM_ERROR; /* not allowed */
+ default:
+ g_assert_not_reached();
+ }
/*
* Fail any requests to ISOLATE the LMB DRC if this LMB doesn't
@@ -116,11 +122,11 @@ static uint32_t drc_isolate_logical(sPAPRDRConnector *drc)
* actually being unplugged, fail the isolation request here.
*/
if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_LMB
- && !drc->awaiting_release) {
+ && !drc->unplug_requested) {
return RTAS_OUT_HW_ERROR;
}
- drc->isolation_state = SPAPR_DR_ISOLATION_STATE_ISOLATED;
+ drc->state = SPAPR_DRC_STATE_LOGICAL_AVAILABLE;
/* if we're awaiting release, but still in an unconfigured state,
* it's likely the guest is still in the process of configuring
@@ -130,38 +136,51 @@ static uint32_t drc_isolate_logical(sPAPRDRConnector *drc)
* configured state, as suggested by the state diagram from PAPR+
* 2.7, 13.4
*/
- if (drc->awaiting_release) {
+ if (drc->unplug_requested) {
uint32_t drc_index = spapr_drc_index(drc);
- if (drc->configured) {
- trace_spapr_drc_set_isolation_state_finalizing(drc_index);
- spapr_drc_detach(drc, DEVICE(drc->dev), NULL);
- } else {
- trace_spapr_drc_set_isolation_state_deferring(drc_index);
- }
+ trace_spapr_drc_set_isolation_state_finalizing(drc_index);
+ spapr_drc_detach(drc);
}
- drc->configured = false;
-
return RTAS_OUT_SUCCESS;
}
static uint32_t drc_unisolate_logical(sPAPRDRConnector *drc)
{
- /* cannot unisolate a non-existent resource, and, or resources
- * which are in an 'UNUSABLE' allocation state. (PAPR 2.7,
- * 13.5.3.5)
- */
- if (!drc->dev ||
- drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
- return RTAS_OUT_NO_SUCH_INDICATOR;
+ switch (drc->state) {
+ case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
+ case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
+ return RTAS_OUT_SUCCESS; /* Nothing to do */
+ case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
+ break; /* see below */
+ case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
+ return RTAS_OUT_NO_SUCH_INDICATOR; /* not allowed */
+ default:
+ g_assert_not_reached();
}
- drc->isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED;
+ /* Move to AVAILABLE state should have ensured device was present */
+ g_assert(drc->dev);
+
+ drc->state = SPAPR_DRC_STATE_LOGICAL_UNISOLATE;
+ drc->ccs_offset = drc->fdt_start_offset;
+ drc->ccs_depth = 0;
return RTAS_OUT_SUCCESS;
}
static uint32_t drc_set_usable(sPAPRDRConnector *drc)
{
+ switch (drc->state) {
+ case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
+ case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
+ case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
+ return RTAS_OUT_SUCCESS; /* Nothing to do */
+ case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
+ break; /* see below */
+ default:
+ g_assert_not_reached();
+ }
+
/* if there's no resource/device associated with the DRC, there's
* no way for us to put it in an allocation state consistent with
* being 'USABLE'. PAPR 2.7, 13.5.3.4 documents that this should
@@ -170,30 +189,36 @@ static uint32_t drc_set_usable(sPAPRDRConnector *drc)
if (!drc->dev) {
return RTAS_OUT_NO_SUCH_INDICATOR;
}
- if (drc->awaiting_release && drc->awaiting_allocation) {
- /* kernel is acknowledging a previous hotplug event
- * while we are already removing it.
- * it's safe to ignore awaiting_allocation here since we know the
- * situation is predicated on the guest either already having done
- * so (boot-time hotplug), or never being able to acquire in the
- * first place (hotplug followed by immediate unplug).
- */
+ if (drc->unplug_requested) {
+ /* Don't allow the guest to move a device away from UNUSABLE
+ * state when we want to unplug it */
return RTAS_OUT_NO_SUCH_INDICATOR;
}
- drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_USABLE;
- drc->awaiting_allocation = false;
+ drc->state = SPAPR_DRC_STATE_LOGICAL_AVAILABLE;
return RTAS_OUT_SUCCESS;
}
static uint32_t drc_set_unusable(sPAPRDRConnector *drc)
{
- drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_UNUSABLE;
- if (drc->awaiting_release) {
+ switch (drc->state) {
+ case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
+ return RTAS_OUT_SUCCESS; /* Nothing to do */
+ case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
+ break; /* see below */
+ case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
+ case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
+ return RTAS_OUT_NO_SUCH_INDICATOR; /* not allowed */
+ default:
+ g_assert_not_reached();
+ }
+
+ drc->state = SPAPR_DRC_STATE_LOGICAL_UNUSABLE;
+ if (drc->unplug_requested) {
uint32_t drc_index = spapr_drc_index(drc);
trace_spapr_drc_set_allocation_state_finalizing(drc_index);
- spapr_drc_detach(drc, DEVICE(drc->dev), NULL);
+ spapr_drc_detach(drc);
}
return RTAS_OUT_SUCCESS;
@@ -247,11 +272,16 @@ static sPAPRDREntitySense physical_entity_sense(sPAPRDRConnector *drc)
static sPAPRDREntitySense logical_entity_sense(sPAPRDRConnector *drc)
{
- if (drc->dev
- && (drc->allocation_state != SPAPR_DR_ALLOCATION_STATE_UNUSABLE)) {
- return SPAPR_DR_ENTITY_SENSE_PRESENT;
- } else {
+ switch (drc->state) {
+ case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
return SPAPR_DR_ENTITY_SENSE_UNUSABLE;
+ case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
+ case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
+ case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
+ g_assert(drc->dev);
+ return SPAPR_DR_ENTITY_SENSE_PRESENT;
+ default:
+ g_assert_not_reached();
}
}
@@ -344,23 +374,18 @@ void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
{
trace_spapr_drc_attach(spapr_drc_index(drc));
- if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) {
+ if (drc->dev) {
error_setg(errp, "an attached device is still awaiting release");
return;
}
- if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_PCI) {
- g_assert(drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE);
- }
+ g_assert((drc->state == SPAPR_DRC_STATE_LOGICAL_UNUSABLE)
+ || (drc->state == SPAPR_DRC_STATE_PHYSICAL_POWERON));
g_assert(fdt);
drc->dev = d;
drc->fdt = fdt;
drc->fdt_start_offset = fdt_start_offset;
- if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI) {
- drc->awaiting_allocation = true;
- }
-
object_property_add_link(OBJECT(drc), "device",
object_get_typename(OBJECT(drc->dev)),
(Object **)(&drc->dev),
@@ -373,85 +398,65 @@ static void spapr_drc_release(sPAPRDRConnector *drc)
drck->release(drc->dev);
- drc->awaiting_release = false;
+ drc->unplug_requested = false;
g_free(drc->fdt);
drc->fdt = NULL;
drc->fdt_start_offset = 0;
- object_property_del(OBJECT(drc), "device", NULL);
+ object_property_del(OBJECT(drc), "device", &error_abort);
drc->dev = NULL;
}
-void spapr_drc_detach(sPAPRDRConnector *drc, DeviceState *d, Error **errp)
+void spapr_drc_detach(sPAPRDRConnector *drc)
{
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+
trace_spapr_drc_detach(spapr_drc_index(drc));
- if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) {
- trace_spapr_drc_awaiting_isolated(spapr_drc_index(drc));
- drc->awaiting_release = true;
- return;
- }
+ g_assert(drc->dev);
- if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI &&
- drc->allocation_state != SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
- trace_spapr_drc_awaiting_unusable(spapr_drc_index(drc));
- drc->awaiting_release = true;
- return;
- }
+ drc->unplug_requested = true;
- if (drc->awaiting_allocation) {
- drc->awaiting_release = true;
- trace_spapr_drc_awaiting_allocation(spapr_drc_index(drc));
+ if (drc->state != drck->empty_state) {
+ trace_spapr_drc_awaiting_quiesce(spapr_drc_index(drc));
return;
}
spapr_drc_release(drc);
}
-static bool release_pending(sPAPRDRConnector *drc)
+void spapr_drc_reset(sPAPRDRConnector *drc)
{
- return drc->awaiting_release;
-}
-
-static void drc_reset(void *opaque)
-{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(opaque);
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
trace_spapr_drc_reset(spapr_drc_index(drc));
- g_free(drc->ccs);
- drc->ccs = NULL;
-
/* immediately upon reset we can safely assume DRCs whose devices
* are pending removal can be safely removed.
*/
- if (drc->awaiting_release) {
+ if (drc->unplug_requested) {
spapr_drc_release(drc);
}
- drc->awaiting_allocation = false;
-
if (drc->dev) {
- /* A device present at reset is coldplugged */
- drc->isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED;
- if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI) {
- drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_USABLE;
- }
- drc->dr_indicator = SPAPR_DR_INDICATOR_ACTIVE;
+ /* A device present at reset is ready to go, same as coldplugged */
+ drc->state = drck->ready_state;
} else {
- /* Otherwise device is absent, but might be hotplugged */
- drc->isolation_state = SPAPR_DR_ISOLATION_STATE_ISOLATED;
- if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI) {
- drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_UNUSABLE;
- }
- drc->dr_indicator = SPAPR_DR_INDICATOR_INACTIVE;
+ drc->state = drck->empty_state;
}
+
+ drc->ccs_offset = -1;
+ drc->ccs_depth = -1;
+}
+
+static void drc_reset(void *opaque)
+{
+ spapr_drc_reset(SPAPR_DR_CONNECTOR(opaque));
}
static bool spapr_drc_needed(void *opaque)
{
sPAPRDRConnector *drc = (sPAPRDRConnector *)opaque;
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- bool rc = false;
sPAPRDREntitySense value = drck->dr_entity_sense(drc);
/* If no dev is plugged in there is no need to migrate the DRC state */
@@ -460,23 +465,10 @@ static bool spapr_drc_needed(void *opaque)
}
/*
- * If there is dev plugged in, we need to migrate the DRC state when
- * it is different from cold-plugged state
- */
- switch (spapr_drc_type(drc)) {
- case SPAPR_DR_CONNECTOR_TYPE_PCI:
- case SPAPR_DR_CONNECTOR_TYPE_CPU:
- case SPAPR_DR_CONNECTOR_TYPE_LMB:
- rc = !((drc->isolation_state == SPAPR_DR_ISOLATION_STATE_UNISOLATED) &&
- (drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE) &&
- drc->configured && !drc->awaiting_release);
- break;
- case SPAPR_DR_CONNECTOR_TYPE_PHB:
- case SPAPR_DR_CONNECTOR_TYPE_VIO:
- default:
- g_assert_not_reached();
- }
- return rc;
+ * We need to migrate the state if it's not equal to the expected
+ * long-term state, which is the same as the coldplugged initial
+ * state */
+ return (drc->state != drck->ready_state);
}
static const VMStateDescription vmstate_spapr_drc = {
@@ -485,12 +477,7 @@ static const VMStateDescription vmstate_spapr_drc = {
.minimum_version_id = 1,
.needed = spapr_drc_needed,
.fields = (VMStateField []) {
- VMSTATE_UINT32(isolation_state, sPAPRDRConnector),
- VMSTATE_UINT32(allocation_state, sPAPRDRConnector),
- VMSTATE_UINT32(dr_indicator, sPAPRDRConnector),
- VMSTATE_BOOL(configured, sPAPRDRConnector),
- VMSTATE_BOOL(awaiting_release, sPAPRDRConnector),
- VMSTATE_BOOL(awaiting_allocation, sPAPRDRConnector),
+ VMSTATE_UINT32(state, sPAPRDRConnector),
VMSTATE_END_OF_LIST()
}
};
@@ -559,46 +546,96 @@ sPAPRDRConnector *spapr_dr_connector_new(Object *owner, const char *type,
object_property_set_bool(OBJECT(drc), true, "realized", NULL);
g_free(prop_name);
- /* PCI slot always start in a USABLE state, and stay there */
- if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_PCI) {
- drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_USABLE;
- }
-
return drc;
}
static void spapr_dr_connector_instance_init(Object *obj)
{
sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
object_property_add_uint32_ptr(obj, "id", &drc->id, NULL);
object_property_add(obj, "index", "uint32", prop_get_index,
NULL, NULL, NULL, NULL);
object_property_add(obj, "fdt", "struct", prop_get_fdt,
NULL, NULL, NULL, NULL);
+ drc->state = drck->empty_state;
}
static void spapr_dr_connector_class_init(ObjectClass *k, void *data)
{
DeviceClass *dk = DEVICE_CLASS(k);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
dk->realize = realize;
dk->unrealize = unrealize;
- drck->release_pending = release_pending;
/*
* Reason: it crashes FIXME find and document the real reason
*/
dk->user_creatable = false;
}
+static bool drc_physical_needed(void *opaque)
+{
+ sPAPRDRCPhysical *drcp = (sPAPRDRCPhysical *)opaque;
+ sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(drcp);
+
+ if ((drc->dev && (drcp->dr_indicator == SPAPR_DR_INDICATOR_ACTIVE))
+ || (!drc->dev && (drcp->dr_indicator == SPAPR_DR_INDICATOR_INACTIVE))) {
+ return false;
+ }
+ return true;
+}
+
+static const VMStateDescription vmstate_spapr_drc_physical = {
+ .name = "spapr_drc/physical",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = drc_physical_needed,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(dr_indicator, sPAPRDRCPhysical),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void drc_physical_reset(void *opaque)
+{
+ sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(opaque);
+ sPAPRDRCPhysical *drcp = SPAPR_DRC_PHYSICAL(drc);
+
+ if (drc->dev) {
+ drcp->dr_indicator = SPAPR_DR_INDICATOR_ACTIVE;
+ } else {
+ drcp->dr_indicator = SPAPR_DR_INDICATOR_INACTIVE;
+ }
+}
+
+static void realize_physical(DeviceState *d, Error **errp)
+{
+ sPAPRDRCPhysical *drcp = SPAPR_DRC_PHYSICAL(d);
+ Error *local_err = NULL;
+
+ realize(d, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ vmstate_register(DEVICE(drcp), spapr_drc_index(SPAPR_DR_CONNECTOR(drcp)),
+ &vmstate_spapr_drc_physical, drcp);
+ qemu_register_reset(drc_physical_reset, drcp);
+}
+
static void spapr_drc_physical_class_init(ObjectClass *k, void *data)
{
+ DeviceClass *dk = DEVICE_CLASS(k);
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
+ dk->realize = realize_physical;
drck->dr_entity_sense = physical_entity_sense;
drck->isolate = drc_isolate_physical;
drck->unisolate = drc_unisolate_physical;
+ drck->ready_state = SPAPR_DRC_STATE_PHYSICAL_CONFIGURED;
+ drck->empty_state = SPAPR_DRC_STATE_PHYSICAL_POWERON;
}
static void spapr_drc_logical_class_init(ObjectClass *k, void *data)
@@ -608,6 +645,8 @@ static void spapr_drc_logical_class_init(ObjectClass *k, void *data)
drck->dr_entity_sense = logical_entity_sense;
drck->isolate = drc_isolate_logical;
drck->unisolate = drc_unisolate_logical;
+ drck->ready_state = SPAPR_DRC_STATE_LOGICAL_CONFIGURED;
+ drck->empty_state = SPAPR_DRC_STATE_LOGICAL_UNUSABLE;
}
static void spapr_drc_cpu_class_init(ObjectClass *k, void *data)
@@ -653,7 +692,7 @@ static const TypeInfo spapr_dr_connector_info = {
static const TypeInfo spapr_drc_physical_info = {
.name = TYPE_SPAPR_DRC_PHYSICAL,
.parent = TYPE_SPAPR_DR_CONNECTOR,
- .instance_size = sizeof(sPAPRDRConnector),
+ .instance_size = sizeof(sPAPRDRCPhysical),
.class_init = spapr_drc_physical_class_init,
.abstract = true,
};
@@ -661,7 +700,6 @@ static const TypeInfo spapr_drc_physical_info = {
static const TypeInfo spapr_drc_logical_info = {
.name = TYPE_SPAPR_DRC_LOGICAL,
.parent = TYPE_SPAPR_DR_CONNECTOR,
- .instance_size = sizeof(sPAPRDRConnector),
.class_init = spapr_drc_logical_class_init,
.abstract = true,
};
@@ -669,21 +707,18 @@ static const TypeInfo spapr_drc_logical_info = {
static const TypeInfo spapr_drc_cpu_info = {
.name = TYPE_SPAPR_DRC_CPU,
.parent = TYPE_SPAPR_DRC_LOGICAL,
- .instance_size = sizeof(sPAPRDRConnector),
.class_init = spapr_drc_cpu_class_init,
};
static const TypeInfo spapr_drc_pci_info = {
.name = TYPE_SPAPR_DRC_PCI,
.parent = TYPE_SPAPR_DRC_PHYSICAL,
- .instance_size = sizeof(sPAPRDRConnector),
.class_init = spapr_drc_pci_class_init,
};
static const TypeInfo spapr_drc_lmb_info = {
.name = TYPE_SPAPR_DRC_LMB,
.parent = TYPE_SPAPR_DRC_LOGICAL,
- .instance_size = sizeof(sPAPRDRConnector),
.class_init = spapr_drc_lmb_class_init,
};
@@ -896,12 +931,18 @@ static uint32_t rtas_set_dr_indicator(uint32_t idx, uint32_t state)
{
sPAPRDRConnector *drc = spapr_drc_by_index(idx);
- if (!drc) {
- return RTAS_OUT_PARAM_ERROR;
+ if (!drc || !object_dynamic_cast(OBJECT(drc), TYPE_SPAPR_DRC_PHYSICAL)) {
+ return RTAS_OUT_NO_SUCH_INDICATOR;
+ }
+ if ((state != SPAPR_DR_INDICATOR_INACTIVE)
+ && (state != SPAPR_DR_INDICATOR_ACTIVE)
+ && (state != SPAPR_DR_INDICATOR_IDENTIFY)
+ && (state != SPAPR_DR_INDICATOR_ACTION)) {
+ return RTAS_OUT_PARAM_ERROR; /* bad state parameter */
}
trace_spapr_drc_set_dr_indicator(idx, state);
- drc->dr_indicator = state;
+ SPAPR_DRC_PHYSICAL(drc)->dr_indicator = state;
return RTAS_OUT_SUCCESS;
}
@@ -1011,7 +1052,7 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
uint64_t wa_offset;
uint32_t drc_index;
sPAPRDRConnector *drc;
- sPAPRConfigureConnectorState *ccs;
+ sPAPRDRConnectorClass *drck;
sPAPRDRCCResponse resp = SPAPR_DR_CC_RESPONSE_CONTINUE;
int rc;
@@ -1030,18 +1071,16 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
goto out;
}
- if (!drc->fdt) {
- trace_spapr_rtas_ibm_configure_connector_missing_fdt(drc_index);
+ if ((drc->state != SPAPR_DRC_STATE_LOGICAL_UNISOLATE)
+ && (drc->state != SPAPR_DRC_STATE_PHYSICAL_UNISOLATE)) {
+ /* Need to unisolate the device before configuring */
rc = SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE;
goto out;
}
- ccs = drc->ccs;
- if (!ccs) {
- ccs = g_new0(sPAPRConfigureConnectorState, 1);
- ccs->fdt_offset = drc->fdt_start_offset;
- drc->ccs = ccs;
- }
+ g_assert(drc->fdt);
+
+ drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
do {
uint32_t tag;
@@ -1049,12 +1088,12 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
const struct fdt_property *prop;
int fdt_offset_next, prop_len;
- tag = fdt_next_tag(drc->fdt, ccs->fdt_offset, &fdt_offset_next);
+ tag = fdt_next_tag(drc->fdt, drc->ccs_offset, &fdt_offset_next);
switch (tag) {
case FDT_BEGIN_NODE:
- ccs->fdt_depth++;
- name = fdt_get_name(drc->fdt, ccs->fdt_offset, NULL);
+ drc->ccs_depth++;
+ name = fdt_get_name(drc->fdt, drc->ccs_offset, NULL);
/* provide the name of the next OF node */
wa_offset = CC_VAL_DATA_OFFSET;
@@ -1063,30 +1102,22 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
resp = SPAPR_DR_CC_RESPONSE_NEXT_CHILD;
break;
case FDT_END_NODE:
- ccs->fdt_depth--;
- if (ccs->fdt_depth == 0) {
- sPAPRDRIsolationState state = drc->isolation_state;
+ drc->ccs_depth--;
+ if (drc->ccs_depth == 0) {
uint32_t drc_index = spapr_drc_index(drc);
- /* done sending the device tree, don't need to track
- * the state anymore
- */
+
+ /* done sending the device tree, move to configured state */
trace_spapr_drc_set_configured(drc_index);
- if (state == SPAPR_DR_ISOLATION_STATE_UNISOLATED) {
- drc->configured = true;
- } else {
- /* guest should be not configuring an isolated device */
- trace_spapr_drc_set_configured_skipping(drc_index);
- }
- g_free(ccs);
- drc->ccs = NULL;
- ccs = NULL;
+ drc->state = drck->ready_state;
+ drc->ccs_offset = -1;
+ drc->ccs_depth = -1;
resp = SPAPR_DR_CC_RESPONSE_SUCCESS;
} else {
resp = SPAPR_DR_CC_RESPONSE_PREV_PARENT;
}
break;
case FDT_PROP:
- prop = fdt_get_property_by_offset(drc->fdt, ccs->fdt_offset,
+ prop = fdt_get_property_by_offset(drc->fdt, drc->ccs_offset,
&prop_len);
name = fdt_string(drc->fdt, fdt32_to_cpu(prop->nameoff));
@@ -1111,8 +1142,8 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
/* keep seeking for an actionable tag */
break;
}
- if (ccs) {
- ccs->fdt_offset = fdt_offset_next;
+ if (drc->ccs_offset >= 0) {
+ drc->ccs_offset = fdt_offset_next;
}
} while (resp == SPAPR_DR_CC_RESPONSE_CONTINUE);
diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c
index 587a3dacb2..f952b78237 100644
--- a/hw/ppc/spapr_events.c
+++ b/hw/ppc/spapr_events.c
@@ -42,8 +42,6 @@
#include "hw/ppc/spapr_ovec.h"
#include <libfdt.h>
-struct rtas_error_log {
- uint32_t summary;
#define RTAS_LOG_VERSION_MASK 0xff000000
#define RTAS_LOG_VERSION_6 0x06000000
#define RTAS_LOG_SEVERITY_MASK 0x00e00000
@@ -85,6 +83,9 @@ struct rtas_error_log {
#define RTAS_LOG_TYPE_ECC_CORR 0x0000000a
#define RTAS_LOG_TYPE_EPOW 0x00000040
#define RTAS_LOG_TYPE_HOTPLUG 0x000000e5
+
+struct rtas_error_log {
+ uint32_t summary;
uint32_t extended_length;
} QEMU_PACKED;
@@ -166,8 +167,7 @@ struct rtas_event_log_v6_epow {
uint64_t reason_code;
} QEMU_PACKED;
-struct epow_log_full {
- struct rtas_error_log hdr;
+struct epow_extended_log {
struct rtas_event_log_v6 v6hdr;
struct rtas_event_log_v6_maina maina;
struct rtas_event_log_v6_mainb mainb;
@@ -205,8 +205,7 @@ struct rtas_event_log_v6_hp {
union drc_identifier drc_id;
} QEMU_PACKED;
-struct hp_log_full {
- struct rtas_error_log hdr;
+struct hp_extended_log {
struct rtas_event_log_v6 v6hdr;
struct rtas_event_log_v6_maina maina;
struct rtas_event_log_v6_mainb mainb;
@@ -341,25 +340,26 @@ static int rtas_event_log_to_irq(sPAPRMachineState *spapr, int log_type)
return source->irq;
}
-static void rtas_event_log_queue(int log_type, void *data)
+static uint32_t spapr_event_log_entry_type(sPAPREventLogEntry *entry)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- sPAPREventLogEntry *entry = g_new(sPAPREventLogEntry, 1);
+ return entry->summary & RTAS_LOG_TYPE_MASK;
+}
- g_assert(data);
- entry->log_type = log_type;
- entry->data = data;
+static void rtas_event_log_queue(sPAPRMachineState *spapr,
+ sPAPREventLogEntry *entry)
+{
QTAILQ_INSERT_TAIL(&spapr->pending_events, entry, next);
}
-static sPAPREventLogEntry *rtas_event_log_dequeue(uint32_t event_mask)
+static sPAPREventLogEntry *rtas_event_log_dequeue(sPAPRMachineState *spapr,
+ uint32_t event_mask)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
sPAPREventLogEntry *entry = NULL;
QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
const sPAPREventSource *source =
- rtas_event_log_to_source(spapr, entry->log_type);
+ rtas_event_log_to_source(spapr,
+ spapr_event_log_entry_type(entry));
if (source->mask & event_mask) {
break;
@@ -380,7 +380,8 @@ static bool rtas_event_log_contains(uint32_t event_mask)
QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
const sPAPREventSource *source =
- rtas_event_log_to_source(spapr, entry->log_type);
+ rtas_event_log_to_source(spapr,
+ spapr_event_log_entry_type(entry));
if (source->mask & event_mask) {
return true;
@@ -428,27 +429,28 @@ static void spapr_init_maina(struct rtas_event_log_v6_maina *maina,
static void spapr_powerdown_req(Notifier *n, void *opaque)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- struct rtas_error_log *hdr;
+ sPAPREventLogEntry *entry;
struct rtas_event_log_v6 *v6hdr;
struct rtas_event_log_v6_maina *maina;
struct rtas_event_log_v6_mainb *mainb;
struct rtas_event_log_v6_epow *epow;
- struct epow_log_full *new_epow;
+ struct epow_extended_log *new_epow;
+ entry = g_new(sPAPREventLogEntry, 1);
new_epow = g_malloc0(sizeof(*new_epow));
- hdr = &new_epow->hdr;
+ entry->extended_log = new_epow;
+
v6hdr = &new_epow->v6hdr;
maina = &new_epow->maina;
mainb = &new_epow->mainb;
epow = &new_epow->epow;
- hdr->summary = cpu_to_be32(RTAS_LOG_VERSION_6
- | RTAS_LOG_SEVERITY_EVENT
- | RTAS_LOG_DISPOSITION_NOT_RECOVERED
- | RTAS_LOG_OPTIONAL_PART_PRESENT
- | RTAS_LOG_TYPE_EPOW);
- hdr->extended_length = cpu_to_be32(sizeof(*new_epow)
- - sizeof(new_epow->hdr));
+ entry->summary = RTAS_LOG_VERSION_6
+ | RTAS_LOG_SEVERITY_EVENT
+ | RTAS_LOG_DISPOSITION_NOT_RECOVERED
+ | RTAS_LOG_OPTIONAL_PART_PRESENT
+ | RTAS_LOG_TYPE_EPOW;
+ entry->extended_length = sizeof(*new_epow);
spapr_init_v6hdr(v6hdr);
spapr_init_maina(maina, 3 /* Main-A, Main-B and EPOW */);
@@ -468,7 +470,7 @@ static void spapr_powerdown_req(Notifier *n, void *opaque)
epow->event_modifier = RTAS_LOG_V6_EPOW_MODIFIER_NORMAL;
epow->extended_modifier = RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC;
- rtas_event_log_queue(RTAS_LOG_TYPE_EPOW, new_epow);
+ rtas_event_log_queue(spapr, entry);
qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr),
rtas_event_log_to_irq(spapr,
@@ -480,28 +482,29 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
union drc_identifier *drc_id)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- struct hp_log_full *new_hp;
- struct rtas_error_log *hdr;
+ sPAPREventLogEntry *entry;
+ struct hp_extended_log *new_hp;
struct rtas_event_log_v6 *v6hdr;
struct rtas_event_log_v6_maina *maina;
struct rtas_event_log_v6_mainb *mainb;
struct rtas_event_log_v6_hp *hp;
- new_hp = g_malloc0(sizeof(struct hp_log_full));
- hdr = &new_hp->hdr;
+ entry = g_new(sPAPREventLogEntry, 1);
+ new_hp = g_malloc0(sizeof(struct hp_extended_log));
+ entry->extended_log = new_hp;
+
v6hdr = &new_hp->v6hdr;
maina = &new_hp->maina;
mainb = &new_hp->mainb;
hp = &new_hp->hp;
- hdr->summary = cpu_to_be32(RTAS_LOG_VERSION_6
- | RTAS_LOG_SEVERITY_EVENT
- | RTAS_LOG_DISPOSITION_NOT_RECOVERED
- | RTAS_LOG_OPTIONAL_PART_PRESENT
- | RTAS_LOG_INITIATOR_HOTPLUG
- | RTAS_LOG_TYPE_HOTPLUG);
- hdr->extended_length = cpu_to_be32(sizeof(*new_hp)
- - sizeof(new_hp->hdr));
+ entry->summary = RTAS_LOG_VERSION_6
+ | RTAS_LOG_SEVERITY_EVENT
+ | RTAS_LOG_DISPOSITION_NOT_RECOVERED
+ | RTAS_LOG_OPTIONAL_PART_PRESENT
+ | RTAS_LOG_INITIATOR_HOTPLUG
+ | RTAS_LOG_TYPE_HOTPLUG;
+ entry->extended_length = sizeof(*new_hp);
spapr_init_v6hdr(v6hdr);
spapr_init_maina(maina, 3 /* Main-A, Main-B, HP */);
@@ -551,7 +554,7 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
cpu_to_be32(drc_id->count_indexed.index);
}
- rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp);
+ rtas_event_log_queue(spapr, entry);
qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr),
rtas_event_log_to_irq(spapr,
@@ -628,7 +631,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,
uint32_t mask, buf, len, event_len;
uint64_t xinfo;
sPAPREventLogEntry *event;
- struct rtas_error_log *hdr;
+ struct rtas_error_log header;
int i;
if ((nargs < 6) || (nargs > 7) || nret != 1) {
@@ -644,21 +647,24 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,
xinfo |= (uint64_t)rtas_ld(args, 6) << 32;
}
- event = rtas_event_log_dequeue(mask);
+ event = rtas_event_log_dequeue(spapr, mask);
if (!event) {
goto out_no_events;
}
- hdr = event->data;
- event_len = be32_to_cpu(hdr->extended_length) + sizeof(*hdr);
+ event_len = event->extended_length + sizeof(header);
if (event_len < len) {
len = event_len;
}
- cpu_physical_memory_write(buf, event->data, len);
+ header.summary = cpu_to_be32(event->summary);
+ header.extended_length = cpu_to_be32(event->extended_length);
+ cpu_physical_memory_write(buf, &header, sizeof(header));
+ cpu_physical_memory_write(buf + sizeof(header), event->extended_log,
+ event->extended_length);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- g_free(event->data);
+ g_free(event->extended_log);
g_free(event);
/* according to PAPR+, the IRQ must be left asserted, or re-asserted, if
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 8624ce8d5b..72ea5a8247 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -3,6 +3,7 @@
#include "sysemu/hw_accel.h"
#include "sysemu/sysemu.h"
#include "qemu/log.h"
+#include "qemu/error-report.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "helper_regs.h"
@@ -354,6 +355,401 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
+struct sPAPRPendingHPT {
+ /* These fields are read-only after initialization */
+ int shift;
+ QemuThread thread;
+
+ /* These fields are protected by the BQL */
+ bool complete;
+
+ /* These fields are private to the preparation thread if
+ * !complete, otherwise protected by the BQL */
+ int ret;
+ void *hpt;
+};
+
+static void free_pending_hpt(sPAPRPendingHPT *pending)
+{
+ if (pending->hpt) {
+ qemu_vfree(pending->hpt);
+ }
+
+ g_free(pending);
+}
+
+static void *hpt_prepare_thread(void *opaque)
+{
+ sPAPRPendingHPT *pending = opaque;
+ size_t size = 1ULL << pending->shift;
+
+ pending->hpt = qemu_memalign(size, size);
+ if (pending->hpt) {
+ memset(pending->hpt, 0, size);
+ pending->ret = H_SUCCESS;
+ } else {
+ pending->ret = H_NO_MEM;
+ }
+
+ qemu_mutex_lock_iothread();
+
+ if (SPAPR_MACHINE(qdev_get_machine())->pending_hpt == pending) {
+ /* Ready to go */
+ pending->complete = true;
+ } else {
+ /* We've been cancelled, clean ourselves up */
+ free_pending_hpt(pending);
+ }
+
+ qemu_mutex_unlock_iothread();
+ return NULL;
+}
+
+/* Must be called with BQL held */
+static void cancel_hpt_prepare(sPAPRMachineState *spapr)
+{
+ sPAPRPendingHPT *pending = spapr->pending_hpt;
+
+ /* Let the thread know it's cancelled */
+ spapr->pending_hpt = NULL;
+
+ if (!pending) {
+ /* Nothing to do */
+ return;
+ }
+
+ if (!pending->complete) {
+ /* thread will clean itself up */
+ return;
+ }
+
+ free_pending_hpt(pending);
+}
+
+/* Convert a return code from the KVM ioctl()s implementing resize HPT
+ * into a PAPR hypercall return code */
+static target_ulong resize_hpt_convert_rc(int ret)
+{
+ if (ret >= 100000) {
+ return H_LONG_BUSY_ORDER_100_SEC;
+ } else if (ret >= 10000) {
+ return H_LONG_BUSY_ORDER_10_SEC;
+ } else if (ret >= 1000) {
+ return H_LONG_BUSY_ORDER_1_SEC;
+ } else if (ret >= 100) {
+ return H_LONG_BUSY_ORDER_100_MSEC;
+ } else if (ret >= 10) {
+ return H_LONG_BUSY_ORDER_10_MSEC;
+ } else if (ret > 0) {
+ return H_LONG_BUSY_ORDER_1_MSEC;
+ }
+
+ switch (ret) {
+ case 0:
+ return H_SUCCESS;
+ case -EPERM:
+ return H_AUTHORITY;
+ case -EINVAL:
+ return H_PARAMETER;
+ case -ENXIO:
+ return H_CLOSED;
+ case -ENOSPC:
+ return H_PTEG_FULL;
+ case -EBUSY:
+ return H_BUSY;
+ case -ENOMEM:
+ return H_NO_MEM;
+ default:
+ return H_HARDWARE;
+ }
+}
+
+static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ target_ulong flags = args[0];
+ int shift = args[1];
+ sPAPRPendingHPT *pending = spapr->pending_hpt;
+ uint64_t current_ram_size = MACHINE(spapr)->ram_size;
+ int rc;
+
+ if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) {
+ return H_AUTHORITY;
+ }
+
+ if (!spapr->htab_shift) {
+ /* Radix guest, no HPT */
+ return H_NOT_AVAILABLE;
+ }
+
+ trace_spapr_h_resize_hpt_prepare(flags, shift);
+
+ if (flags != 0) {
+ return H_PARAMETER;
+ }
+
+ if (shift && ((shift < 18) || (shift > 46))) {
+ return H_PARAMETER;
+ }
+
+ current_ram_size = pc_existing_dimms_capacity(&error_fatal);
+
+ /* We only allow the guest to allocate an HPT one order above what
+ * we'd normally give them (to stop a small guest claiming a huge
+ * chunk of resources in the HPT */
+ if (shift > (spapr_hpt_shift_for_ramsize(current_ram_size) + 1)) {
+ return H_RESOURCE;
+ }
+
+ rc = kvmppc_resize_hpt_prepare(cpu, flags, shift);
+ if (rc != -ENOSYS) {
+ return resize_hpt_convert_rc(rc);
+ }
+
+ if (pending) {
+ /* something already in progress */
+ if (pending->shift == shift) {
+ /* and it's suitable */
+ if (pending->complete) {
+ return pending->ret;
+ } else {
+ return H_LONG_BUSY_ORDER_100_MSEC;
+ }
+ }
+
+ /* not suitable, cancel and replace */
+ cancel_hpt_prepare(spapr);
+ }
+
+ if (!shift) {
+ /* nothing to do */
+ return H_SUCCESS;
+ }
+
+ /* start new prepare */
+
+ pending = g_new0(sPAPRPendingHPT, 1);
+ pending->shift = shift;
+ pending->ret = H_HARDWARE;
+
+ qemu_thread_create(&pending->thread, "sPAPR HPT prepare",
+ hpt_prepare_thread, pending, QEMU_THREAD_DETACHED);
+
+ spapr->pending_hpt = pending;
+
+ /* In theory we could estimate the time more accurately based on
+ * the new size, but there's not much point */
+ return H_LONG_BUSY_ORDER_100_MSEC;
+}
+
+static uint64_t new_hpte_load0(void *htab, uint64_t pteg, int slot)
+{
+ uint8_t *addr = htab;
+
+ addr += pteg * HASH_PTEG_SIZE_64;
+ addr += slot * HASH_PTE_SIZE_64;
+ return ldq_p(addr);
+}
+
+static void new_hpte_store(void *htab, uint64_t pteg, int slot,
+ uint64_t pte0, uint64_t pte1)
+{
+ uint8_t *addr = htab;
+
+ addr += pteg * HASH_PTEG_SIZE_64;
+ addr += slot * HASH_PTE_SIZE_64;
+
+ stq_p(addr, pte0);
+ stq_p(addr + HASH_PTE_SIZE_64 / 2, pte1);
+}
+
+static int rehash_hpte(PowerPCCPU *cpu,
+ const ppc_hash_pte64_t *hptes,
+ void *old_hpt, uint64_t oldsize,
+ void *new_hpt, uint64_t newsize,
+ uint64_t pteg, int slot)
+{
+ uint64_t old_hash_mask = (oldsize >> 7) - 1;
+ uint64_t new_hash_mask = (newsize >> 7) - 1;
+ target_ulong pte0 = ppc_hash64_hpte0(cpu, hptes, slot);
+ target_ulong pte1;
+ uint64_t avpn;
+ unsigned base_pg_shift;
+ uint64_t hash, new_pteg, replace_pte0;
+
+ if (!(pte0 & HPTE64_V_VALID) || !(pte0 & HPTE64_V_BOLTED)) {
+ return H_SUCCESS;
+ }
+
+ pte1 = ppc_hash64_hpte1(cpu, hptes, slot);
+
+ base_pg_shift = ppc_hash64_hpte_page_shift_noslb(cpu, pte0, pte1);
+ assert(base_pg_shift); /* H_ENTER shouldn't allow a bad encoding */
+ avpn = HPTE64_V_AVPN_VAL(pte0) & ~(((1ULL << base_pg_shift) - 1) >> 23);
+
+ if (pte0 & HPTE64_V_SECONDARY) {
+ pteg = ~pteg;
+ }
+
+ if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_256M) {
+ uint64_t offset, vsid;
+
+ /* We only have 28 - 23 bits of offset in avpn */
+ offset = (avpn & 0x1f) << 23;
+ vsid = avpn >> 5;
+ /* We can find more bits from the pteg value */
+ if (base_pg_shift < 23) {
+ offset |= ((vsid ^ pteg) & old_hash_mask) << base_pg_shift;
+ }
+
+ hash = vsid ^ (offset >> base_pg_shift);
+ } else if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_1T) {
+ uint64_t offset, vsid;
+
+ /* We only have 40 - 23 bits of seg_off in avpn */
+ offset = (avpn & 0x1ffff) << 23;
+ vsid = avpn >> 17;
+ if (base_pg_shift < 23) {
+ offset |= ((vsid ^ (vsid << 25) ^ pteg) & old_hash_mask)
+ << base_pg_shift;
+ }
+
+ hash = vsid ^ (vsid << 25) ^ (offset >> base_pg_shift);
+ } else {
+ error_report("rehash_pte: Bad segment size in HPTE");
+ return H_HARDWARE;
+ }
+
+ new_pteg = hash & new_hash_mask;
+ if (pte0 & HPTE64_V_SECONDARY) {
+ assert(~pteg == (hash & old_hash_mask));
+ new_pteg = ~new_pteg;
+ } else {
+ assert(pteg == (hash & old_hash_mask));
+ }
+ assert((oldsize != newsize) || (pteg == new_pteg));
+ replace_pte0 = new_hpte_load0(new_hpt, new_pteg, slot);
+ /*
+ * Strictly speaking, we don't need all these tests, since we only
+ * ever rehash bolted HPTEs. We might in future handle non-bolted
+ * HPTEs, though so make the logic correct for those cases as
+ * well.
+ */
+ if (replace_pte0 & HPTE64_V_VALID) {
+ assert(newsize < oldsize);
+ if (replace_pte0 & HPTE64_V_BOLTED) {
+ if (pte0 & HPTE64_V_BOLTED) {
+ /* Bolted collision, nothing we can do */
+ return H_PTEG_FULL;
+ } else {
+ /* Discard this hpte */
+ return H_SUCCESS;
+ }
+ }
+ }
+
+ new_hpte_store(new_hpt, new_pteg, slot, pte0, pte1);
+ return H_SUCCESS;
+}
+
+static int rehash_hpt(PowerPCCPU *cpu,
+ void *old_hpt, uint64_t oldsize,
+ void *new_hpt, uint64_t newsize)
+{
+ uint64_t n_ptegs = oldsize >> 7;
+ uint64_t pteg;
+ int slot;
+ int rc;
+
+ for (pteg = 0; pteg < n_ptegs; pteg++) {
+ hwaddr ptex = pteg * HPTES_PER_GROUP;
+ const ppc_hash_pte64_t *hptes
+ = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
+
+ if (!hptes) {
+ return H_HARDWARE;
+ }
+
+ for (slot = 0; slot < HPTES_PER_GROUP; slot++) {
+ rc = rehash_hpte(cpu, hptes, old_hpt, oldsize, new_hpt, newsize,
+ pteg, slot);
+ if (rc != H_SUCCESS) {
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
+ return rc;
+ }
+ }
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
+ }
+
+ return H_SUCCESS;
+}
+
+static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ target_ulong flags = args[0];
+ target_ulong shift = args[1];
+ sPAPRPendingHPT *pending = spapr->pending_hpt;
+ int rc;
+ size_t newsize;
+
+ if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) {
+ return H_AUTHORITY;
+ }
+
+ trace_spapr_h_resize_hpt_commit(flags, shift);
+
+ rc = kvmppc_resize_hpt_commit(cpu, flags, shift);
+ if (rc != -ENOSYS) {
+ return resize_hpt_convert_rc(rc);
+ }
+
+ if (flags != 0) {
+ return H_PARAMETER;
+ }
+
+ if (!pending || (pending->shift != shift)) {
+ /* no matching prepare */
+ return H_CLOSED;
+ }
+
+ if (!pending->complete) {
+ /* prepare has not completed */
+ return H_BUSY;
+ }
+
+ /* Shouldn't have got past PREPARE without an HPT */
+ g_assert(spapr->htab_shift);
+
+ newsize = 1ULL << pending->shift;
+ rc = rehash_hpt(cpu, spapr->htab, HTAB_SIZE(spapr),
+ pending->hpt, newsize);
+ if (rc == H_SUCCESS) {
+ qemu_vfree(spapr->htab);
+ spapr->htab = pending->hpt;
+ spapr->htab_shift = pending->shift;
+
+ if (kvm_enabled()) {
+ /* For KVM PR, update the HPT pointer */
+ target_ulong sdr1 = (target_ulong)(uintptr_t)spapr->htab
+ | (spapr->htab_shift - 18);
+ kvmppc_update_sdr1(sdr1);
+ }
+
+ pending->hpt = NULL; /* so it's not free()d */
+ }
+
+ /* Clean up */
+ spapr->pending_hpt = NULL;
+ free_pending_hpt(pending);
+
+ return rc;
+}
+
static target_ulong h_set_sprg0(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
@@ -1133,6 +1529,45 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
guest_radix = spapr_ovec_test(ov5_guest, OV5_MMU_RADIX_300);
spapr_ovec_clear(ov5_guest, OV5_MMU_RADIX_300);
+ /*
+ * HPT resizing is a bit of a special case, because when enabled
+ * we assume an HPT guest will support it until it says it
+ * doesn't, instead of assuming it won't support it until it says
+ * it does. Strictly speaking that approach could break for
+ * guests which don't make a CAS call, but those are so old we
+ * don't care about them. Without that assumption we'd have to
+ * make at least a temporary allocation of an HPT sized for max
+ * memory, which could be impossibly difficult under KVM HV if
+ * maxram is large.
+ */
+ if (!guest_radix && !spapr_ovec_test(ov5_guest, OV5_HPT_RESIZE)) {
+ int maxshift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size);
+
+ if (spapr->resize_hpt == SPAPR_RESIZE_HPT_REQUIRED) {
+ error_report(
+ "h_client_architecture_support: Guest doesn't support HPT resizing, but resize-hpt=required");
+ exit(1);
+ }
+
+ if (spapr->htab_shift < maxshift) {
+ CPUState *cs;
+
+ /* Guest doesn't know about HPT resizing, so we
+ * pre-emptively resize for the maximum permitted RAM. At
+ * the point this is called, nothing should have been
+ * entered into the existing HPT */
+ spapr_reallocate_hpt(spapr, maxshift, &error_fatal);
+ CPU_FOREACH(cs) {
+ if (kvm_enabled()) {
+ /* For KVM PR, update the HPT pointer */
+ target_ulong sdr1 = (target_ulong)(uintptr_t)spapr->htab
+ | (spapr->htab_shift - 18);
+ kvmppc_update_sdr1(sdr1);
+ }
+ }
+ }
+ }
+
/* NOTE: there are actually a number of ov5 bits where input from the
* guest is always zero, and the platform/QEMU enables them independently
* of guest input. To model these properly we'd want some sort of mask,
@@ -1246,6 +1681,10 @@ static void hypercall_register_types(void)
/* hcall-bulk */
spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
+ /* hcall-hpt-resize */
+ spapr_register_hypercall(H_RESIZE_HPT_PREPARE, h_resize_hpt_prepare);
+ spapr_register_hypercall(H_RESIZE_HPT_COMMIT, h_resize_hpt_commit);
+
/* hcall-splpar */
spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
spapr_register_hypercall(H_CEDE, h_cede);
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index 8656a54a3e..e614621a83 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -110,7 +110,8 @@ static void spapr_tce_free_table(uint64_t *table, int fd, uint32_t nb_table)
}
/* Called from RCU critical section */
-static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr,
+static IOMMUTLBEntry spapr_tce_translate_iommu(IOMMUMemoryRegion *iommu,
+ hwaddr addr,
IOMMUAccessFlags flag)
{
sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
@@ -150,14 +151,14 @@ static void spapr_tce_table_pre_save(void *opaque)
tcet->bus_offset, tcet->page_shift);
}
-static uint64_t spapr_tce_get_min_page_size(MemoryRegion *iommu)
+static uint64_t spapr_tce_get_min_page_size(IOMMUMemoryRegion *iommu)
{
sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
return 1ULL << tcet->page_shift;
}
-static void spapr_tce_notify_flag_changed(MemoryRegion *iommu,
+static void spapr_tce_notify_flag_changed(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old,
IOMMUNotifierFlag new)
{
@@ -247,12 +248,6 @@ static const VMStateDescription vmstate_spapr_tce_table = {
}
};
-static MemoryRegionIOMMUOps spapr_iommu_ops = {
- .translate = spapr_tce_translate_iommu,
- .get_min_page_size = spapr_tce_get_min_page_size,
- .notify_flag_changed = spapr_tce_notify_flag_changed,
-};
-
static int spapr_tce_table_realize(DeviceState *dev)
{
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
@@ -265,7 +260,9 @@ static int spapr_tce_table_realize(DeviceState *dev)
memory_region_init(&tcet->root, tcetobj, tmp, UINT64_MAX);
snprintf(tmp, sizeof(tmp), "tce-iommu-%x", tcet->liobn);
- memory_region_init_iommu(&tcet->iommu, tcetobj, &spapr_iommu_ops, tmp, 0);
+ memory_region_init_iommu(&tcet->iommu, sizeof(tcet->iommu),
+ TYPE_SPAPR_IOMMU_MEMORY_REGION,
+ tcetobj, tmp, 0);
QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list);
@@ -334,7 +331,7 @@ void spapr_tce_table_enable(sPAPRTCETable *tcet,
uint32_t nb_table)
{
if (tcet->nb_table) {
- error_report("Warning: trying to enable already enabled TCE table");
+ warn_report("trying to enable already enabled TCE table");
return;
}
@@ -348,9 +345,10 @@ void spapr_tce_table_enable(sPAPRTCETable *tcet,
&tcet->fd,
tcet->need_vfio);
- memory_region_set_size(&tcet->iommu,
+ memory_region_set_size(MEMORY_REGION(&tcet->iommu),
(uint64_t)tcet->nb_table << tcet->page_shift);
- memory_region_add_subregion(&tcet->root, tcet->bus_offset, &tcet->iommu);
+ memory_region_add_subregion(&tcet->root, tcet->bus_offset,
+ MEMORY_REGION(&tcet->iommu));
}
void spapr_tce_table_disable(sPAPRTCETable *tcet)
@@ -359,8 +357,8 @@ void spapr_tce_table_disable(sPAPRTCETable *tcet)
return;
}
- memory_region_del_subregion(&tcet->root, &tcet->iommu);
- memory_region_set_size(&tcet->iommu, 0);
+ memory_region_del_subregion(&tcet->root, MEMORY_REGION(&tcet->iommu));
+ memory_region_set_size(MEMORY_REGION(&tcet->iommu), 0);
spapr_tce_free_table(tcet->table, tcet->fd, tcet->nb_table);
tcet->fd = -1;
@@ -637,9 +635,25 @@ static TypeInfo spapr_tce_table_info = {
.class_init = spapr_tce_table_class_init,
};
+static void spapr_iommu_memory_region_class_init(ObjectClass *klass, void *data)
+{
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
+
+ imrc->translate = spapr_tce_translate_iommu;
+ imrc->get_min_page_size = spapr_tce_get_min_page_size;
+ imrc->notify_flag_changed = spapr_tce_notify_flag_changed;
+}
+
+static const TypeInfo spapr_iommu_memory_region_info = {
+ .parent = TYPE_IOMMU_MEMORY_REGION,
+ .name = TYPE_SPAPR_IOMMU_MEMORY_REGION,
+ .class_init = spapr_iommu_memory_region_class_init,
+};
+
static void register_types(void)
{
type_register_static(&spapr_tce_table_info);
+ type_register_static(&spapr_iommu_memory_region_info);
}
type_init(register_types);
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index a52dcf8ec0..6ecdf29d28 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1443,7 +1443,9 @@ static void spapr_pci_plug(HotplugHandler *plug_handler,
/* If this is function 0, signal hotplug for all the device functions.
* Otherwise defer sending the hotplug event.
*/
- if (plugged_dev->hotplugged && PCI_FUNC(pdev->devfn) == 0) {
+ if (!spapr_drc_hotplugged(plugged_dev)) {
+ spapr_drc_reset(drc);
+ } else if (PCI_FUNC(pdev->devfn) == 0) {
int i;
for (i = 0; i < 8; i++) {
@@ -1474,9 +1476,7 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
{
sPAPRPHBState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
PCIDevice *pdev = PCI_DEVICE(plugged_dev);
- sPAPRDRConnectorClass *drck;
sPAPRDRConnector *drc = spapr_phb_get_pci_drc(phb, pdev);
- Error *local_err = NULL;
if (!phb->dr_enabled) {
error_setg(errp, QERR_BUS_NO_HOTPLUG,
@@ -1487,8 +1487,7 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
g_assert(drc);
g_assert(drc->dev == plugged_dev);
- drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- if (!drck->release_pending(drc)) {
+ if (!spapr_drc_unplug_requested(drc)) {
PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev)));
uint32_t slotnr = PCI_SLOT(pdev->devfn);
sPAPRDRConnector *func_drc;
@@ -1504,7 +1503,7 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
func_drck = SPAPR_DR_CONNECTOR_GET_CLASS(func_drc);
state = func_drck->dr_entity_sense(func_drc);
if (state == SPAPR_DR_ENTITY_SENSE_PRESENT
- && !func_drck->release_pending(func_drc)) {
+ && !spapr_drc_unplug_requested(func_drc)) {
error_setg(errp,
"PCI: slot %d, function %d still present. "
"Must unplug all non-0 functions first.",
@@ -1514,11 +1513,7 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
}
}
- spapr_drc_detach(drc, DEVICE(pdev), &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
+ spapr_drc_detach(drc);
/* if this isn't func 0, defer unplug event. otherwise signal removal
* for all present functions
diff --git a/hw/ppc/spapr_rng.c b/hw/ppc/spapr_rng.c
index 80515eb54d..d2acd61a15 100644
--- a/hw/ppc/spapr_rng.c
+++ b/hw/ppc/spapr_rng.c
@@ -96,17 +96,11 @@ static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr,
static void spapr_rng_instance_init(Object *obj)
{
- sPAPRRngState *rngstate = SPAPR_RNG(obj);
-
if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL) != NULL) {
error_report("spapr-rng can not be instantiated twice!");
return;
}
- object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
- (Object **)&rngstate->backend,
- object_property_allow_set_link,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
object_property_set_description(obj, "rng",
"ID of the random number generator backend",
NULL);
@@ -163,6 +157,8 @@ int spapr_rng_populate_dt(void *fdt)
static Property spapr_rng_properties[] = {
DEFINE_PROP_BOOL("use-kvm", sPAPRRngState, use_kvm, false),
+ DEFINE_PROP_LINK("rng", sPAPRRngState, backend, TYPE_RNG_BACKEND,
+ RngBackend *),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index 3e8e3cffde..0f7d9be4ef 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -16,6 +16,8 @@ spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes"
# hw/ppc/spapr_hcall.c
spapr_cas_pvr_try(uint32_t pvr) "%x"
spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=%x, explicit_match=%u, new=%x"
+spapr_h_resize_hpt_prepare(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64
+spapr_h_resize_hpt_commit(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64
# hw/ppc/spapr_iommu.c
spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
@@ -46,8 +48,7 @@ spapr_drc_set_configured(uint32_t index) "drc: 0x%"PRIx32
spapr_drc_set_configured_skipping(uint32_t index) "drc: 0x%"PRIx32", isolated device"
spapr_drc_attach(uint32_t index) "drc: 0x%"PRIx32
spapr_drc_detach(uint32_t index) "drc: 0x%"PRIx32
-spapr_drc_awaiting_isolated(uint32_t index) "drc: 0x%"PRIx32
-spapr_drc_awaiting_unusable(uint32_t index) "drc: 0x%"PRIx32
+spapr_drc_awaiting_quiesce(uint32_t index) "drc: 0x%"PRIx32
spapr_drc_awaiting_allocation(uint32_t index) "drc: 0x%"PRIx32
spapr_drc_reset(uint32_t index) "drc: 0x%"PRIx32
spapr_drc_realize(uint32_t index) "drc: 0x%"PRIx32
diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index a8e5575a8a..b2aade2466 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -13,5 +13,7 @@ obj-y += css-bridge.o
obj-y += ccw-device.o
obj-y += s390-pci-bus.o s390-pci-inst.o
obj-y += s390-skeys.o
+obj-y += s390-stattrib.o
obj-$(CONFIG_KVM) += s390-skeys-kvm.o
+obj-$(CONFIG_KVM) += s390-stattrib-kvm.o
obj-y += s390-ccw.o
diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c
index 823747fcd7..c4a9735d71 100644
--- a/hw/s390x/css-bridge.c
+++ b/hw/s390x/css-bridge.c
@@ -110,7 +110,7 @@ VirtualCssBus *virtual_css_bus_init(void)
qbus_set_hotplug_handler(bus, dev, &error_abort);
css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false,
- &error_abort);
+ 0, &error_abort);
return cbus;
}
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index d67fffae30..6a42b95cee 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -29,12 +29,45 @@ typedef struct CrwContainer {
QTAILQ_ENTRY(CrwContainer) sibling;
} CrwContainer;
+static const VMStateDescription vmstate_crw = {
+ .name = "s390_crw",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(flags, CRW),
+ VMSTATE_UINT16(rsid, CRW),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const VMStateDescription vmstate_crw_container = {
+ .name = "s390_crw_container",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(crw, CrwContainer, 0, vmstate_crw, CRW),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
typedef struct ChpInfo {
uint8_t in_use;
uint8_t type;
uint8_t is_virtual;
} ChpInfo;
+static const VMStateDescription vmstate_chp_info = {
+ .name = "s390_chp_info",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(in_use, ChpInfo),
+ VMSTATE_UINT8(type, ChpInfo),
+ VMSTATE_UINT8(is_virtual, ChpInfo),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
typedef struct SubchSet {
SubchDev *sch[MAX_SCHID + 1];
unsigned long schids_used[BITS_TO_LONGS(MAX_SCHID + 1)];
@@ -132,6 +165,36 @@ static const VMStateDescription vmstate_sense_id = {
}
};
+static const VMStateDescription vmstate_orb = {
+ .name = "s390_orb",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(intparm, ORB),
+ VMSTATE_UINT16(ctrl0, ORB),
+ VMSTATE_UINT8(lpm, ORB),
+ VMSTATE_UINT8(ctrl1, ORB),
+ VMSTATE_UINT32(cpa, ORB),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool vmstate_schdev_orb_needed(void *opaque)
+{
+ return css_migration_enabled();
+}
+
+static const VMStateDescription vmstate_schdev_orb = {
+ .name = "s390_subch_dev/orb",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = vmstate_schdev_orb_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(orb, SubchDev, 1, vmstate_orb, ORB),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static int subch_dev_post_load(void *opaque, int version_id);
static void subch_dev_pre_save(void *opaque);
@@ -160,6 +223,10 @@ const VMStateDescription vmstate_subch_dev = {
VMSTATE_BOOL(ccw_fmt_1, SubchDev),
VMSTATE_UINT8(ccw_no_data_cnt, SubchDev),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_schdev_orb,
+ NULL
}
};
@@ -221,10 +288,24 @@ typedef struct CssImage {
ChpInfo chpids[MAX_CHPID + 1];
} CssImage;
+static const VMStateDescription vmstate_css_img = {
+ .name = "s390_css_img",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ /* Subchannel sets have no relevant state. */
+ VMSTATE_STRUCT_ARRAY(chpids, CssImage, MAX_CHPID + 1, 0,
+ vmstate_chp_info, ChpInfo),
+ VMSTATE_END_OF_LIST()
+ }
+
+};
+
typedef struct IoAdapter {
uint32_t id;
uint8_t type;
uint8_t isc;
+ uint8_t flags;
} IoAdapter;
typedef struct ChannelSubSys {
@@ -238,10 +319,34 @@ typedef struct ChannelSubSys {
uint64_t chnmon_area;
CssImage *css[MAX_CSSID + 1];
uint8_t default_cssid;
+ /* don't migrate, see css_register_io_adapters */
IoAdapter *io_adapters[CSS_IO_ADAPTER_TYPE_NUMS][MAX_ISC + 1];
+ /* don't migrate, see get_indicator and IndAddrPtrTmp */
QTAILQ_HEAD(, IndAddr) indicator_addresses;
} ChannelSubSys;
+static const VMStateDescription vmstate_css = {
+ .name = "s390_css",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_QTAILQ_V(pending_crws, ChannelSubSys, 1, vmstate_crw_container,
+ CrwContainer, sibling),
+ VMSTATE_BOOL(sei_pending, ChannelSubSys),
+ VMSTATE_BOOL(do_crw_mchk, ChannelSubSys),
+ VMSTATE_BOOL(crws_lost, ChannelSubSys),
+ /* These were kind of migrated by virtio */
+ VMSTATE_UINT8(max_cssid, ChannelSubSys),
+ VMSTATE_UINT8(max_ssid, ChannelSubSys),
+ VMSTATE_BOOL(chnmon_active, ChannelSubSys),
+ VMSTATE_UINT64(chnmon_area, ChannelSubSys),
+ VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(css, ChannelSubSys, MAX_CSSID + 1,
+ 0, vmstate_css_img, CssImage),
+ VMSTATE_UINT8(default_cssid, ChannelSubSys),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static ChannelSubSys channel_subsys = {
.pending_crws = QTAILQ_HEAD_INITIALIZER(channel_subsys.pending_crws),
.do_crw_mchk = true,
@@ -281,6 +386,10 @@ static int subch_dev_post_load(void *opaque, int version_id)
css_subch_assign(s->cssid, s->ssid, s->schid, s->devno, s);
}
+ if (css_migration_enabled()) {
+ /* No compat voodoo to do ;) */
+ return 0;
+ }
/*
* Hack alert. If we don't migrate the channel subsystem status
* we still need to find out if the guest enabled mss/mcss-e.
@@ -299,6 +408,11 @@ static int subch_dev_post_load(void *opaque, int version_id)
return 0;
}
+void css_register_vmstate(void)
+{
+ vmstate_register(NULL, 0, &vmstate_css, &channel_subsys);
+}
+
IndAddr *get_indicator(hwaddr ind_addr, int len)
{
IndAddr *indicator;
@@ -392,10 +506,12 @@ uint32_t css_get_adapter_id(CssIoAdapterType type, uint8_t isc)
*
* @swap: an indication if byte swap is needed.
* @maskable: an indication if the adapter is subject to the mask operation.
+ * @flags: further characteristics of the adapter.
+ * e.g. suppressible, an indication if the adapter is subject to AIS.
* @errp: location to store error information.
*/
void css_register_io_adapters(CssIoAdapterType type, bool swap, bool maskable,
- Error **errp)
+ uint8_t flags, Error **errp)
{
uint32_t id;
int ret, isc;
@@ -413,12 +529,13 @@ void css_register_io_adapters(CssIoAdapterType type, bool swap, bool maskable,
for (isc = 0; isc <= MAX_ISC; isc++) {
id = (type << 3) | isc;
- ret = fsc->register_io_adapter(fs, id, isc, swap, maskable);
+ ret = fsc->register_io_adapter(fs, id, isc, swap, maskable, flags);
if (ret == 0) {
adapter = g_new0(IoAdapter, 1);
adapter->id = id;
adapter->isc = isc;
adapter->type = type;
+ adapter->flags = flags;
channel_subsys.io_adapters[type][isc] = adapter;
} else {
error_setg_errno(errp, -ret, "Unexpected error %d when "
@@ -517,12 +634,52 @@ void css_conditional_io_interrupt(SubchDev *sch)
}
}
-void css_adapter_interrupt(uint8_t isc)
+int css_do_sic(CPUS390XState *env, uint8_t isc, uint16_t mode)
+{
+ S390FLICState *fs = s390_get_flic();
+ S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+ int r;
+
+ if (env->psw.mask & PSW_MASK_PSTATE) {
+ r = -PGM_PRIVILEGED;
+ goto out;
+ }
+
+ trace_css_do_sic(mode, isc);
+ switch (mode) {
+ case SIC_IRQ_MODE_ALL:
+ case SIC_IRQ_MODE_SINGLE:
+ break;
+ default:
+ r = -PGM_OPERAND;
+ goto out;
+ }
+
+ r = fsc->modify_ais_mode(fs, isc, mode) ? -PGM_OPERATION : 0;
+out:
+ return r;
+}
+
+void css_adapter_interrupt(CssIoAdapterType type, uint8_t isc)
{
+ S390FLICState *fs = s390_get_flic();
+ S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;
+ IoAdapter *adapter = channel_subsys.io_adapters[type][isc];
+
+ if (!adapter) {
+ return;
+ }
trace_css_adapter_interrupt(isc);
- s390_io_interrupt(0, 0, 0, io_int_word);
+ if (fs->ais_supported) {
+ if (fsc->inject_airq(fs, type, isc, adapter->flags)) {
+ error_report("Failed to inject airq with AIS supported");
+ exit(1);
+ }
+ } else {
+ s390_io_interrupt(0, 0, 0, io_int_word);
+ }
}
static void sch_handle_clear_func(SubchDev *sch)
@@ -752,7 +909,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
return ret;
}
-static void sch_handle_start_func_virtual(SubchDev *sch, ORB *orb)
+static void sch_handle_start_func_virtual(SubchDev *sch)
{
PMCW *p = &sch->curr_status.pmcw;
@@ -766,10 +923,10 @@ static void sch_handle_start_func_virtual(SubchDev *sch, ORB *orb)
if (!(s->ctrl & SCSW_ACTL_SUSP)) {
/* Start Function triggered via ssch, i.e. we have an ORB */
+ ORB *orb = &sch->orb;
s->cstat = 0;
s->dstat = 0;
/* Look at the orb and try to execute the channel program. */
- assert(orb != NULL); /* resume does not pass an orb */
p->intparm = orb->intparm;
if (!(orb->lpm & path)) {
/* Generate a deferred cc 3 condition. */
@@ -783,8 +940,7 @@ static void sch_handle_start_func_virtual(SubchDev *sch, ORB *orb)
sch->ccw_no_data_cnt = 0;
suspend_allowed = !!(orb->ctrl0 & ORB_CTRL0_MASK_SPND);
} else {
- /* Start Function resumed via rsch, i.e. we don't have an
- * ORB */
+ /* Start Function resumed via rsch */
s->ctrl &= ~(SCSW_ACTL_SUSP | SCSW_ACTL_RESUME_PEND);
/* The channel program had been suspended before. */
suspend_allowed = true;
@@ -854,13 +1010,14 @@ static void sch_handle_start_func_virtual(SubchDev *sch, ORB *orb)
}
-static int sch_handle_start_func_passthrough(SubchDev *sch, ORB *orb)
+static int sch_handle_start_func_passthrough(SubchDev *sch)
{
PMCW *p = &sch->curr_status.pmcw;
SCSW *s = &sch->curr_status.scsw;
int ret;
+ ORB *orb = &sch->orb;
if (!(s->ctrl & SCSW_ACTL_SUSP)) {
assert(orb != NULL);
p->intparm = orb->intparm;
@@ -905,7 +1062,7 @@ static int sch_handle_start_func_passthrough(SubchDev *sch, ORB *orb)
* read/writes) asynchronous later on if we start supporting more than
* our current very simple devices.
*/
-int do_subchannel_work_virtual(SubchDev *sch, ORB *orb)
+int do_subchannel_work_virtual(SubchDev *sch)
{
SCSW *s = &sch->curr_status.scsw;
@@ -916,7 +1073,7 @@ int do_subchannel_work_virtual(SubchDev *sch, ORB *orb)
sch_handle_halt_func(sch);
} else if (s->ctrl & SCSW_FCTL_START_FUNC) {
/* Triggered by both ssch and rsch. */
- sch_handle_start_func_virtual(sch, orb);
+ sch_handle_start_func_virtual(sch);
} else {
/* Cannot happen. */
return 0;
@@ -925,7 +1082,7 @@ int do_subchannel_work_virtual(SubchDev *sch, ORB *orb)
return 0;
}
-int do_subchannel_work_passthrough(SubchDev *sch, ORB *orb)
+int do_subchannel_work_passthrough(SubchDev *sch)
{
int ret;
SCSW *s = &sch->curr_status.scsw;
@@ -939,7 +1096,7 @@ int do_subchannel_work_passthrough(SubchDev *sch, ORB *orb)
sch_handle_halt_func(sch);
ret = 0;
} else if (s->ctrl & SCSW_FCTL_START_FUNC) {
- ret = sch_handle_start_func_passthrough(sch, orb);
+ ret = sch_handle_start_func_passthrough(sch);
} else {
/* Cannot happen. */
return -ENODEV;
@@ -948,10 +1105,10 @@ int do_subchannel_work_passthrough(SubchDev *sch, ORB *orb)
return ret;
}
-static int do_subchannel_work(SubchDev *sch, ORB *orb)
+static int do_subchannel_work(SubchDev *sch)
{
if (sch->do_subchannel_work) {
- return sch->do_subchannel_work(sch, orb);
+ return sch->do_subchannel_work(sch);
} else {
return -EINVAL;
}
@@ -1158,7 +1315,7 @@ int css_do_csch(SubchDev *sch)
s->ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL);
s->ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_ACTL_CLEAR_PEND;
- do_subchannel_work(sch, NULL);
+ do_subchannel_work(sch);
ret = 0;
out:
@@ -1199,7 +1356,7 @@ int css_do_hsch(SubchDev *sch)
}
s->ctrl |= SCSW_ACTL_HALT_PEND;
- do_subchannel_work(sch, NULL);
+ do_subchannel_work(sch);
ret = 0;
out:
@@ -1268,12 +1425,13 @@ int css_do_ssch(SubchDev *sch, ORB *orb)
if (channel_subsys.chnmon_active) {
css_update_chnmon(sch);
}
+ sch->orb = *orb;
sch->channel_prog = orb->cpa;
/* Trigger the start function. */
s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND);
s->flags &= ~SCSW_FLAGS_MASK_PNO;
- ret = do_subchannel_work(sch, orb);
+ ret = do_subchannel_work(sch);
out:
return ret;
@@ -1552,7 +1710,7 @@ int css_do_rsch(SubchDev *sch)
}
s->ctrl |= SCSW_ACTL_RESUME_PEND;
- do_subchannel_work(sch, NULL);
+ do_subchannel_work(sch);
ret = 0;
out:
@@ -2095,7 +2253,7 @@ out:
g_free(str);
}
-PropertyInfo css_devid_propinfo = {
+const PropertyInfo css_devid_propinfo = {
.name = "str",
.description = "Identifier of an I/O device in the channel "
"subsystem, example: fe.1.23ab",
@@ -2103,7 +2261,7 @@ PropertyInfo css_devid_propinfo = {
.set = set_css_devid,
};
-PropertyInfo css_devid_ro_propinfo = {
+const PropertyInfo css_devid_ro_propinfo = {
.name = "str",
.description = "Read-only identifier of an I/O device in the channel "
"subsystem, example: fe.1.23ab",
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 5651483781..61cfd2138f 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -356,7 +356,7 @@ out:
return pte;
}
-static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *mr, hwaddr addr,
+static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
IOMMUAccessFlags flag)
{
uint64_t pte;
@@ -407,10 +407,6 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *mr, hwaddr addr,
return ret;
}
-static const MemoryRegionIOMMUOps s390_iommu_ops = {
- .translate = s390_translate_iommu,
-};
-
static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus,
int devfn)
{
@@ -504,7 +500,7 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
0x80 >> ((ind_bit + vec) % 8));
if (!set_ind_atomic(pbdev->routes.adapter.summary_addr + sum_bit / 8,
0x80 >> (sum_bit % 8))) {
- css_adapter_interrupt(pbdev->isc);
+ css_adapter_interrupt(CSS_IO_ADAPTER_PCI, pbdev->isc);
}
}
@@ -522,17 +518,18 @@ static const MemoryRegionOps s390_msi_ctrl_ops = {
void s390_pci_iommu_enable(S390PCIIOMMU *iommu)
{
char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid);
- memory_region_init_iommu(&iommu->iommu_mr, OBJECT(&iommu->mr),
- &s390_iommu_ops, name, iommu->pal + 1);
+ memory_region_init_iommu(&iommu->iommu_mr, sizeof(iommu->iommu_mr),
+ TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr),
+ name, iommu->pal + 1);
iommu->enabled = true;
- memory_region_add_subregion(&iommu->mr, 0, &iommu->iommu_mr);
+ memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&iommu->iommu_mr));
g_free(name);
}
void s390_pci_iommu_disable(S390PCIIOMMU *iommu)
{
iommu->enabled = false;
- memory_region_del_subregion(&iommu->mr, &iommu->iommu_mr);
+ memory_region_del_subregion(&iommu->mr, MEMORY_REGION(&iommu->iommu_mr));
object_unparent(OBJECT(&iommu->iommu_mr));
}
@@ -582,7 +579,8 @@ static int s390_pcihost_init(SysBusDevice *dev)
QTAILQ_INIT(&s->pending_sei);
QTAILQ_INIT(&s->zpci_devs);
- css_register_io_adapters(CSS_IO_ADAPTER_PCI, true, false, &error_abort);
+ css_register_io_adapters(CSS_IO_ADAPTER_PCI, true, false,
+ S390_ADAPTER_SUPPRESSIBLE, &error_abort);
return 0;
}
@@ -1018,7 +1016,7 @@ static void s390_pci_set_fid(Object *obj, Visitor *v, const char *name,
zpci->fid_defined = true;
}
-static PropertyInfo s390_pci_fid_propinfo = {
+static const PropertyInfo s390_pci_fid_propinfo = {
.name = "zpci_fid",
.get = s390_pci_get_fid,
.set = s390_pci_set_fid,
@@ -1058,12 +1056,26 @@ static TypeInfo s390_pci_iommu_info = {
.instance_size = sizeof(S390PCIIOMMU),
};
+static void s390_iommu_memory_region_class_init(ObjectClass *klass, void *data)
+{
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
+
+ imrc->translate = s390_translate_iommu;
+}
+
+static const TypeInfo s390_iommu_memory_region_info = {
+ .parent = TYPE_IOMMU_MEMORY_REGION,
+ .name = TYPE_S390_IOMMU_MEMORY_REGION,
+ .class_init = s390_iommu_memory_region_class_init,
+};
+
static void s390_pci_register_types(void)
{
type_register_static(&s390_pcihost_info);
type_register_static(&s390_pcibus_info);
type_register_static(&s390_pci_device_info);
type_register_static(&s390_pci_iommu_info);
+ type_register_static(&s390_iommu_memory_region_info);
}
type_init(s390_pci_register_types)
diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h
index cf142a3e68..67af2c12ff 100644
--- a/hw/s390x/s390-pci-bus.h
+++ b/hw/s390x/s390-pci-bus.h
@@ -24,6 +24,7 @@
#define TYPE_S390_PCI_BUS "s390-pcibus"
#define TYPE_S390_PCI_DEVICE "zpci"
#define TYPE_S390_PCI_IOMMU "s390-pci-iommu"
+#define TYPE_S390_IOMMU_MEMORY_REGION "s390-iommu-memory-region"
#define FH_MASK_ENABLE 0x80000000
#define FH_MASK_INSTANCE 0x7f000000
#define FH_MASK_SHM 0x00ff0000
@@ -266,7 +267,7 @@ typedef struct S390PCIIOMMU {
S390PCIBusDevice *pbdev;
AddressSpace as;
MemoryRegion mr;
- MemoryRegion iommu_mr;
+ IOMMUMemoryRegion iommu_mr;
bool enabled;
uint64_t g_iota;
uint64_t pba;
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 8bc7c98682..b7beb8c36a 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -563,7 +563,8 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
S390PCIIOMMU *iommu;
hwaddr start, end;
IOMMUTLBEntry entry;
- MemoryRegion *mr;
+ IOMMUMemoryRegion *iommu_mr;
+ IOMMUMemoryRegionClass *imrc;
cpu_synchronize_state(CPU(cpu));
@@ -622,9 +623,11 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
goto out;
}
- mr = &iommu->iommu_mr;
+ iommu_mr = &iommu->iommu_mr;
+ imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
+
while (start < end) {
- entry = mr->iommu_ops->translate(mr, start, IOMMU_NONE);
+ entry = imrc->translate(iommu_mr, start, IOMMU_NONE);
if (!entry.translated_addr) {
pbdev->state = ZPCI_FS_ERROR;
@@ -635,7 +638,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
goto out;
}
- memory_region_notify_iommu(mr, entry);
+ memory_region_notify_iommu(iommu_mr, entry);
start += entry.addr_mask + 1;
}
diff --git a/hw/s390x/s390-stattrib-kvm.c b/hw/s390x/s390-stattrib-kvm.c
new file mode 100644
index 0000000000..ff3f89fd2d
--- /dev/null
+++ b/hw/s390x/s390-stattrib-kvm.c
@@ -0,0 +1,190 @@
+/*
+ * s390 storage attributes device -- KVM object
+ *
+ * Copyright 2016 IBM Corp.
+ * Author(s): Claudio Imbrenda <imbrenda@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/boards.h"
+#include "migration/qemu-file.h"
+#include "hw/s390x/storage-attributes.h"
+#include "qemu/error-report.h"
+#include "sysemu/kvm.h"
+#include "exec/ram_addr.h"
+#include "cpu.h"
+
+Object *kvm_s390_stattrib_create(void)
+{
+ if (kvm_enabled() &&
+ kvm_check_extension(kvm_state, KVM_CAP_S390_CMMA_MIGRATION)) {
+ return object_new(TYPE_KVM_S390_STATTRIB);
+ }
+ return NULL;
+}
+
+static void kvm_s390_stattrib_instance_init(Object *obj)
+{
+ KVMS390StAttribState *sas = KVM_S390_STATTRIB(obj);
+
+ sas->still_dirty = 0;
+}
+
+static int kvm_s390_stattrib_read_helper(S390StAttribState *sa,
+ uint64_t *start_gfn,
+ uint32_t count,
+ uint8_t *values,
+ uint32_t flags)
+{
+ KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
+ int r;
+ struct kvm_s390_cmma_log clog = {
+ .values = (uint64_t)values,
+ .start_gfn = *start_gfn,
+ .count = count,
+ .flags = flags,
+ };
+
+ r = kvm_vm_ioctl(kvm_state, KVM_S390_GET_CMMA_BITS, &clog);
+ if (r < 0) {
+ error_report("KVM_S390_GET_CMMA_BITS failed: %s", strerror(-r));
+ return r;
+ }
+
+ *start_gfn = clog.start_gfn;
+ sas->still_dirty = clog.remaining;
+ return clog.count;
+}
+
+static int kvm_s390_stattrib_get_stattr(S390StAttribState *sa,
+ uint64_t *start_gfn,
+ uint32_t count,
+ uint8_t *values)
+{
+ return kvm_s390_stattrib_read_helper(sa, start_gfn, count, values, 0);
+}
+
+static int kvm_s390_stattrib_peek_stattr(S390StAttribState *sa,
+ uint64_t start_gfn,
+ uint32_t count,
+ uint8_t *values)
+{
+ return kvm_s390_stattrib_read_helper(sa, &start_gfn, count, values,
+ KVM_S390_CMMA_PEEK);
+}
+
+static int kvm_s390_stattrib_set_stattr(S390StAttribState *sa,
+ uint64_t start_gfn,
+ uint32_t count,
+ uint8_t *values)
+{
+ KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
+ MachineState *machine = MACHINE(qdev_get_machine());
+ unsigned long max = machine->maxram_size / TARGET_PAGE_SIZE;
+
+ if (start_gfn + count > max) {
+ error_report("Out of memory bounds when setting storage attributes");
+ return -1;
+ }
+ if (!sas->incoming_buffer) {
+ sas->incoming_buffer = g_malloc0(max);
+ }
+
+ memcpy(sas->incoming_buffer + start_gfn, values, count);
+
+ return 0;
+}
+
+static void kvm_s390_stattrib_synchronize(S390StAttribState *sa)
+{
+ KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
+ MachineState *machine = MACHINE(qdev_get_machine());
+ unsigned long max = machine->maxram_size / TARGET_PAGE_SIZE;
+ unsigned long cx, len = 1 << 19;
+ int r;
+ struct kvm_s390_cmma_log clog = {
+ .flags = 0,
+ .mask = ~0ULL,
+ };
+
+ if (sas->incoming_buffer) {
+ for (cx = 0; cx + len <= max; cx += len) {
+ clog.start_gfn = cx;
+ clog.count = len;
+ clog.values = (uint64_t)(sas->incoming_buffer + cx * len);
+ r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog);
+ if (r) {
+ error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r));
+ return;
+ }
+ }
+ if (cx < max) {
+ clog.start_gfn = cx;
+ clog.count = max - cx;
+ clog.values = (uint64_t)(sas->incoming_buffer + cx * len);
+ r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog);
+ if (r) {
+ error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r));
+ }
+ }
+ g_free(sas->incoming_buffer);
+ sas->incoming_buffer = NULL;
+ }
+}
+
+static int kvm_s390_stattrib_set_migrationmode(S390StAttribState *sa, bool val)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_S390_VM_MIGRATION,
+ .attr = val,
+ .addr = 0,
+ };
+ return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+}
+
+static long long kvm_s390_stattrib_get_dirtycount(S390StAttribState *sa)
+{
+ KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
+ uint8_t val[8];
+
+ kvm_s390_stattrib_peek_stattr(sa, 0, 1, val);
+ return sas->still_dirty;
+}
+
+static int kvm_s390_stattrib_get_active(S390StAttribState *sa)
+{
+ return kvm_s390_cmma_active() && sa->migration_enabled;
+}
+
+static void kvm_s390_stattrib_class_init(ObjectClass *oc, void *data)
+{
+ S390StAttribClass *sac = S390_STATTRIB_CLASS(oc);
+
+ sac->get_stattr = kvm_s390_stattrib_get_stattr;
+ sac->peek_stattr = kvm_s390_stattrib_peek_stattr;
+ sac->set_stattr = kvm_s390_stattrib_set_stattr;
+ sac->set_migrationmode = kvm_s390_stattrib_set_migrationmode;
+ sac->get_dirtycount = kvm_s390_stattrib_get_dirtycount;
+ sac->synchronize = kvm_s390_stattrib_synchronize;
+ sac->get_active = kvm_s390_stattrib_get_active;
+}
+
+static const TypeInfo kvm_s390_stattrib_info = {
+ .name = TYPE_KVM_S390_STATTRIB,
+ .parent = TYPE_S390_STATTRIB,
+ .instance_init = kvm_s390_stattrib_instance_init,
+ .instance_size = sizeof(KVMS390StAttribState),
+ .class_init = kvm_s390_stattrib_class_init,
+ .class_size = sizeof(S390StAttribClass),
+};
+
+static void kvm_s390_stattrib_register_types(void)
+{
+ type_register_static(&kvm_s390_stattrib_info);
+}
+
+type_init(kvm_s390_stattrib_register_types)
diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c
new file mode 100644
index 0000000000..d14923f099
--- /dev/null
+++ b/hw/s390x/s390-stattrib.c
@@ -0,0 +1,404 @@
+/*
+ * s390 storage attributes device
+ *
+ * Copyright 2016 IBM Corp.
+ * Author(s): Claudio Imbrenda <imbrenda@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/boards.h"
+#include "qmp-commands.h"
+#include "migration/qemu-file.h"
+#include "migration/register.h"
+#include "hw/s390x/storage-attributes.h"
+#include "qemu/error-report.h"
+#include "sysemu/kvm.h"
+#include "exec/ram_addr.h"
+#include "qapi/error.h"
+
+#define CMMA_BLOCK_SIZE (1 << 10)
+
+#define STATTR_FLAG_EOS 0x01ULL
+#define STATTR_FLAG_MORE 0x02ULL
+#define STATTR_FLAG_ERROR 0x04ULL
+#define STATTR_FLAG_DONE 0x08ULL
+
+static S390StAttribState *s390_get_stattrib_device(void)
+{
+ S390StAttribState *sas;
+
+ sas = S390_STATTRIB(object_resolve_path_type("", TYPE_S390_STATTRIB, NULL));
+ assert(sas);
+ return sas;
+}
+
+void s390_stattrib_init(void)
+{
+ Object *obj;
+
+ obj = kvm_s390_stattrib_create();
+ if (!obj) {
+ obj = object_new(TYPE_QEMU_S390_STATTRIB);
+ }
+
+ object_property_add_child(qdev_get_machine(), TYPE_S390_STATTRIB,
+ obj, NULL);
+ object_unref(obj);
+
+ qdev_init_nofail(DEVICE(obj));
+}
+
+/* Console commands: */
+
+void hmp_migrationmode(Monitor *mon, const QDict *qdict)
+{
+ S390StAttribState *sas = s390_get_stattrib_device();
+ S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
+ uint64_t what = qdict_get_int(qdict, "mode");
+ int r;
+
+ r = sac->set_migrationmode(sas, what);
+ if (r < 0) {
+ monitor_printf(mon, "Error: %s", strerror(-r));
+ }
+}
+
+void hmp_info_cmma(Monitor *mon, const QDict *qdict)
+{
+ S390StAttribState *sas = s390_get_stattrib_device();
+ S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
+ uint64_t addr = qdict_get_int(qdict, "addr");
+ uint64_t buflen = qdict_get_try_int(qdict, "count", 8);
+ uint8_t *vals;
+ int cx, len;
+
+ vals = g_try_malloc(buflen);
+ if (!vals) {
+ monitor_printf(mon, "Error: %s\n", strerror(errno));
+ return;
+ }
+
+ len = sac->peek_stattr(sas, addr / TARGET_PAGE_SIZE, buflen, vals);
+ if (len < 0) {
+ monitor_printf(mon, "Error: %s", strerror(-len));
+ goto out;
+ }
+
+ monitor_printf(mon, " CMMA attributes, "
+ "pages %" PRIu64 "+%d (0x%" PRIx64 "):\n",
+ addr / TARGET_PAGE_SIZE, len, addr & ~TARGET_PAGE_MASK);
+ for (cx = 0; cx < len; cx++) {
+ if (cx % 8 == 7) {
+ monitor_printf(mon, "%02x\n", vals[cx]);
+ } else {
+ monitor_printf(mon, "%02x", vals[cx]);
+ }
+ }
+ monitor_printf(mon, "\n");
+
+out:
+ g_free(vals);
+}
+
+/* Migration support: */
+
+static int cmma_load(QEMUFile *f, void *opaque, int version_id)
+{
+ S390StAttribState *sas = S390_STATTRIB(opaque);
+ S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
+ uint64_t count, cur_gfn;
+ int flags, ret = 0;
+ ram_addr_t addr;
+ uint8_t *buf;
+
+ while (!ret) {
+ addr = qemu_get_be64(f);
+ flags = addr & ~TARGET_PAGE_MASK;
+ addr &= TARGET_PAGE_MASK;
+
+ switch (flags) {
+ case STATTR_FLAG_MORE: {
+ cur_gfn = addr / TARGET_PAGE_SIZE;
+ count = qemu_get_be64(f);
+ buf = g_try_malloc(count);
+ if (!buf) {
+ error_report("cmma_load could not allocate memory");
+ ret = -ENOMEM;
+ break;
+ }
+
+ qemu_get_buffer(f, buf, count);
+ ret = sac->set_stattr(sas, cur_gfn, count, buf);
+ if (ret < 0) {
+ error_report("Error %d while setting storage attributes", ret);
+ }
+ g_free(buf);
+ break;
+ }
+ case STATTR_FLAG_ERROR: {
+ error_report("Storage attributes data is incomplete");
+ ret = -EINVAL;
+ break;
+ }
+ case STATTR_FLAG_DONE:
+ /* This is after the last pre-copied value has been sent, nothing
+ * more will be sent after this. Pre-copy has finished, and we
+ * are done flushing all the remaining values. Now the target
+ * system is about to take over. We synchronize the buffer to
+ * apply the actual correct values where needed.
+ */
+ sac->synchronize(sas);
+ break;
+ case STATTR_FLAG_EOS:
+ /* Normal exit */
+ return 0;
+ default:
+ error_report("Unexpected storage attribute flag data: %#x", flags);
+ ret = -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+static int cmma_save_setup(QEMUFile *f, void *opaque)
+{
+ S390StAttribState *sas = S390_STATTRIB(opaque);
+ S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
+ int res;
+ /*
+ * Signal that we want to start a migration, thus needing PGSTE dirty
+ * tracking.
+ */
+ res = sac->set_migrationmode(sas, 1);
+ if (res) {
+ return res;
+ }
+ qemu_put_be64(f, STATTR_FLAG_EOS);
+ return 0;
+}
+
+static void cmma_save_pending(QEMUFile *f, void *opaque, uint64_t max_size,
+ uint64_t *non_postcopiable_pending,
+ uint64_t *postcopiable_pending)
+{
+ S390StAttribState *sas = S390_STATTRIB(opaque);
+ S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
+ long long res = sac->get_dirtycount(sas);
+
+ if (res >= 0) {
+ *non_postcopiable_pending += res;
+ }
+}
+
+static int cmma_save(QEMUFile *f, void *opaque, int final)
+{
+ S390StAttribState *sas = S390_STATTRIB(opaque);
+ S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
+ uint8_t *buf;
+ int r, cx, reallen = 0, ret = 0;
+ uint32_t buflen = 1 << 19; /* 512kB cover 2GB of guest memory */
+ uint64_t start_gfn = sas->migration_cur_gfn;
+
+ buf = g_try_malloc(buflen);
+ if (!buf) {
+ error_report("Could not allocate memory to save storage attributes");
+ return -ENOMEM;
+ }
+
+ while (final ? 1 : qemu_file_rate_limit(f) == 0) {
+ reallen = sac->get_stattr(sas, &start_gfn, buflen, buf);
+ if (reallen < 0) {
+ g_free(buf);
+ return reallen;
+ }
+
+ ret = 1;
+ if (!reallen) {
+ break;
+ }
+ qemu_put_be64(f, (start_gfn << TARGET_PAGE_BITS) | STATTR_FLAG_MORE);
+ qemu_put_be64(f, reallen);
+ for (cx = 0; cx < reallen; cx++) {
+ qemu_put_byte(f, buf[cx]);
+ }
+ if (!sac->get_dirtycount(sas)) {
+ break;
+ }
+ }
+
+ sas->migration_cur_gfn = start_gfn + reallen;
+ g_free(buf);
+ if (final) {
+ qemu_put_be64(f, STATTR_FLAG_DONE);
+ }
+ qemu_put_be64(f, STATTR_FLAG_EOS);
+
+ r = qemu_file_get_error(f);
+ if (r < 0) {
+ return r;
+ }
+
+ return ret;
+}
+
+static int cmma_save_iterate(QEMUFile *f, void *opaque)
+{
+ return cmma_save(f, opaque, 0);
+}
+
+static int cmma_save_complete(QEMUFile *f, void *opaque)
+{
+ return cmma_save(f, opaque, 1);
+}
+
+static void cmma_save_cleanup(void *opaque)
+{
+ S390StAttribState *sas = S390_STATTRIB(opaque);
+ S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
+ sac->set_migrationmode(sas, 0);
+}
+
+static bool cmma_active(void *opaque)
+{
+ S390StAttribState *sas = S390_STATTRIB(opaque);
+ S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
+ return sac->get_active(sas);
+}
+
+/* QEMU object: */
+
+static void qemu_s390_stattrib_instance_init(Object *obj)
+{
+}
+
+static int qemu_s390_peek_stattr_stub(S390StAttribState *sa, uint64_t start_gfn,
+ uint32_t count, uint8_t *values)
+{
+ return 0;
+}
+static void qemu_s390_synchronize_stub(S390StAttribState *sa)
+{
+}
+static int qemu_s390_get_stattr_stub(S390StAttribState *sa, uint64_t *start_gfn,
+ uint32_t count, uint8_t *values)
+{
+ return 0;
+}
+static long long qemu_s390_get_dirtycount_stub(S390StAttribState *sa)
+{
+ return 0;
+}
+static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value)
+{
+ return 0;
+}
+
+static int qemu_s390_get_active(S390StAttribState *sa)
+{
+ return sa->migration_enabled;
+}
+
+static void qemu_s390_stattrib_class_init(ObjectClass *oc, void *data)
+{
+ S390StAttribClass *sa_cl = S390_STATTRIB_CLASS(oc);
+
+ sa_cl->synchronize = qemu_s390_synchronize_stub;
+ sa_cl->get_stattr = qemu_s390_get_stattr_stub;
+ sa_cl->set_stattr = qemu_s390_peek_stattr_stub;
+ sa_cl->peek_stattr = qemu_s390_peek_stattr_stub;
+ sa_cl->set_migrationmode = qemu_s390_set_migrationmode_stub;
+ sa_cl->get_dirtycount = qemu_s390_get_dirtycount_stub;
+ sa_cl->get_active = qemu_s390_get_active;
+}
+
+static const TypeInfo qemu_s390_stattrib_info = {
+ .name = TYPE_QEMU_S390_STATTRIB,
+ .parent = TYPE_S390_STATTRIB,
+ .instance_init = qemu_s390_stattrib_instance_init,
+ .instance_size = sizeof(QEMUS390StAttribState),
+ .class_init = qemu_s390_stattrib_class_init,
+ .class_size = sizeof(S390StAttribClass),
+};
+
+/* Generic abstract object: */
+
+static void s390_stattrib_realize(DeviceState *dev, Error **errp)
+{
+ bool ambiguous = false;
+
+ object_resolve_path_type("", TYPE_S390_STATTRIB, &ambiguous);
+ if (ambiguous) {
+ error_setg(errp, "storage_attributes device already exists");
+ }
+}
+
+static void s390_stattrib_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->hotpluggable = false;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ dc->realize = s390_stattrib_realize;
+}
+
+static inline bool s390_stattrib_get_migration_enabled(Object *obj, Error **e)
+{
+ S390StAttribState *s = S390_STATTRIB(obj);
+
+ return s->migration_enabled;
+}
+
+static inline void s390_stattrib_set_migration_enabled(Object *obj, bool value,
+ Error **errp)
+{
+ S390StAttribState *s = S390_STATTRIB(obj);
+
+ s->migration_enabled = value;
+}
+
+static void s390_stattrib_instance_init(Object *obj)
+{
+ S390StAttribState *sas = S390_STATTRIB(obj);
+ SaveVMHandlers *ops;
+
+ /* ops will always be freed by qemu when unregistering */
+ ops = g_new0(SaveVMHandlers, 1);
+
+ ops->save_setup = cmma_save_setup;
+ ops->save_live_iterate = cmma_save_iterate;
+ ops->save_live_complete_precopy = cmma_save_complete;
+ ops->save_live_pending = cmma_save_pending;
+ ops->save_cleanup = cmma_save_cleanup;
+ ops->load_state = cmma_load;
+ ops->is_active = cmma_active;
+ register_savevm_live(NULL, TYPE_S390_STATTRIB, 0, 0, ops, sas);
+
+ object_property_add_bool(obj, "migration-enabled",
+ s390_stattrib_get_migration_enabled,
+ s390_stattrib_set_migration_enabled, NULL);
+ object_property_set_bool(obj, true, "migration-enabled", NULL);
+ sas->migration_cur_gfn = 0;
+}
+
+static const TypeInfo s390_stattrib_info = {
+ .name = TYPE_S390_STATTRIB,
+ .parent = TYPE_DEVICE,
+ .instance_init = s390_stattrib_instance_init,
+ .instance_size = sizeof(S390StAttribState),
+ .class_init = s390_stattrib_class_init,
+ .class_size = sizeof(S390StAttribClass),
+ .abstract = true,
+};
+
+static void s390_stattrib_register_types(void)
+{
+ type_register_static(&s390_stattrib_info);
+ type_register_static(&qemu_s390_stattrib_info);
+}
+
+type_init(s390_stattrib_register_types)
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 41ca6668e2..ce3921e4de 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -24,11 +24,13 @@
#include "qemu/config-file.h"
#include "s390-pci-bus.h"
#include "hw/s390x/storage-keys.h"
+#include "hw/s390x/storage-attributes.h"
#include "hw/compat.h"
#include "ipl.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/css-bridge.h"
#include "migration/register.h"
+#include "cpu_models.h"
static const char *const reset_dev_types[] = {
TYPE_VIRTUAL_CSS_BRIDGE,
@@ -103,6 +105,8 @@ void s390_memory_init(ram_addr_t mem_size)
/* Initialize storage key device */
s390_skeys_init();
+ /* Initialize storage attributes device */
+ s390_stattrib_init();
}
static SaveVMHandlers savevm_gtod = {
@@ -119,6 +123,9 @@ static void ccw_init(MachineState *machine)
s390_sclp_init();
s390_memory_init(machine->ram_size);
+ /* init CPUs */
+ s390_init_cpus(machine);
+
s390_flic_init();
/* get a BUS */
@@ -135,9 +142,6 @@ static void ccw_init(MachineState *machine)
/* register hypercalls */
virtio_ccw_register_hcalls();
- /* init CPUs */
- s390_init_cpus(machine);
-
if (kvm_enabled()) {
kvm_s390_enable_css_support(s390_cpu_addr2state(0));
}
@@ -206,6 +210,8 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
s390mc->ri_allowed = true;
s390mc->cpu_model_allowed = true;
+ s390mc->css_migration_enabled = true;
+ s390mc->gs_allowed = true;
mc->init = ccw_init;
mc->reset = s390_machine_reset;
mc->hot_add_cpu = s390_hot_add_cpu;
@@ -252,36 +258,51 @@ static inline void machine_set_dea_key_wrap(Object *obj, bool value,
ms->dea_key_wrap = value;
}
+static S390CcwMachineClass *current_mc;
+
+static S390CcwMachineClass *get_machine_class(void)
+{
+ if (unlikely(!current_mc)) {
+ /*
+ * No s390 ccw machine was instantiated, we are likely to
+ * be called for the 'none' machine. The properties will
+ * have their after-initialization values.
+ */
+ current_mc = S390_MACHINE_CLASS(
+ object_class_by_name(TYPE_S390_CCW_MACHINE));
+ }
+ return current_mc;
+}
+
bool ri_allowed(void)
{
+ if (!kvm_enabled()) {
+ return false;
+ }
+ /* for "none" machine this results in true */
+ return get_machine_class()->ri_allowed;
+}
+
+bool cpu_model_allowed(void)
+{
+ /* for "none" machine this results in true */
+ return get_machine_class()->cpu_model_allowed;
+}
+
+bool gs_allowed(void)
+{
if (kvm_enabled()) {
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
if (object_class_dynamic_cast(OBJECT_CLASS(mc),
TYPE_S390_CCW_MACHINE)) {
S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
- return s390mc->ri_allowed;
+ return s390mc->gs_allowed;
}
- /*
- * Make sure the "none" machine can have ri, otherwise it won't * be
- * unlocked in KVM and therefore the host CPU model might be wrong.
- */
+ /* Make sure the "none" machine can have gs */
return true;
}
- return 0;
-}
-
-bool cpu_model_allowed(void)
-{
- MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
- if (object_class_dynamic_cast(OBJECT_CLASS(mc),
- TYPE_S390_CCW_MACHINE)) {
- S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
-
- return s390mc->cpu_model_allowed;
- }
- /* allow CPU model qmp queries with the "none" machine */
- return true;
+ return false;
}
static char *machine_get_loadparm(Object *obj, Error **errp)
@@ -376,6 +397,11 @@ static const TypeInfo ccw_machine_info = {
},
};
+bool css_migration_enabled(void)
+{
+ return get_machine_class()->css_migration_enabled;
+}
+
#define DEFINE_CCW_MACHINE(suffix, verstr, latest) \
static void ccw_machine_##suffix##_class_init(ObjectClass *oc, \
void *data) \
@@ -391,6 +417,7 @@ static const TypeInfo ccw_machine_info = {
static void ccw_machine_##suffix##_instance_init(Object *obj) \
{ \
MachineState *machine = MACHINE(obj); \
+ current_mc = S390_MACHINE_CLASS(MACHINE_GET_CLASS(machine)); \
ccw_machine_##suffix##_instance_options(machine); \
} \
static const TypeInfo ccw_machine_##suffix##_info = { \
@@ -406,7 +433,12 @@ static const TypeInfo ccw_machine_info = {
type_init(ccw_machine_register_##suffix)
#define CCW_COMPAT_2_9 \
- HW_COMPAT_2_9
+ HW_COMPAT_2_9 \
+ {\
+ .driver = TYPE_S390_STATTRIB,\
+ .property = "migration-enabled",\
+ .value = "off",\
+ },
#define CCW_COMPAT_2_8 \
HW_COMPAT_2_8 \
@@ -476,6 +508,9 @@ static const TypeInfo ccw_machine_info = {
static void ccw_machine_2_10_instance_options(MachineState *machine)
{
+ if (css_migration_enabled()) {
+ css_register_vmstate();
+ }
}
static void ccw_machine_2_10_class_options(MachineClass *mc)
@@ -486,12 +521,21 @@ DEFINE_CCW_MACHINE(2_10, "2.10", true);
static void ccw_machine_2_9_instance_options(MachineState *machine)
{
ccw_machine_2_10_instance_options(machine);
+ s390_cpudef_featoff_greater(12, 1, S390_FEAT_ESOP);
+ s390_cpudef_featoff_greater(12, 1, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2);
+ s390_cpudef_featoff_greater(12, 1, S390_FEAT_ZPCI);
+ s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_INT_SUPPRESSION);
+ s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_EVENT_NOTIFICATION);
}
static void ccw_machine_2_9_class_options(MachineClass *mc)
{
+ S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
+
+ s390mc->gs_allowed = false;
ccw_machine_2_10_class_options(mc);
SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_9);
+ s390mc->css_migration_enabled = false;
}
DEFINE_CCW_MACHINE(2_9, "2.9", false);
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index 83d6023894..9253dbbc64 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -273,7 +273,6 @@ static void assign_storage(SCLPDevice *sclp, SCCB *sccb)
* instead of doing it via the ref count of the MemoryRegion. */
object_ref(OBJECT(standby_ram));
object_unparent(OBJECT(standby_ram));
- vmstate_register_ram_global(standby_ram);
memory_region_add_subregion(sysmem, offset, standby_ram);
}
/* The specified subregion is no longer in standby */
diff --git a/hw/s390x/trace-events b/hw/s390x/trace-events
index 84ea964875..f07e974678 100644
--- a/hw/s390x/trace-events
+++ b/hw/s390x/trace-events
@@ -8,6 +8,7 @@ css_new_image(uint8_t cssid, const char *default_cssid) "CSS: add css image %02x
css_assign_subch(const char *do_assign, uint8_t cssid, uint8_t ssid, uint16_t schid, uint16_t devno) "CSS: %s %x.%x.%04x (devno %04x)"
css_io_interrupt(int cssid, int ssid, int schid, uint32_t intparm, uint8_t isc, const char *conditional) "CSS: I/O interrupt on sch %x.%x.%04x (intparm %08x, isc %x) %s"
css_adapter_interrupt(uint8_t isc) "CSS: adapter I/O interrupt (isc %x)"
+css_do_sic(uint16_t mode, uint8_t isc) "CSS: set interruption mode %x on isc %x"
# hw/s390x/virtio-ccw.c
virtio_ccw_interpret_ccw(int cssid, int ssid, int schid, int cmd_code) "VIRTIO-CCW: %x.%x.%04x: interpret command %x"
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index e18fd2600d..b1976fdd19 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -867,8 +867,6 @@ static void virtio_ccw_blk_instance_init(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_BLK);
- object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
- &error_abort);
object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
"bootindex", &error_abort);
}
@@ -952,8 +950,6 @@ static void virtio_ccw_scsi_instance_init(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_SCSI);
- object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
- &error_abort);
}
#ifdef CONFIG_VHOST_SCSI
@@ -1074,7 +1070,7 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
0x80 >> ((ind_bit + vector) % 8));
if (!virtio_set_ind_atomic(sch, dev->summary_indicator->addr,
0x01)) {
- css_adapter_interrupt(dev->thinint_isc);
+ css_adapter_interrupt(CSS_IO_ADAPTER_VIRTIO, dev->thinint_isc);
}
} else {
indicators = address_space_ldq(&address_space_memory,
@@ -1552,8 +1548,6 @@ static void virtio_ccw_rng_instance_init(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_RNG);
- object_property_add_alias(obj, "rng", OBJECT(&dev->vdev),
- "rng", &error_abort);
}
static Property virtio_ccw_rng_properties[] = {
@@ -1600,9 +1594,6 @@ static void virtio_ccw_crypto_instance_init(Object *obj)
ccw_dev->force_revision_1 = true;
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_CRYPTO);
-
- object_property_add_alias(obj, "cryptodev", OBJECT(&dev->vdev),
- "cryptodev", &error_abort);
}
static void virtio_ccw_crypto_class_init(ObjectClass *klass, void *data)
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index f5574469c8..23c51de66a 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -282,9 +282,9 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated)
continue; /* claimed */
}
if (!dinfo->is_default) {
- error_report("warning: bus=%d,unit=%d is deprecated with this"
- " machine type",
- bus->busnr, unit);
+ warn_report("bus=%d,unit=%d is deprecated with this"
+ " machine type",
+ bus->busnr, unit);
}
}
scsi_bus_legacy_add_drive(bus, blk_by_legacy_dinfo(dinfo),
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index d076fe778b..eb639442d1 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -898,16 +898,6 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
virtio_scsi_dataplane_setup(s, errp);
}
-static void virtio_scsi_instance_init(Object *obj)
-{
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(obj);
-
- object_property_add_link(obj, "iothread", TYPE_IOTHREAD,
- (Object **)&vs->conf.iothread,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);
-}
-
void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
@@ -935,6 +925,8 @@ static Property virtio_scsi_properties[] = {
VIRTIO_SCSI_F_HOTPLUG, true),
DEFINE_PROP_BIT("param_change", VirtIOSCSI, host_features,
VIRTIO_SCSI_F_CHANGE, true),
+ DEFINE_PROP_LINK("iothread", VirtIOSCSI, parent_obj.conf.iothread,
+ TYPE_IOTHREAD, IOThread *),
DEFINE_PROP_END_OF_LIST(),
};
@@ -989,7 +981,6 @@ static const TypeInfo virtio_scsi_info = {
.name = TYPE_VIRTIO_SCSI,
.parent = TYPE_VIRTIO_SCSI_COMMON,
.instance_size = sizeof(VirtIOSCSI),
- .instance_init = virtio_scsi_instance_init,
.class_init = virtio_scsi_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c
index e6fc74ed87..a0462adb97 100644
--- a/hw/sh4/r2d.c
+++ b/hw/sh4/r2d.c
@@ -260,7 +260,6 @@ static void r2d_init(MachineState *machine)
/* Allocate memory space */
memory_region_init_ram(sdram, NULL, "r2d.sdram", SDRAM_SIZE, &error_fatal);
- vmstate_register_ram_global(sdram);
memory_region_add_subregion(address_space_mem, SDRAM_BASE, sdram);
/* Register peripherals */
s = sh7750_init(cpu, address_space_mem);
diff --git a/hw/sh4/shix.c b/hw/sh4/shix.c
index fd00cc5ea2..e22eaf0c8f 100644
--- a/hw/sh4/shix.c
+++ b/hw/sh4/shix.c
@@ -64,16 +64,13 @@ static void shix_init(MachineState *machine)
/* Allocate memory space */
memory_region_init_ram(rom, NULL, "shix.rom", 0x4000, &error_fatal);
- vmstate_register_ram_global(rom);
memory_region_set_readonly(rom, true);
memory_region_add_subregion(sysmem, 0x00000000, rom);
memory_region_init_ram(&sdram[0], NULL, "shix.sdram1", 0x01000000,
&error_fatal);
- vmstate_register_ram_global(&sdram[0]);
memory_region_add_subregion(sysmem, 0x08000000, &sdram[0]);
memory_region_init_ram(&sdram[1], NULL, "shix.sdram2", 0x01000000,
&error_fatal);
- vmstate_register_ram_global(&sdram[1]);
memory_region_add_subregion(sysmem, 0x0c000000, &sdram[1]);
/* Load BIOS in 0 (and access it through P2, 0xA0000000) */
diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c
index f415997649..d5ff188d9e 100644
--- a/hw/sparc/leon3.c
+++ b/hw/sparc/leon3.c
@@ -160,7 +160,6 @@ static void leon3_generic_hw_init(MachineState *machine)
/* Allocate BIOS */
prom_size = 8 * 1024 * 1024; /* 8Mb */
memory_region_init_ram(prom, NULL, "Leon3.bios", prom_size, &error_fatal);
- vmstate_register_ram_global(prom);
memory_region_set_readonly(prom, true);
memory_region_add_subregion(address_space_mem, 0x00000000, prom);
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 0faff4619f..89dd8a96c3 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -590,7 +590,7 @@ static void idreg_init1(Object *obj)
IDRegState *s = MACIO_ID_REGISTER(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- memory_region_init_ram(&s->mem, obj,
+ memory_region_init_ram_nomigrate(&s->mem, obj,
"sun4m.idreg", sizeof(idreg_data), &error_fatal);
vmstate_register_ram_global(&s->mem);
memory_region_set_readonly(&s->mem, true);
@@ -631,7 +631,7 @@ static void afx_init1(Object *obj)
AFXState *s = TCX_AFX(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- memory_region_init_ram(&s->mem, obj, "sun4m.afx", 4, &error_fatal);
+ memory_region_init_ram_nomigrate(&s->mem, obj, "sun4m.afx", 4, &error_fatal);
vmstate_register_ram_global(&s->mem);
sysbus_init_mmio(dev, &s->mem);
}
@@ -698,7 +698,7 @@ static void prom_init1(Object *obj)
PROMState *s = OPENPROM(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- memory_region_init_ram(&s->prom, obj, "sun4m.prom", PROM_SIZE_MAX,
+ memory_region_init_ram_nomigrate(&s->prom, obj, "sun4m.prom", PROM_SIZE_MAX,
&error_fatal);
vmstate_register_ram_global(&s->prom);
memory_region_set_readonly(&s->prom, true);
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index 69f565db25..bbdb40c330 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -334,7 +334,7 @@ static void prom_init1(Object *obj)
PROMState *s = OPENPROM(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- memory_region_init_ram(&s->prom, obj, "sun4u.prom", PROM_SIZE_MAX,
+ memory_region_init_ram_nomigrate(&s->prom, obj, "sun4u.prom", PROM_SIZE_MAX,
&error_fatal);
vmstate_register_ram_global(&s->prom);
memory_region_set_readonly(&s->prom, true);
@@ -377,7 +377,7 @@ static void ram_realize(DeviceState *dev, Error **errp)
RamDevice *d = SUN4U_RAM(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- memory_region_init_ram(&d->ram, OBJECT(d), "sun4u.ram", d->size,
+ memory_region_init_ram_nomigrate(&d->ram, OBJECT(d), "sun4u.ram", d->size,
&error_fatal);
vmstate_register_ram_global(&d->ram);
sysbus_init_mmio(sbd, &d->ram);
diff --git a/hw/tricore/tricore_testboard.c b/hw/tricore/tricore_testboard.c
index 8910bf0f27..6c574231d5 100644
--- a/hw/tricore/tricore_testboard.c
+++ b/hw/tricore/tricore_testboard.c
@@ -80,24 +80,18 @@ static void tricore_testboard_init(MachineState *machine, int board_id)
exit(1);
}
env = &cpu->env;
- memory_region_init_ram(ext_cram, NULL, "powerlink_ext_c.ram", 2*1024*1024,
+ memory_region_init_ram(ext_cram, NULL, "powerlink_ext_c.ram",
+ 2 * 1024 * 1024, &error_fatal);
+ memory_region_init_ram(ext_dram, NULL, "powerlink_ext_d.ram",
+ 4 * 1024 * 1024, &error_fatal);
+ memory_region_init_ram(int_cram, NULL, "powerlink_int_c.ram", 48 * 1024,
&error_fatal);
- vmstate_register_ram_global(ext_cram);
- memory_region_init_ram(ext_dram, NULL, "powerlink_ext_d.ram", 4*1024*1024,
+ memory_region_init_ram(int_dram, NULL, "powerlink_int_d.ram", 48 * 1024,
&error_fatal);
- vmstate_register_ram_global(ext_dram);
- memory_region_init_ram(int_cram, NULL, "powerlink_int_c.ram", 48*1024,
- &error_fatal);
- vmstate_register_ram_global(int_cram);
- memory_region_init_ram(int_dram, NULL, "powerlink_int_d.ram", 48*1024,
- &error_fatal);
- vmstate_register_ram_global(int_dram);
- memory_region_init_ram(pcp_data, NULL, "powerlink_pcp_data.ram", 16*1024,
- &error_fatal);
- vmstate_register_ram_global(pcp_data);
- memory_region_init_ram(pcp_text, NULL, "powerlink_pcp_text.ram", 32*1024,
- &error_fatal);
- vmstate_register_ram_global(pcp_text);
+ memory_region_init_ram(pcp_data, NULL, "powerlink_pcp_data.ram",
+ 16 * 1024, &error_fatal);
+ memory_region_init_ram(pcp_text, NULL, "powerlink_pcp_text.ram",
+ 32 * 1024, &error_fatal);
memory_region_add_subregion(sysmem, 0x80000000, ext_cram);
memory_region_add_subregion(sysmem, 0xa1000000, ext_dram);
diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c
index 032078fd3e..e9d1a60b6f 100644
--- a/hw/unicore32/puv3.c
+++ b/hw/unicore32/puv3.c
@@ -80,7 +80,6 @@ static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size)
/* SDRAM at address zero. */
memory_region_init_ram(ram_memory, NULL, "puv3.ram", ram_size,
&error_fatal);
- vmstate_register_ram_global(ram_memory);
memory_region_add_subregion(get_system_memory(), 0, ram_memory);
}
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index ac1725eeae..45d96b03c6 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -322,7 +322,7 @@ static void passthru_apdu_from_guest(
{
PassthruState *card = PASSTHRU_CCID_CARD(base);
- if (!qemu_chr_fe_get_driver(&card->cs)) {
+ if (!qemu_chr_fe_backend_connected(&card->cs)) {
printf("ccid-passthru: no chardev, discarding apdu length %d\n", len);
return;
}
@@ -343,12 +343,12 @@ static int passthru_initfn(CCIDCardState *base)
card->vscard_in_pos = 0;
card->vscard_in_hdr = 0;
- if (qemu_chr_fe_get_driver(&card->cs)) {
+ if (qemu_chr_fe_backend_connected(&card->cs)) {
DPRINTF(card, D_INFO, "initing chardev\n");
qemu_chr_fe_set_handlers(&card->cs,
ccid_card_vscard_can_read,
ccid_card_vscard_read,
- ccid_card_vscard_event, card, NULL, true);
+ ccid_card_vscard_event, NULL, card, NULL, true);
ccid_card_vscard_send_init(card);
} else {
error_report("missing chardev");
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index bfbf7cdce7..94b5c34afe 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -484,13 +484,12 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
{
USBSerialState *s = USB_SERIAL_DEV(dev);
Error *local_err = NULL;
- Chardev *chr = qemu_chr_fe_get_driver(&s->cs);
usb_desc_create_serial(dev);
usb_desc_init(dev);
dev->auto_attach = 0;
- if (!chr) {
+ if (!qemu_chr_fe_backend_connected(&s->cs)) {
error_setg(errp, "Property chardev is required");
return;
}
@@ -502,10 +501,10 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
}
qemu_chr_fe_set_handlers(&s->cs, usb_serial_can_read, usb_serial_read,
- usb_serial_event, s, NULL, true);
+ usb_serial_event, NULL, s, NULL, true);
usb_serial_handle_reset(dev);
- if (chr->be_open && !dev->attached) {
+ if (qemu_chr_fe_backend_open(&s->cs) && !dev->attached) {
usb_device_attach(dev, &error_abort);
}
}
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 49cb1829b5..bef1f03c42 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -1314,12 +1314,12 @@ static int ccid_card_init(DeviceState *qdev)
int ret = 0;
if (card->slot != 0) {
- error_report("Warning: usb-ccid supports one slot, can't add %d",
- card->slot);
+ warn_report("usb-ccid supports one slot, can't add %d",
+ card->slot);
return -1;
}
if (s->card != NULL) {
- error_report("Warning: usb-ccid card already full, not adding");
+ warn_report("usb-ccid card already full, not adding");
return -1;
}
ret = ccid_card_initfn(card);
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index aa22d69216..5e42730449 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -193,7 +193,7 @@ static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p,
#define WARNING(...) \
do { \
if (dev->debug >= usbredirparser_warning) { \
- error_report("usb-redir warning: " __VA_ARGS__); \
+ warn_report("" __VA_ARGS__); \
} \
} while (0)
#define INFO(...) \
@@ -273,10 +273,9 @@ static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
static int usbredir_write(void *priv, uint8_t *data, int count)
{
USBRedirDevice *dev = priv;
- Chardev *chr = qemu_chr_fe_get_driver(&dev->cs);
int r;
- if (!chr->be_open) {
+ if (!qemu_chr_fe_backend_open(&dev->cs)) {
return 0;
}
@@ -1366,7 +1365,7 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
USBRedirDevice *dev = USB_REDIRECT(udev);
int i;
- if (!qemu_chr_fe_get_driver(&dev->cs)) {
+ if (!qemu_chr_fe_backend_connected(&dev->cs)) {
error_setg(errp, QERR_MISSING_PARAMETER, "chardev");
return;
}
@@ -1399,7 +1398,7 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
/* Let the backend know we are ready */
qemu_chr_fe_set_handlers(&dev->cs, usbredir_chardev_can_read,
usbredir_chardev_read, usbredir_chardev_event,
- dev, NULL, true);
+ NULL, dev, NULL, true);
dev->vmstate =
qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 29923e4990..c1bb6d429a 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -479,6 +479,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
if (memory_region_is_iommu(section->mr)) {
VFIOGuestIOMMU *giommu;
+ IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
trace_vfio_listener_region_add_iommu(iova, end);
/*
@@ -488,7 +489,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
* device emulation the VFIO iommu handles to use).
*/
giommu = g_malloc0(sizeof(*giommu));
- giommu->iommu = section->mr;
+ giommu->iommu = iommu_mr;
giommu->iommu_offset = section->offset_within_address_space -
section->offset_within_region;
giommu->container = container;
@@ -501,7 +502,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
int128_get64(llend));
QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
- memory_region_register_iommu_notifier(giommu->iommu, &giommu->n);
+ memory_region_register_iommu_notifier(section->mr, &giommu->n);
memory_region_iommu_replay(giommu->iommu, &giommu->n);
return;
@@ -569,9 +570,9 @@ static void vfio_listener_region_del(MemoryListener *listener,
VFIOGuestIOMMU *giommu;
QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) {
- if (giommu->iommu == section->mr &&
+ if (MEMORY_REGION(giommu->iommu) == section->mr &&
giommu->n.start == section->offset_within_region) {
- memory_region_unregister_iommu_notifier(giommu->iommu,
+ memory_region_unregister_iommu_notifier(section->mr,
&giommu->n);
QLIST_REMOVE(giommu, giommu_next);
g_free(giommu);
@@ -1163,7 +1164,8 @@ static void vfio_disconnect_container(VFIOGroup *group)
QLIST_REMOVE(container, next);
QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) {
- memory_region_unregister_iommu_notifier(giommu->iommu, &giommu->n);
+ memory_region_unregister_iommu_notifier(
+ MEMORY_REGION(giommu->iommu), &giommu->n);
QLIST_REMOVE(giommu, giommu_next);
g_free(giommu);
}
diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c
index 4409bcc0d7..32fd6a9b54 100644
--- a/hw/vfio/spapr.c
+++ b/hw/vfio/spapr.c
@@ -143,7 +143,8 @@ int vfio_spapr_create_window(VFIOContainer *container,
hwaddr *pgsize)
{
int ret;
- unsigned pagesize = memory_region_iommu_get_min_page_size(section->mr);
+ IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
+ unsigned pagesize = memory_region_iommu_get_min_page_size(iommu_mr);
unsigned entries, pages;
struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) };
diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c
index 422aca3a98..bf64996e48 100644
--- a/hw/virtio/virtio-crypto-pci.c
+++ b/hw/virtio/virtio-crypto-pci.c
@@ -62,8 +62,6 @@ static void virtio_crypto_initfn(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_CRYPTO);
- object_property_add_alias(obj, "cryptodev", OBJECT(&dev->vdev),
- "cryptodev", &error_abort);
}
static const TypeInfo virtio_crypto_pci_info = {
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index 0353eb6d5d..19c82e0432 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -781,6 +781,11 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp)
if (vcrypto->cryptodev == NULL) {
error_setg(errp, "'cryptodev' parameter expects a valid object");
return;
+ } else if (cryptodev_backend_is_used(vcrypto->cryptodev)) {
+ char *path = object_get_canonical_path_component(OBJECT(vcrypto->conf.cryptodev));
+ error_setg(errp, "can't use already used cryptodev backend: %s", path);
+ g_free(path);
+ return;
}
vcrypto->max_queues = MAX(vcrypto->cryptodev->conf.peers.queues, 1);
@@ -845,6 +850,8 @@ static const VMStateDescription vmstate_virtio_crypto = {
};
static Property virtio_crypto_properties[] = {
+ DEFINE_PROP_LINK("cryptodev", VirtIOCrypto, conf.cryptodev,
+ TYPE_CRYPTODEV_BACKEND, CryptoDevBackend *),
DEFINE_PROP_END_OF_LIST(),
};
@@ -888,20 +895,6 @@ static void virtio_crypto_class_init(ObjectClass *klass, void *data)
vdc->reset = virtio_crypto_reset;
}
-static void
-virtio_crypto_check_cryptodev_is_used(Object *obj, const char *name,
- Object *val, Error **errp)
-{
- if (cryptodev_backend_is_used(CRYPTODEV_BACKEND(val))) {
- char *path = object_get_canonical_path_component(val);
- error_setg(errp,
- "can't use already used cryptodev backend: %s", path);
- g_free(path);
- } else {
- qdev_prop_allow_set_link_before_realize(obj, name, val, errp);
- }
-}
-
static void virtio_crypto_instance_init(Object *obj)
{
VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(obj);
@@ -911,12 +904,6 @@ static void virtio_crypto_instance_init(Object *obj)
* Can be overriden with virtio_crypto_set_config_size.
*/
vcrypto->config_size = sizeof(struct virtio_crypto_config);
-
- object_property_add_link(obj, "cryptodev",
- TYPE_CRYPTODEV_BACKEND,
- (Object **)&vcrypto->conf.cryptodev,
- virtio_crypto_check_cryptodev_is_used,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
}
static const TypeInfo virtio_crypto_info = {
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 93480a7af1..5d14bd66dc 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -2000,8 +2000,6 @@ static void virtio_blk_pci_instance_init(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_BLK);
- object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
- &error_abort);
object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
"bootindex", &error_abort);
}
@@ -2071,8 +2069,6 @@ static void virtio_scsi_pci_instance_init(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_SCSI);
- object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
- &error_abort);
}
static const TypeInfo virtio_scsi_pci_info = {
@@ -2467,8 +2463,6 @@ static void virtio_rng_initfn(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_RNG);
- object_property_add_alias(obj, "rng", OBJECT(&dev->vdev), "rng",
- &error_abort);
}
static const TypeInfo virtio_rng_pci_info = {
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index a6ee501051..289bbcac03 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -246,6 +246,7 @@ static Property virtio_rng_properties[] = {
*/
DEFINE_PROP_UINT64("max-bytes", VirtIORNG, conf.max_bytes, INT64_MAX),
DEFINE_PROP_UINT32("period", VirtIORNG, conf.period_ms, 1 << 16),
+ DEFINE_PROP_LINK("rng", VirtIORNG, conf.rng, TYPE_RNG_BACKEND, RngBackend *),
DEFINE_PROP_END_OF_LIST(),
};
@@ -262,21 +263,10 @@ static void virtio_rng_class_init(ObjectClass *klass, void *data)
vdc->get_features = get_features;
}
-static void virtio_rng_initfn(Object *obj)
-{
- VirtIORNG *vrng = VIRTIO_RNG(obj);
-
- object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
- (Object **)&vrng->conf.rng,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
-}
-
static const TypeInfo virtio_rng_info = {
.name = TYPE_VIRTIO_RNG,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIORNG),
- .instance_init = virtio_rng_initfn,
.class_init = virtio_rng_class_init,
};
diff --git a/hw/xtensa/sim.c b/hw/xtensa/sim.c
index 5521e9184a..249cd1e8c9 100644
--- a/hw/xtensa/sim.c
+++ b/hw/xtensa/sim.c
@@ -49,9 +49,7 @@ static void xtensa_create_memory_regions(const XtensaMemory *memory,
g_string_printf(num_name, "%s%u", name, i);
m = g_new(MemoryRegion, 1);
memory_region_init_ram(m, NULL, num_name->str,
- memory->location[i].size,
- &error_fatal);
- vmstate_register_ram_global(m);
+ memory->location[i].size, &error_fatal);
memory_region_add_subregion(get_system_memory(),
memory->location[i].addr, m);
}
diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c
index d5ac080d4a..635a4d4ec3 100644
--- a/hw/xtensa/xtfpga.c
+++ b/hw/xtensa/xtfpga.c
@@ -147,7 +147,7 @@ static void lx60_net_init(MemoryRegion *address_space,
sysbus_mmio_get_region(s, 1));
ram = g_malloc(sizeof(*ram));
- memory_region_init_ram(ram, OBJECT(s), "open_eth.ram", 16384,
+ memory_region_init_ram_nomigrate(ram, OBJECT(s), "open_eth.ram", 16384,
&error_fatal);
vmstate_register_ram_global(ram);
memory_region_add_subregion(address_space, buffers, ram);
@@ -251,7 +251,6 @@ static void lx_init(const LxBoardDesc *board, MachineState *machine)
ram = g_malloc(sizeof(*ram));
memory_region_init_ram(ram, NULL, "lx60.dram", machine->ram_size,
&error_fatal);
- vmstate_register_ram_global(ram);
memory_region_add_subregion(system_memory, 0, ram);
system_io = g_malloc(sizeof(*system_io));
@@ -294,7 +293,6 @@ static void lx_init(const LxBoardDesc *board, MachineState *machine)
rom = g_malloc(sizeof(*rom));
memory_region_init_ram(rom, NULL, "lx60.sram", board->sram_size,
&error_fatal);
- vmstate_register_ram_global(rom);
memory_region_add_subregion(system_memory, 0xfe000000, rom);
if (kernel_cmdline) {
diff --git a/include/block/block.h b/include/block/block.h
index 4a2725267d..b3e2674845 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -302,10 +302,13 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
const char *backing_file);
int bdrv_get_backing_file_depth(BlockDriverState *bs);
void bdrv_refresh_filename(BlockDriverState *bs);
-int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp);
+int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
+ Error **errp);
int64_t bdrv_nb_sectors(BlockDriverState *bs);
int64_t bdrv_getlength(BlockDriverState *bs);
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
+BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts,
+ BlockDriverState *in_bs, Error **errp);
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
void bdrv_refresh_limits(BlockDriverState *bs, Error **errp);
int bdrv_commit(BlockDriverState *bs);
@@ -464,9 +467,6 @@ BlockDriverState *bdrv_next(BdrvNextIterator *it);
BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs);
bool bdrv_is_encrypted(BlockDriverState *bs);
-bool bdrv_key_required(BlockDriverState *bs);
-int bdrv_set_key(BlockDriverState *bs, const char *key);
-void bdrv_add_key(BlockDriverState *bs, const char *key, Error **errp);
void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
void *opaque);
const char *bdrv_get_node_name(const BlockDriverState *bs);
@@ -620,4 +620,7 @@ void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
Error **errp);
void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
+bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
+ uint32_t granularity, Error **errp);
+
#endif
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 15fa602150..5c6b761d81 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -37,11 +37,11 @@
#include "qemu/main-loop.h"
#include "qemu/throttle.h"
-#define BLOCK_FLAG_ENCRYPT 1
#define BLOCK_FLAG_LAZY_REFCOUNTS 8
#define BLOCK_OPT_SIZE "size"
#define BLOCK_OPT_ENCRYPT "encryption"
+#define BLOCK_OPT_ENCRYPT_FORMAT "encrypt.format"
#define BLOCK_OPT_COMPAT6 "compat6"
#define BLOCK_OPT_HWVERSION "hwversion"
#define BLOCK_OPT_BACKING_FILE "backing_file"
@@ -204,11 +204,14 @@ struct BlockDriver {
int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs);
const char *protocol_name;
- int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset, Error **errp);
+ int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset,
+ PreallocMode prealloc, Error **errp);
int64_t (*bdrv_getlength)(BlockDriverState *bs);
bool has_variable_length;
int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs);
+ BlockMeasureInfo *(*bdrv_measure)(QemuOpts *opts, BlockDriverState *in_bs,
+ Error **errp);
int coroutine_fn (*bdrv_co_pwritev_compressed)(BlockDriverState *bs,
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov);
@@ -321,7 +324,7 @@ struct BlockDriver {
* Drain and stop any internal sources of requests in the driver, and
* remain so until next I/O callback (e.g. bdrv_co_writev) is called.
*/
- void (*bdrv_drain)(BlockDriverState *bs);
+ void coroutine_fn (*bdrv_co_drain)(BlockDriverState *bs);
void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child,
Error **errp);
@@ -381,6 +384,20 @@ struct BlockDriver {
uint64_t parent_perm, uint64_t parent_shared,
uint64_t *nperm, uint64_t *nshared);
+ /**
+ * Bitmaps should be marked as 'IN_USE' in the image on reopening image
+ * as rw. This handler should realize it. It also should unset readonly
+ * field of BlockDirtyBitmap's in case of success.
+ */
+ int (*bdrv_reopen_bitmaps_rw)(BlockDriverState *bs, Error **errp);
+ bool (*bdrv_can_store_new_dirty_bitmap)(BlockDriverState *bs,
+ const char *name,
+ uint32_t granularity,
+ Error **errp);
+ void (*bdrv_remove_persistent_dirty_bitmap)(BlockDriverState *bs,
+ const char *name,
+ Error **errp);
+
QLIST_ENTRY(BlockDriver) list;
};
@@ -529,7 +546,6 @@ struct BlockDriverState {
int open_flags; /* flags used to open the file, re-used for re-open */
bool read_only; /* if true, the media is read only */
bool encrypted; /* if true, the media is encrypted */
- bool valid_key; /* if true, a valid encryption key has been set */
bool sg; /* if true, the device is a /dev/sg* */
bool probed; /* if true, format was probed rather than specified */
bool force_share; /* if true, always allow all shared permissions */
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index ad6558af56..a79a58d2c3 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -25,11 +25,15 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs,
void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap);
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs);
+void bdrv_release_persistent_dirty_bitmaps(BlockDriverState *bs);
+void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs,
+ const char *name,
+ Error **errp);
void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
-uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap);
+uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap);
uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
@@ -66,8 +70,16 @@ void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
uint64_t start, uint64_t count,
bool finish);
+void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
+ uint64_t start, uint64_t count,
+ bool finish);
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
+void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value);
+void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload);
+void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
+ bool persistent);
+
/* Functions that require manual locking. */
void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap);
@@ -82,5 +94,13 @@ void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
+bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
+bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);
+bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
+bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap);
+bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs);
+BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
+ BdrvDirtyBitmap *bitmap);
+char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp);
#endif
diff --git a/include/block/nbd.h b/include/block/nbd.h
index 6d75d5a670..9c3d0a5868 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Red Hat, Inc.
+ * Copyright (C) 2016-2017 Red Hat, Inc.
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device
@@ -83,18 +83,37 @@ typedef struct NBDReply NBDReply;
#define NBD_FLAG_C_FIXED_NEWSTYLE (1 << 0) /* Fixed newstyle protocol. */
#define NBD_FLAG_C_NO_ZEROES (1 << 1) /* End handshake without zeroes. */
-/* Reply types. */
+/* Option requests. */
+#define NBD_OPT_EXPORT_NAME (1)
+#define NBD_OPT_ABORT (2)
+#define NBD_OPT_LIST (3)
+/* #define NBD_OPT_PEEK_EXPORT (4) not in use */
+#define NBD_OPT_STARTTLS (5)
+#define NBD_OPT_INFO (6)
+#define NBD_OPT_GO (7)
+#define NBD_OPT_STRUCTURED_REPLY (8)
+
+/* Option reply types. */
#define NBD_REP_ERR(value) ((UINT32_C(1) << 31) | (value))
#define NBD_REP_ACK (1) /* Data sending finished. */
#define NBD_REP_SERVER (2) /* Export description. */
-
-#define NBD_REP_ERR_UNSUP NBD_REP_ERR(1) /* Unknown option */
-#define NBD_REP_ERR_POLICY NBD_REP_ERR(2) /* Server denied */
-#define NBD_REP_ERR_INVALID NBD_REP_ERR(3) /* Invalid length */
-#define NBD_REP_ERR_PLATFORM NBD_REP_ERR(4) /* Not compiled in */
-#define NBD_REP_ERR_TLS_REQD NBD_REP_ERR(5) /* TLS required */
-#define NBD_REP_ERR_SHUTDOWN NBD_REP_ERR(7) /* Server shutting down */
+#define NBD_REP_INFO (3) /* NBD_OPT_INFO/GO. */
+
+#define NBD_REP_ERR_UNSUP NBD_REP_ERR(1) /* Unknown option */
+#define NBD_REP_ERR_POLICY NBD_REP_ERR(2) /* Server denied */
+#define NBD_REP_ERR_INVALID NBD_REP_ERR(3) /* Invalid length */
+#define NBD_REP_ERR_PLATFORM NBD_REP_ERR(4) /* Not compiled in */
+#define NBD_REP_ERR_TLS_REQD NBD_REP_ERR(5) /* TLS required */
+#define NBD_REP_ERR_UNKNOWN NBD_REP_ERR(6) /* Export unknown */
+#define NBD_REP_ERR_SHUTDOWN NBD_REP_ERR(7) /* Server shutting down */
+#define NBD_REP_ERR_BLOCK_SIZE_REQD NBD_REP_ERR(8) /* Need INFO_BLOCK_SIZE */
+
+/* Info types, used during NBD_REP_INFO */
+#define NBD_INFO_EXPORT 0
+#define NBD_INFO_NAME 1
+#define NBD_INFO_DESCRIPTION 2
+#define NBD_INFO_BLOCK_SIZE 3
/* Request flags, sent from client to server during transmission phase */
#define NBD_CMD_FLAG_FUA (1 << 0) /* 'force unit access' during write */
@@ -123,13 +142,26 @@ enum {
* aren't overflowing some other buffer. */
#define NBD_MAX_NAME_SIZE 256
+/* Details collected by NBD_OPT_EXPORT_NAME and NBD_OPT_GO */
+struct NBDExportInfo {
+ /* Set by client before nbd_receive_negotiate() */
+ bool request_sizes;
+ /* Set by server results during nbd_receive_negotiate() */
+ uint64_t size;
+ uint16_t flags;
+ uint32_t min_block;
+ uint32_t opt_block;
+ uint32_t max_block;
+};
+typedef struct NBDExportInfo NBDExportInfo;
+
ssize_t nbd_rwv(QIOChannel *ioc, struct iovec *iov, size_t niov, size_t length,
bool do_read, Error **errp);
-int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
+int nbd_receive_negotiate(QIOChannel *ioc, const char *name,
QCryptoTLSCreds *tlscreds, const char *hostname,
- QIOChannel **outioc,
- off_t *size, Error **errp);
-int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size,
+ QIOChannel **outioc, NBDExportInfo *info,
+ Error **errp);
+int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
Error **errp);
ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request);
ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp);
diff --git a/include/chardev/char-fe.h b/include/chardev/char-fe.h
index 2cbb262f66..71cd069478 100644
--- a/include/chardev/char-fe.h
+++ b/include/chardev/char-fe.h
@@ -4,6 +4,7 @@
#include "chardev/char.h"
typedef void IOEventHandler(void *opaque, int event);
+typedef int BackendChangeHandler(void *opaque);
/* This is the backend as seen by frontend, the actual backend is
* Chardev */
@@ -12,6 +13,7 @@ struct CharBackend {
IOEventHandler *chr_event;
IOCanReadHandler *chr_can_read;
IOReadHandler *chr_read;
+ BackendChangeHandler *chr_be_change;
void *opaque;
int tag;
int fe_open;
@@ -44,16 +46,35 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del);
*
* Returns the driver associated with a CharBackend or NULL if no
* associated Chardev.
+ * Note: avoid this function as the driver should never be accessed directly,
+ * especially by the frontends that support chardevice hotswap.
+ * Consider qemu_chr_fe_backend_connected() to check for driver existence
*/
Chardev *qemu_chr_fe_get_driver(CharBackend *be);
/**
+ * @qemu_chr_fe_backend_connected:
+ *
+ * Returns true if there is a chardevice associated with @be.
+ */
+bool qemu_chr_fe_backend_connected(CharBackend *be);
+
+/**
+ * @qemu_chr_fe_backend_open:
+ *
+ * Returns true if chardevice associated with @be is open.
+ */
+bool qemu_chr_fe_backend_open(CharBackend *be);
+
+/**
* @qemu_chr_fe_set_handlers:
* @b: a CharBackend
* @fd_can_read: callback to get the amount of data the frontend may
* receive
* @fd_read: callback to receive data from char
* @fd_event: event callback
+ * @be_change: backend change callback; passing NULL means hot backend change
+ * is not supported and will not be attempted
* @opaque: an opaque pointer for the callbacks
* @context: a main loop context or NULL for the default
* @set_open: whether to call qemu_chr_fe_set_open() implicitely when
@@ -68,6 +89,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
IOCanReadHandler *fd_can_read,
IOReadHandler *fd_read,
IOEventHandler *fd_event,
+ BackendChangeHandler *be_change,
void *opaque,
GMainContext *context,
bool set_open);
diff --git a/include/chardev/char.h b/include/chardev/char.h
index 8a9ade4931..1604ea9143 100644
--- a/include/chardev/char.h
+++ b/include/chardev/char.h
@@ -81,6 +81,16 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend);
/**
+ * @qemu_chr_parse_opts:
+ *
+ * Parse the options to the ChardevBackend struct.
+ *
+ * Returns: a new backend or NULL on error
+ */
+ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts,
+ Error **errp);
+
+/**
* @qemu_chr_new:
*
* Create a new character backend from a URI.
@@ -93,6 +103,15 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend);
Chardev *qemu_chr_new(const char *label, const char *filename);
/**
+ * @qemu_chr_change:
+ *
+ * Change an existing character backend
+ *
+ * @opts the new backend options
+ */
+void qemu_chr_change(QemuOpts *opts, Error **errp);
+
+/**
* @qemu_chr_cleanup:
*
* Delete all chardevs (when leaving qemu)
diff --git a/include/crypto/block.h b/include/crypto/block.h
index 013a435f1b..f0e543bee1 100644
--- a/include/crypto/block.h
+++ b/include/crypto/block.h
@@ -71,6 +71,7 @@ typedef enum {
/**
* qcrypto_block_open:
* @options: the encryption options
+ * @optprefix: name prefix for options
* @readfunc: callback for reading data from the volume
* @opaque: data to pass to @readfunc
* @flags: bitmask of QCryptoBlockOpenFlags values
@@ -102,6 +103,7 @@ typedef enum {
* Returns: a block encryption format, or NULL on error
*/
QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
+ const char *optprefix,
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
@@ -109,7 +111,8 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
/**
* qcrypto_block_create:
- * @format: the encryption format
+ * @options: the encryption options
+ * @optprefix: name prefix for options
* @initfunc: callback for initializing volume header
* @writefunc: callback for writing data to the volume header
* @opaque: data to pass to @initfunc and @writefunc
@@ -133,6 +136,7 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
* Returns: a block encryption format, or NULL on error
*/
QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
+ const char *optprefix,
QCryptoBlockInitFunc initfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,
diff --git a/include/elf.h b/include/elf.h
index 0dbd3e968b..cd51434877 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -1476,6 +1476,7 @@ typedef struct elf64_shdr {
#define NT_TASKSTRUCT 4
#define NT_AUXV 6
#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */
+#define NT_S390_GS_CB 0x30b /* s390 guarded storage registers */
#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */
#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 (lower half) */
#define NT_S390_PREFIX 0x305 /* s390 prefix register */
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 8096d64a1d..bf8da2aa5a 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -290,6 +290,9 @@ static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu,
uint16_t idxmap)
{
}
+static inline void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
+{
+}
#endif
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index f9708bbcd6..9aa7756d92 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -58,15 +58,6 @@ void gdb_register_coprocessor(CPUState *cpu,
gdb_reg_cb get_reg, gdb_reg_cb set_reg,
int num_regs, const char *xml, int g_pos);
-static inline int cpu_index(CPUState *cpu)
-{
-#if defined(CONFIG_USER_ONLY)
- return cpu->host_tid;
-#else
- return cpu->cpu_index + 1;
-#endif
-}
-
/* The GDB remote protocol transfers values in target byte order. This means
* we can use the raw memory access routines to access the value buffer.
* Conveniently, these also handle the case where the buffer is mis-aligned.
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 8503685455..400dd4491b 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -25,6 +25,7 @@
#include "qemu/notify.h"
#include "qom/object.h"
#include "qemu/rcu.h"
+#include "hw/qdev-core.h"
#define RAM_ADDR_INVALID (~(ram_addr_t)0)
@@ -35,6 +36,16 @@
#define MEMORY_REGION(obj) \
OBJECT_CHECK(MemoryRegion, (obj), TYPE_MEMORY_REGION)
+#define TYPE_IOMMU_MEMORY_REGION "qemu:iommu-memory-region"
+#define IOMMU_MEMORY_REGION(obj) \
+ OBJECT_CHECK(IOMMUMemoryRegion, (obj), TYPE_IOMMU_MEMORY_REGION)
+#define IOMMU_MEMORY_REGION_CLASS(klass) \
+ OBJECT_CLASS_CHECK(IOMMUMemoryRegionClass, (klass), \
+ TYPE_IOMMU_MEMORY_REGION)
+#define IOMMU_MEMORY_REGION_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(IOMMUMemoryRegionClass, (obj), \
+ TYPE_IOMMU_MEMORY_REGION)
+
typedef struct MemoryRegionOps MemoryRegionOps;
typedef struct MemoryRegionMmio MemoryRegionMmio;
@@ -189,26 +200,27 @@ struct MemoryRegionOps {
const MemoryRegionMmio old_mmio;
};
-typedef struct MemoryRegionIOMMUOps MemoryRegionIOMMUOps;
+typedef struct IOMMUMemoryRegionClass {
+ /* private */
+ struct DeviceClass parent_class;
-struct MemoryRegionIOMMUOps {
/*
* Return a TLB entry that contains a given address. Flag should
* be the access permission of this translation operation. We can
* set flag to IOMMU_NONE to mean that we don't need any
* read/write permission checks, like, when for region replay.
*/
- IOMMUTLBEntry (*translate)(MemoryRegion *iommu, hwaddr addr,
+ IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag);
/* Returns minimum supported page size */
- uint64_t (*get_min_page_size)(MemoryRegion *iommu);
+ uint64_t (*get_min_page_size)(IOMMUMemoryRegion *iommu);
/* Called when IOMMU Notifier flag changed */
- void (*notify_flag_changed)(MemoryRegion *iommu,
+ void (*notify_flag_changed)(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old_flags,
IOMMUNotifierFlag new_flags);
/* Set this up to provide customized IOMMU replay function */
- void (*replay)(MemoryRegion *iommu, IOMMUNotifier *notifier);
-};
+ void (*replay)(IOMMUMemoryRegion *iommu, IOMMUNotifier *notifier);
+} IOMMUMemoryRegionClass;
typedef struct CoalescedMemoryRange CoalescedMemoryRange;
typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd;
@@ -227,9 +239,9 @@ struct MemoryRegion {
bool flush_coalesced_mmio;
bool global_locking;
uint8_t dirty_log_mask;
+ bool is_iommu;
RAMBlock *ram_block;
Object *owner;
- const MemoryRegionIOMMUOps *iommu_ops;
const MemoryRegionOps *ops;
void *opaque;
@@ -252,6 +264,11 @@ struct MemoryRegion {
const char *name;
unsigned ioeventfd_nb;
MemoryRegionIoeventfd *ioeventfds;
+};
+
+struct IOMMUMemoryRegion {
+ MemoryRegion parent_obj;
+
QLIST_HEAD(, IOMMUNotifier) iommu_notify;
IOMMUNotifierFlag iommu_notify_flags;
};
@@ -403,8 +420,9 @@ void memory_region_init_io(MemoryRegion *mr,
uint64_t size);
/**
- * memory_region_init_ram: Initialize RAM memory region. Accesses into the
- * region will modify memory directly.
+ * memory_region_init_ram_nomigrate: Initialize RAM memory region. Accesses
+ * into the region will modify memory
+ * directly.
*
* @mr: the #MemoryRegion to be initialized.
* @owner: the object that tracks the region's reference count
@@ -412,12 +430,15 @@ void memory_region_init_io(MemoryRegion *mr,
* must be unique within any device
* @size: size of the region.
* @errp: pointer to Error*, to store an error if it happens.
+ *
+ * Note that this function does not do anything to cause the data in the
+ * RAM memory region to be migrated; that is the responsibility of the caller.
*/
-void memory_region_init_ram(MemoryRegion *mr,
- struct Object *owner,
- const char *name,
- uint64_t size,
- Error **errp);
+void memory_region_init_ram_nomigrate(MemoryRegion *mr,
+ struct Object *owner,
+ const char *name,
+ uint64_t size,
+ Error **errp);
/**
* memory_region_init_resizeable_ram: Initialize memory region with resizeable
@@ -434,6 +455,9 @@ void memory_region_init_ram(MemoryRegion *mr,
* @max_size: max size of the region.
* @resized: callback to notify owner about used size change.
* @errp: pointer to Error*, to store an error if it happens.
+ *
+ * Note that this function does not do anything to cause the data in the
+ * RAM memory region to be migrated; that is the responsibility of the caller.
*/
void memory_region_init_resizeable_ram(MemoryRegion *mr,
struct Object *owner,
@@ -457,6 +481,9 @@ void memory_region_init_resizeable_ram(MemoryRegion *mr,
* @share: %true if memory must be mmaped with the MAP_SHARED flag
* @path: the path in which to allocate the RAM.
* @errp: pointer to Error*, to store an error if it happens.
+ *
+ * Note that this function does not do anything to cause the data in the
+ * RAM memory region to be migrated; that is the responsibility of the caller.
*/
void memory_region_init_ram_from_file(MemoryRegion *mr,
struct Object *owner,
@@ -477,6 +504,9 @@ void memory_region_init_ram_from_file(MemoryRegion *mr,
* @share: %true if memory must be mmaped with the MAP_SHARED flag
* @fd: the fd to mmap.
* @errp: pointer to Error*, to store an error if it happens.
+ *
+ * Note that this function does not do anything to cause the data in the
+ * RAM memory region to be migrated; that is the responsibility of the caller.
*/
void memory_region_init_ram_from_fd(MemoryRegion *mr,
struct Object *owner,
@@ -498,6 +528,9 @@ void memory_region_init_ram_from_fd(MemoryRegion *mr,
* must be unique within any device
* @size: size of the region.
* @ptr: memory to be mapped; must contain at least @size bytes.
+ *
+ * Note that this function does not do anything to cause the data in the
+ * RAM memory region to be migrated; that is the responsibility of the caller.
*/
void memory_region_init_ram_ptr(MemoryRegion *mr,
struct Object *owner,
@@ -522,6 +555,10 @@ void memory_region_init_ram_ptr(MemoryRegion *mr,
* @name: the name of the region.
* @size: size of the region.
* @ptr: memory to be mapped; must contain at least @size bytes.
+ *
+ * Note that this function does not do anything to cause the data in the
+ * RAM memory region to be migrated; that is the responsibility of the caller.
+ * (For RAM device memory regions, migrating the contents rarely makes sense.)
*/
void memory_region_init_ram_device_ptr(MemoryRegion *mr,
struct Object *owner,
@@ -549,12 +586,16 @@ void memory_region_init_alias(MemoryRegion *mr,
uint64_t size);
/**
- * memory_region_init_rom: Initialize a ROM memory region.
+ * memory_region_init_rom_nomigrate: Initialize a ROM memory region.
*
- * This has the same effect as calling memory_region_init_ram()
+ * This has the same effect as calling memory_region_init_ram_nomigrate()
* and then marking the resulting region read-only with
* memory_region_set_readonly().
*
+ * Note that this function does not do anything to cause the data in the
+ * RAM side of the memory region to be migrated; that is the responsibility
+ * of the caller.
+ *
* @mr: the #MemoryRegion to be initialized.
* @owner: the object that tracks the region's reference count
* @name: Region name, becomes part of RAMBlock name used in migration stream
@@ -562,15 +603,19 @@ void memory_region_init_alias(MemoryRegion *mr,
* @size: size of the region.
* @errp: pointer to Error*, to store an error if it happens.
*/
-void memory_region_init_rom(MemoryRegion *mr,
- struct Object *owner,
- const char *name,
- uint64_t size,
- Error **errp);
+void memory_region_init_rom_nomigrate(MemoryRegion *mr,
+ struct Object *owner,
+ const char *name,
+ uint64_t size,
+ Error **errp);
/**
- * memory_region_init_rom_device: Initialize a ROM memory region. Writes are
- * handled via callbacks.
+ * memory_region_init_rom_device_nomigrate: Initialize a ROM memory region.
+ * Writes are handled via callbacks.
+ *
+ * Note that this function does not do anything to cause the data in the
+ * RAM side of the memory region to be migrated; that is the responsibility
+ * of the caller.
*
* @mr: the #MemoryRegion to be initialized.
* @owner: the object that tracks the region's reference count
@@ -580,13 +625,13 @@ void memory_region_init_rom(MemoryRegion *mr,
* @size: size of the region.
* @errp: pointer to Error*, to store an error if it happens.
*/
-void memory_region_init_rom_device(MemoryRegion *mr,
- struct Object *owner,
- const MemoryRegionOps *ops,
- void *opaque,
- const char *name,
- uint64_t size,
- Error **errp);
+void memory_region_init_rom_device_nomigrate(MemoryRegion *mr,
+ struct Object *owner,
+ const MemoryRegionOps *ops,
+ void *opaque,
+ const char *name,
+ uint64_t size,
+ Error **errp);
/**
* memory_region_init_reservation: Initialize a memory region that reserves
@@ -612,25 +657,116 @@ static inline void memory_region_init_reservation(MemoryRegion *mr,
}
/**
- * memory_region_init_iommu: Initialize a memory region that translates
- * addresses
+ * memory_region_init_iommu: Initialize a memory region of a custom type
+ * that translates addresses
*
* An IOMMU region translates addresses and forwards accesses to a target
* memory region.
*
- * @mr: the #MemoryRegion to be initialized
+ * @typename: QOM class name
+ * @_iommu_mr: the #IOMMUMemoryRegion to be initialized
+ * @instance_size: the IOMMUMemoryRegion subclass instance size
* @owner: the object that tracks the region's reference count
* @ops: a function that translates addresses into the @target region
* @name: used for debugging; not visible to the user or ABI
* @size: size of the region.
*/
-void memory_region_init_iommu(MemoryRegion *mr,
- struct Object *owner,
- const MemoryRegionIOMMUOps *ops,
+void memory_region_init_iommu(void *_iommu_mr,
+ size_t instance_size,
+ const char *mrtypename,
+ Object *owner,
const char *name,
uint64_t size);
/**
+ * memory_region_init_ram - Initialize RAM memory region. Accesses into the
+ * region will modify memory directly.
+ *
+ * @mr: the #MemoryRegion to be initialized
+ * @owner: the object that tracks the region's reference count (must be
+ * TYPE_DEVICE or a subclass of TYPE_DEVICE, or NULL)
+ * @name: name of the memory region
+ * @size: size of the region in bytes
+ * @errp: pointer to Error*, to store an error if it happens.
+ *
+ * This function allocates RAM for a board model or device, and
+ * arranges for it to be migrated (by calling vmstate_register_ram()
+ * if @owner is a DeviceState, or vmstate_register_ram_global() if
+ * @owner is NULL).
+ *
+ * TODO: Currently we restrict @owner to being either NULL (for
+ * global RAM regions with no owner) or devices, so that we can
+ * give the RAM block a unique name for migration purposes.
+ * We should lift this restriction and allow arbitrary Objects.
+ * If you pass a non-NULL non-device @owner then we will assert.
+ */
+void memory_region_init_ram(MemoryRegion *mr,
+ struct Object *owner,
+ const char *name,
+ uint64_t size,
+ Error **errp);
+
+/**
+ * memory_region_init_rom: Initialize a ROM memory region.
+ *
+ * This has the same effect as calling memory_region_init_ram()
+ * and then marking the resulting region read-only with
+ * memory_region_set_readonly(). This includes arranging for the
+ * contents to be migrated.
+ *
+ * TODO: Currently we restrict @owner to being either NULL (for
+ * global RAM regions with no owner) or devices, so that we can
+ * give the RAM block a unique name for migration purposes.
+ * We should lift this restriction and allow arbitrary Objects.
+ * If you pass a non-NULL non-device @owner then we will assert.
+ *
+ * @mr: the #MemoryRegion to be initialized.
+ * @owner: the object that tracks the region's reference count
+ * @name: Region name, becomes part of RAMBlock name used in migration stream
+ * must be unique within any device
+ * @size: size of the region.
+ * @errp: pointer to Error*, to store an error if it happens.
+ */
+void memory_region_init_rom(MemoryRegion *mr,
+ struct Object *owner,
+ const char *name,
+ uint64_t size,
+ Error **errp);
+
+/**
+ * memory_region_init_rom_device: Initialize a ROM memory region.
+ * Writes are handled via callbacks.
+ *
+ * This function initializes a memory region backed by RAM for reads
+ * and callbacks for writes, and arranges for the RAM backing to
+ * be migrated (by calling vmstate_register_ram()
+ * if @owner is a DeviceState, or vmstate_register_ram_global() if
+ * @owner is NULL).
+ *
+ * TODO: Currently we restrict @owner to being either NULL (for
+ * global RAM regions with no owner) or devices, so that we can
+ * give the RAM block a unique name for migration purposes.
+ * We should lift this restriction and allow arbitrary Objects.
+ * If you pass a non-NULL non-device @owner then we will assert.
+ *
+ * @mr: the #MemoryRegion to be initialized.
+ * @owner: the object that tracks the region's reference count
+ * @ops: callbacks for write access handling (must not be NULL).
+ * @name: Region name, becomes part of RAMBlock name used in migration stream
+ * must be unique within any device
+ * @size: size of the region.
+ * @errp: pointer to Error*, to store an error if it happens.
+ */
+void memory_region_init_rom_device(MemoryRegion *mr,
+ struct Object *owner,
+ const MemoryRegionOps *ops,
+ void *opaque,
+ const char *name,
+ uint64_t size,
+ Error **errp);
+
+
+/**
* memory_region_owner: get a memory region's owner.
*
* @mr: the memory region being queried.
@@ -679,20 +815,40 @@ static inline bool memory_region_is_romd(MemoryRegion *mr)
}
/**
- * memory_region_is_iommu: check whether a memory region is an iommu
+ * memory_region_get_iommu: check whether a memory region is an iommu
*
- * Returns %true is a memory region is an iommu.
+ * Returns pointer to IOMMUMemoryRegion if a memory region is an iommu,
+ * otherwise NULL.
*
* @mr: the memory region being queried
*/
-static inline bool memory_region_is_iommu(MemoryRegion *mr)
+static inline IOMMUMemoryRegion *memory_region_get_iommu(MemoryRegion *mr)
{
if (mr->alias) {
- return memory_region_is_iommu(mr->alias);
+ return memory_region_get_iommu(mr->alias);
+ }
+ if (mr->is_iommu) {
+ return (IOMMUMemoryRegion *) mr;
}
- return mr->iommu_ops;
+ return NULL;
}
+/**
+ * memory_region_get_iommu_class_nocheck: returns iommu memory region class
+ * if an iommu or NULL if not
+ *
+ * Returns pointer to IOMMUMemoryRegioniClass if a memory region is an iommu,
+ * otherwise NULL. This is fast path avoinding QOM checking, use with caution.
+ *
+ * @mr: the memory region being queried
+ */
+static inline IOMMUMemoryRegionClass *memory_region_get_iommu_class_nocheck(
+ IOMMUMemoryRegion *iommu_mr)
+{
+ return (IOMMUMemoryRegionClass *) (((Object *)iommu_mr)->class);
+}
+
+#define memory_region_is_iommu(mr) (memory_region_get_iommu(mr) != NULL)
/**
* memory_region_iommu_get_min_page_size: get minimum supported page size
@@ -700,9 +856,9 @@ static inline bool memory_region_is_iommu(MemoryRegion *mr)
*
* Returns minimum supported page size for an iommu.
*
- * @mr: the memory region being queried
+ * @iommu_mr: the memory region being queried
*/
-uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr);
+uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr);
/**
* memory_region_notify_iommu: notify a change in an IOMMU translation entry.
@@ -716,12 +872,12 @@ uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr);
* Note: for any IOMMU implementation, an in-place mapping change
* should be notified with an UNMAP followed by a MAP.
*
- * @mr: the memory region that was changed
+ * @iommu_mr: the memory region that was changed
* @entry: the new entry in the IOMMU translation table. The entry
* replaces all old entries for the same virtual I/O address range.
* Deleted entries have .@perm == 0.
*/
-void memory_region_notify_iommu(MemoryRegion *mr,
+void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
IOMMUTLBEntry entry);
/**
@@ -756,18 +912,18 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
* a notifier with the minimum page granularity returned by
* mr->iommu_ops->get_page_size().
*
- * @mr: the memory region to observe
+ * @iommu_mr: the memory region to observe
* @n: the notifier to which to replay iommu mappings
*/
-void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n);
+void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n);
/**
* memory_region_iommu_replay_all: replay existing IOMMU translations
* to all the notifiers registered.
*
- * @mr: the memory region to observe
+ * @iommu_mr: the memory region to observe
*/
-void memory_region_iommu_replay_all(MemoryRegion *mr);
+void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr);
/**
* memory_region_unregister_iommu_notifier: unregister a notifier for
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 76ce0219ff..3363dd19fd 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -9,6 +9,35 @@
#include "qom/object.h"
#include "qom/cpu.h"
+/**
+ * memory_region_allocate_system_memory - Allocate a board's main memory
+ * @mr: the #MemoryRegion to be initialized
+ * @owner: the object that tracks the region's reference count
+ * @name: name of the memory region
+ * @ram_size: size of the region in bytes
+ *
+ * This function allocates the main memory for a board model, and
+ * initializes @mr appropriately. It also arranges for the memory
+ * to be migrated (by calling vmstate_register_ram_global()).
+ *
+ * Memory allocated via this function will be backed with the memory
+ * backend the user provided using "-mem-path" or "-numa node,memdev=..."
+ * if appropriate; this is typically used to cause host huge pages to be
+ * used. This function should therefore be called by a board exactly once,
+ * for the primary or largest RAM area it implements.
+ *
+ * For boards where the major RAM is split into two parts in the memory
+ * map, you can deal with this by calling memory_region_allocate_system_memory()
+ * once to get a MemoryRegion with enough RAM for both parts, and then
+ * creating alias MemoryRegions via memory_region_init_alias() which
+ * alias into different parts of the RAM MemoryRegion and can be mapped
+ * into the memory map in the appropriate places.
+ *
+ * Smaller pieces of memory (display RAM, static RAMs, etc) don't need
+ * to be backed via the -mem-path memory backend and can simply
+ * be created via memory_region_allocate_aux_memory() or
+ * memory_region_init_ram().
+ */
void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner,
const char *name,
uint64_t ram_size);
diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h
index 3e51876b75..08d8a26d13 100644
--- a/include/hw/i386/intel_iommu.h
+++ b/include/hw/i386/intel_iommu.h
@@ -32,6 +32,8 @@
#define INTEL_IOMMU_DEVICE(obj) \
OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE)
+#define TYPE_INTEL_IOMMU_MEMORY_REGION "intel-iommu-iommu-memory-region"
+
/* DMAR Hardware Unit Definition address (IOMMU unit) */
#define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed90000ULL
@@ -83,7 +85,7 @@ struct VTDAddressSpace {
PCIBus *bus;
uint8_t devfn;
AddressSpace as;
- MemoryRegion iommu;
+ IOMMUMemoryRegion iommu;
MemoryRegion root;
MemoryRegion sys_alias;
MemoryRegion iommu_ir; /* Interrupt region: 0xfeeXXXXX */
@@ -289,7 +291,6 @@ struct IntelIOMMUState {
uint32_t context_cache_gen; /* Should be in [1,MAX] */
GHashTable *iotlb; /* IOTLB */
- MemoryRegionIOMMUOps iommu_ops;
GHashTable *vtd_as_by_busptr; /* VTDBus objects indexed by PCIBus* reference */
VTDBus *vtd_as_by_bus_num[VTD_PCI_BUS_MAX]; /* VTDBus objects indexed by bus number */
/* list of registered notifiers */
diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h
index 16412dc150..2f6774d540 100644
--- a/include/hw/mips/mips.h
+++ b/include/hw/mips/mips.h
@@ -19,6 +19,6 @@ typedef struct rc4030DMAState *rc4030_dma;
void rc4030_dma_read(void *dma, uint8_t *buf, int len);
void rc4030_dma_write(void *dma, uint8_t *buf, int len);
-DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr);
+DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr);
#endif
diff --git a/include/hw/misc/unimp.h b/include/hw/misc/unimp.h
index 3462d85836..52e068ec3e 100644
--- a/include/hw/misc/unimp.h
+++ b/include/hw/misc/unimp.h
@@ -8,6 +8,8 @@
#ifndef HW_MISC_UNIMP_H
#define HW_MISC_UNIMP_H
+#include "hw/sysbus.h"
+
#define TYPE_UNIMPLEMENTED_DEVICE "unimplemented-device"
/**
diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h
index 11d83e43f8..f6af5eae1f 100644
--- a/include/hw/ppc/pnv_psi.h
+++ b/include/hw/ppc/pnv_psi.h
@@ -28,8 +28,6 @@
#define PSIHB_XSCOM_MAX 0x20
-typedef struct XICSState XICSState;
-
typedef struct PnvPsi {
SysBusDevice parent;
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index a184ffab0e..2a303a705c 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -13,6 +13,7 @@ struct sPAPRPHBState;
struct sPAPRNVRAM;
typedef struct sPAPREventLogEntry sPAPREventLogEntry;
typedef struct sPAPREventSource sPAPREventSource;
+typedef struct sPAPRPendingHPT sPAPRPendingHPT;
#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL
#define SPAPR_ENTRY_POINT 0x100
@@ -42,6 +43,13 @@ typedef struct sPAPRMachineClass sPAPRMachineClass;
#define SPAPR_MACHINE_CLASS(klass) \
OBJECT_CLASS_CHECK(sPAPRMachineClass, klass, TYPE_SPAPR_MACHINE)
+typedef enum {
+ SPAPR_RESIZE_HPT_DEFAULT = 0,
+ SPAPR_RESIZE_HPT_DISABLED,
+ SPAPR_RESIZE_HPT_ENABLED,
+ SPAPR_RESIZE_HPT_REQUIRED,
+} sPAPRResizeHPT;
+
/**
* sPAPRMachineClass:
*/
@@ -58,6 +66,7 @@ struct sPAPRMachineClass {
uint64_t *buid, hwaddr *pio,
hwaddr *mmio32, hwaddr *mmio64,
unsigned n_dma, uint32_t *liobns, Error **errp);
+ sPAPRResizeHPT resize_hpt_default;
};
/**
@@ -73,9 +82,12 @@ struct sPAPRMachineState {
ICSState *ics;
sPAPRRTCState rtc;
+ sPAPRResizeHPT resize_hpt;
void *htab;
uint32_t htab_shift;
uint64_t patb_entry; /* Process tbl registed in H_REGISTER_PROCESS_TABLE */
+ sPAPRPendingHPT *pending_hpt; /* in-progress resize */
+
hwaddr rma_size;
int vrma_adjust;
ssize_t rtas_size;
@@ -367,6 +379,8 @@ struct sPAPRMachineState {
#define H_XIRR_X 0x2FC
#define H_RANDOM 0x300
#define H_SET_MODE 0x31C
+#define H_RESIZE_HPT_PREPARE 0x36C
+#define H_RESIZE_HPT_COMMIT 0x370
#define H_CLEAN_SLB 0x374
#define H_INVALIDATE_PID 0x378
#define H_REGISTER_PROC_TBL 0x37C
@@ -582,6 +596,10 @@ typedef struct sPAPRTCETable sPAPRTCETable;
#define SPAPR_TCE_TABLE(obj) \
OBJECT_CHECK(sPAPRTCETable, (obj), TYPE_SPAPR_TCE_TABLE)
+#define TYPE_SPAPR_IOMMU_MEMORY_REGION "spapr-iommu-memory-region"
+#define SPAPR_IOMMU_MEMORY_REGION(obj) \
+ OBJECT_CHECK(IOMMUMemoryRegion, (obj), TYPE_SPAPR_IOMMU_MEMORY_REGION)
+
struct sPAPRTCETable {
DeviceState parent;
uint32_t liobn;
@@ -594,7 +612,8 @@ struct sPAPRTCETable {
bool bypass;
bool need_vfio;
int fd;
- MemoryRegion root, iommu;
+ MemoryRegion root;
+ IOMMUMemoryRegion iommu;
struct VIOsPAPRDevice *vdev; /* for @bypass migration compatibility only */
QLIST_ENTRY(sPAPRTCETable) list;
};
@@ -602,8 +621,9 @@ struct sPAPRTCETable {
sPAPRTCETable *spapr_tce_find_by_liobn(target_ulong liobn);
struct sPAPREventLogEntry {
- int log_type;
- void *data;
+ uint32_t summary;
+ uint32_t extended_length;
+ void *extended_log;
QTAILQ_ENTRY(sPAPREventLogEntry) next;
};
@@ -639,6 +659,9 @@ void spapr_hotplug_req_add_by_count_indexed(sPAPRDRConnectorType drc_type,
void spapr_hotplug_req_remove_by_count_indexed(sPAPRDRConnectorType drc_type,
uint32_t count, uint32_t index);
void spapr_cpu_parse_features(sPAPRMachineState *spapr);
+int spapr_hpt_shift_for_ramsize(uint64_t ramsize);
+void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
+ Error **errp);
/* CPU and LMB DRC release callbacks. */
void spapr_core_release(DeviceState *dev);
@@ -679,4 +702,6 @@ int spapr_rng_populate_dt(void *fdt);
void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg);
+#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
+
#endif /* HW_SPAPR_H */
diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h
index d15e9eb3b4..a7958d0a8d 100644
--- a/include/hw/ppc/spapr_drc.h
+++ b/include/hw/ppc/spapr_drc.h
@@ -15,6 +15,7 @@
#include <libfdt.h>
#include "qom/object.h"
+#include "sysemu/sysemu.h"
#include "hw/qdev.h"
#define TYPE_SPAPR_DR_CONNECTOR "spapr-dr-connector"
@@ -32,7 +33,7 @@
#define SPAPR_DRC_PHYSICAL_CLASS(klass) \
OBJECT_CLASS_CHECK(sPAPRDRConnectorClass, klass, \
TYPE_SPAPR_DRC_PHYSICAL)
-#define SPAPR_DRC_PHYSICAL(obj) OBJECT_CHECK(sPAPRDRConnector, (obj), \
+#define SPAPR_DRC_PHYSICAL(obj) OBJECT_CHECK(sPAPRDRCPhysical, (obj), \
TYPE_SPAPR_DRC_PHYSICAL)
#define TYPE_SPAPR_DRC_LOGICAL "spapr-drc-logical"
@@ -172,11 +173,23 @@ typedef enum {
SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE = -9003,
} sPAPRDRCCResponse;
-/* rtas-configure-connector state */
-typedef struct sPAPRConfigureConnectorState {
- int fdt_offset;
- int fdt_depth;
-} sPAPRConfigureConnectorState;
+typedef enum {
+ /*
+ * Values come from Fig. 12 in LoPAPR section 13.4
+ *
+ * These are exposed in the migration stream, so don't change
+ * them.
+ */
+ SPAPR_DRC_STATE_INVALID = 0,
+ SPAPR_DRC_STATE_LOGICAL_UNUSABLE = 1,
+ SPAPR_DRC_STATE_LOGICAL_AVAILABLE = 2,
+ SPAPR_DRC_STATE_LOGICAL_UNISOLATE = 3,
+ SPAPR_DRC_STATE_LOGICAL_CONFIGURED = 4,
+ SPAPR_DRC_STATE_PHYSICAL_AVAILABLE = 5,
+ SPAPR_DRC_STATE_PHYSICAL_POWERON = 6,
+ SPAPR_DRC_STATE_PHYSICAL_UNISOLATE = 7,
+ SPAPR_DRC_STATE_PHYSICAL_CONFIGURED = 8,
+} sPAPRDRCState;
typedef struct sPAPRDRConnector {
/*< private >*/
@@ -185,29 +198,25 @@ typedef struct sPAPRDRConnector {
uint32_t id;
Object *owner;
- /* DR-indicator */
- uint32_t dr_indicator;
+ uint32_t state;
- /* sensor/indicator states */
- uint32_t isolation_state;
- uint32_t allocation_state;
-
- /* configure-connector state */
- void *fdt;
- int fdt_start_offset;
- bool configured;
- sPAPRConfigureConnectorState *ccs;
-
- bool awaiting_release;
- bool awaiting_allocation;
+ /* RTAS ibm,configure-connector state */
+ /* (only valid in UNISOLATE state) */
+ int ccs_offset;
+ int ccs_depth;
/* device pointer, via link property */
DeviceState *dev;
+ bool unplug_requested;
+ void *fdt;
+ int fdt_start_offset;
} sPAPRDRConnector;
typedef struct sPAPRDRConnectorClass {
/*< private >*/
DeviceClass parent;
+ sPAPRDRCState empty_state;
+ sPAPRDRCState ready_state;
/*< public >*/
sPAPRDRConnectorTypeShift typeshift;
@@ -218,11 +227,23 @@ typedef struct sPAPRDRConnectorClass {
uint32_t (*isolate)(sPAPRDRConnector *drc);
uint32_t (*unisolate)(sPAPRDRConnector *drc);
void (*release)(DeviceState *dev);
-
- /* QEMU interfaces for managing hotplug operations */
- bool (*release_pending)(sPAPRDRConnector *drc);
} sPAPRDRConnectorClass;
+typedef struct sPAPRDRCPhysical {
+ /*< private >*/
+ sPAPRDRConnector parent;
+
+ /* DR-indicator */
+ uint32_t dr_indicator;
+} sPAPRDRCPhysical;
+
+static inline bool spapr_drc_hotplugged(DeviceState *dev)
+{
+ return dev->hotplugged && !runstate_check(RUN_STATE_INMIGRATE);
+}
+
+void spapr_drc_reset(sPAPRDRConnector *drc);
+
uint32_t spapr_drc_index(sPAPRDRConnector *drc);
sPAPRDRConnectorType spapr_drc_type(sPAPRDRConnector *drc);
@@ -235,6 +256,11 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
int fdt_start_offset, Error **errp);
-void spapr_drc_detach(sPAPRDRConnector *drc, DeviceState *d, Error **errp);
+void spapr_drc_detach(sPAPRDRConnector *drc);
+
+static inline bool spapr_drc_unplug_requested(sPAPRDRConnector *drc)
+{
+ return drc->unplug_requested;
+}
#endif /* HW_SPAPR_DRC_H */
diff --git a/include/hw/ppc/spapr_ovec.h b/include/hw/ppc/spapr_ovec.h
index 0b464e22e7..9edfa5ff75 100644
--- a/include/hw/ppc/spapr_ovec.h
+++ b/include/hw/ppc/spapr_ovec.h
@@ -50,6 +50,7 @@ typedef struct sPAPROptionVector sPAPROptionVector;
#define OV5_DRCONF_MEMORY OV_BIT(2, 2)
#define OV5_FORM1_AFFINITY OV_BIT(5, 0)
#define OV5_HP_EVT OV_BIT(6, 5)
+#define OV5_HPT_RESIZE OV_BIT(6, 7)
#define OV5_XIVE_EXPLOIT OV_BIT(23, 7)
/* ISA 3.00 MMU features: */
diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h
index eafc3f0a86..fc4ef5cc1d 100644
--- a/include/hw/ptimer.h
+++ b/include/hw/ptimer.h
@@ -12,6 +12,20 @@
#include "qemu/timer.h"
#include "migration/vmstate.h"
+/* The ptimer API implements a simple periodic countdown timer.
+ * The countdown timer has a value (which can be read and written via
+ * ptimer_get_count() and ptimer_set_count()). When it is enabled
+ * using ptimer_run(), the value will count downwards at the frequency
+ * which has been configured using ptimer_set_period() or ptimer_set_freq().
+ * When it reaches zero it will trigger a QEMU bottom half handler, and
+ * can be set to either reload itself from a specified limit value
+ * and keep counting down, or to stop (as a one-shot timer).
+ *
+ * Forgetting to set the period/frequency (or setting it to zero) is a
+ * bug in the QEMU device and will cause warning messages to be printed
+ * to stderr when the guest attempts to enable the timer.
+ */
+
/* The default ptimer policy retains backward compatibility with the legacy
* timers. Custom policies are adjusting the default one. Consider providing
* a correct policy for your timer.
@@ -59,15 +73,121 @@
typedef struct ptimer_state ptimer_state;
typedef void (*ptimer_cb)(void *opaque);
+/**
+ * ptimer_init - Allocate and return a new ptimer
+ * @bh: QEMU bottom half which is run on timer expiry
+ * @policy: PTIMER_POLICY_* bits specifying behaviour
+ *
+ * The ptimer returned must be freed using ptimer_free().
+ * The ptimer takes ownership of @bh and will delete it
+ * when the ptimer is eventually freed.
+ */
ptimer_state *ptimer_init(QEMUBH *bh, uint8_t policy_mask);
+
+/**
+ * ptimer_free - Free a ptimer
+ * @s: timer to free
+ *
+ * Free a ptimer created using ptimer_init() (including
+ * deleting the bottom half which it is using).
+ */
void ptimer_free(ptimer_state *s);
+
+/**
+ * ptimer_set_period - Set counter increment interval in nanoseconds
+ * @s: ptimer to configure
+ * @period: period of the counter in nanoseconds
+ *
+ * Note that if your counter behaviour is specified as having a
+ * particular frequency rather than a period then ptimer_set_freq()
+ * may be more appropriate.
+ */
void ptimer_set_period(ptimer_state *s, int64_t period);
+
+/**
+ * ptimer_set_freq - Set counter frequency in Hz
+ * @s: ptimer to configure
+ * @freq: counter frequency in Hz
+ *
+ * This does the same thing as ptimer_set_period(), so you only
+ * need to call one of them. If the counter behaviour is specified
+ * as setting the frequency then this function is more appropriate,
+ * because it allows specifying an effective period which is
+ * precise to fractions of a nanosecond, avoiding rounding errors.
+ */
void ptimer_set_freq(ptimer_state *s, uint32_t freq);
+
+/**
+ * ptimer_get_limit - Get the configured limit of the ptimer
+ * @s: ptimer to query
+ *
+ * This function returns the current limit (reload) value
+ * of the down-counter; that is, the value which it will be
+ * reset to when it hits zero.
+ *
+ * Generally timer devices using ptimers should be able to keep
+ * their reload register state inside the ptimer using the get
+ * and set limit functions rather than needing to also track it
+ * in their own state structure.
+ */
uint64_t ptimer_get_limit(ptimer_state *s);
+
+/**
+ * ptimer_set_limit - Set the limit of the ptimer
+ * @s: ptimer
+ * @limit: initial countdown value
+ * @reload: if nonzero, then reset the counter to the new limit
+ *
+ * Set the limit value of the down-counter. The @reload flag can
+ * be used to emulate the behaviour of timers which immediately
+ * reload the counter when their reload register is written to.
+ */
void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload);
+
+/**
+ * ptimer_get_count - Get the current value of the ptimer
+ * @s: ptimer
+ *
+ * Return the current value of the down-counter. This will
+ * return the correct value whether the counter is enabled or
+ * disabled.
+ */
uint64_t ptimer_get_count(ptimer_state *s);
+
+/**
+ * ptimer_set_count - Set the current value of the ptimer
+ * @s: ptimer
+ * @count: count value to set
+ *
+ * Set the value of the down-counter. If the counter is currently
+ * enabled this will arrange for a timer callback at the appropriate
+ * point in the future.
+ */
void ptimer_set_count(ptimer_state *s, uint64_t count);
+
+/**
+ * ptimer_run - Start a ptimer counting
+ * @s: ptimer
+ * @oneshot: non-zero if this timer should only count down once
+ *
+ * Start a ptimer counting down; when it reaches zero the bottom half
+ * passed to ptimer_init() will be invoked. If the @oneshot argument is zero,
+ * the counter value will then be reloaded from the limit and it will
+ * start counting down again. If @oneshot is non-zero, then the counter
+ * will disable itself when it reaches zero.
+ */
void ptimer_run(ptimer_state *s, int oneshot);
+
+/**
+ * ptimer_stop - Stop a ptimer counting
+ * @s: ptimer
+ *
+ * Pause a timer (the count stays at its current value until ptimer_run()
+ * is called to start it counting again).
+ *
+ * Note that this can cause it to "lose" time, even if it is immediately
+ * restarted.
+ */
void ptimer_stop(ptimer_state *s);
extern const VMStateDescription vmstate_ptimer;
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 9d7c1c0e9b..53488153fd 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -223,7 +223,7 @@ struct BusState {
struct Property {
const char *name;
- PropertyInfo *info;
+ const PropertyInfo *info;
ptrdiff_t offset;
uint8_t bitnr;
union {
@@ -231,8 +231,9 @@ struct Property {
uint64_t u;
} defval;
int arrayoffset;
- PropertyInfo *arrayinfo;
+ const PropertyInfo *arrayinfo;
int arrayfieldsize;
+ const char *link_type;
};
struct PropertyInfo {
@@ -241,6 +242,7 @@ struct PropertyInfo {
const char * const *enum_table;
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
void (*set_default_value)(Object *obj, const Property *prop);
+ void (*create)(Object *obj, Property *prop, Error **errp);
ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set;
ObjectPropertyRelease *release;
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 0604c337e0..f6692d5dc3 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -5,31 +5,32 @@
/*** qdev-properties.c ***/
-extern PropertyInfo qdev_prop_bit;
-extern PropertyInfo qdev_prop_bit64;
-extern PropertyInfo qdev_prop_bool;
-extern PropertyInfo qdev_prop_uint8;
-extern PropertyInfo qdev_prop_uint16;
-extern PropertyInfo qdev_prop_uint32;
-extern PropertyInfo qdev_prop_int32;
-extern PropertyInfo qdev_prop_uint64;
-extern PropertyInfo qdev_prop_size;
-extern PropertyInfo qdev_prop_string;
-extern PropertyInfo qdev_prop_chr;
-extern PropertyInfo qdev_prop_ptr;
-extern PropertyInfo qdev_prop_macaddr;
-extern PropertyInfo qdev_prop_on_off_auto;
-extern PropertyInfo qdev_prop_losttickpolicy;
-extern PropertyInfo qdev_prop_blockdev_on_error;
-extern PropertyInfo qdev_prop_bios_chs_trans;
-extern PropertyInfo qdev_prop_fdc_drive_type;
-extern PropertyInfo qdev_prop_drive;
-extern PropertyInfo qdev_prop_netdev;
-extern PropertyInfo qdev_prop_vlan;
-extern PropertyInfo qdev_prop_pci_devfn;
-extern PropertyInfo qdev_prop_blocksize;
-extern PropertyInfo qdev_prop_pci_host_devaddr;
-extern PropertyInfo qdev_prop_arraylen;
+extern const PropertyInfo qdev_prop_bit;
+extern const PropertyInfo qdev_prop_bit64;
+extern const PropertyInfo qdev_prop_bool;
+extern const PropertyInfo qdev_prop_uint8;
+extern const PropertyInfo qdev_prop_uint16;
+extern const PropertyInfo qdev_prop_uint32;
+extern const PropertyInfo qdev_prop_int32;
+extern const PropertyInfo qdev_prop_uint64;
+extern const PropertyInfo qdev_prop_size;
+extern const PropertyInfo qdev_prop_string;
+extern const PropertyInfo qdev_prop_chr;
+extern const PropertyInfo qdev_prop_ptr;
+extern const PropertyInfo qdev_prop_macaddr;
+extern const PropertyInfo qdev_prop_on_off_auto;
+extern const PropertyInfo qdev_prop_losttickpolicy;
+extern const PropertyInfo qdev_prop_blockdev_on_error;
+extern const PropertyInfo qdev_prop_bios_chs_trans;
+extern const PropertyInfo qdev_prop_fdc_drive_type;
+extern const PropertyInfo qdev_prop_drive;
+extern const PropertyInfo qdev_prop_netdev;
+extern const PropertyInfo qdev_prop_vlan;
+extern const PropertyInfo qdev_prop_pci_devfn;
+extern const PropertyInfo qdev_prop_blocksize;
+extern const PropertyInfo qdev_prop_pci_host_devaddr;
+extern const PropertyInfo qdev_prop_arraylen;
+extern const PropertyInfo qdev_prop_link;
#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
.name = (_name), \
@@ -117,6 +118,14 @@ extern PropertyInfo qdev_prop_arraylen;
.arrayoffset = offsetof(_state, _arrayfield), \
}
+#define DEFINE_PROP_LINK(_name, _state, _field, _type, _ptr_type) { \
+ .name = (_name), \
+ .info = &(qdev_prop_link), \
+ .offset = offsetof(_state, _field) \
+ + type_check(_ptr_type, typeof_field(_state, _field)), \
+ .link_type = _type, \
+ }
+
#define DEFINE_PROP_UINT8(_n, _s, _f, _d) \
DEFINE_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
#define DEFINE_PROP_UINT16(_n, _s, _f, _d) \
@@ -272,7 +281,8 @@ void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
* This function should be used as the check() argument to
* object_property_add_link().
*/
-void qdev_prop_allow_set_link_before_realize(Object *obj, const char *name,
+void qdev_prop_allow_set_link_before_realize(const Object *obj,
+ const char *name,
Object *val, Error **errp);
#endif
diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h
index eb0e26f258..5c5fe6b202 100644
--- a/include/hw/s390x/css.h
+++ b/include/hw/s390x/css.h
@@ -12,6 +12,7 @@
#ifndef CSS_H
#define CSS_H
+#include "cpu.h"
#include "hw/s390x/adapter.h"
#include "hw/s390x/s390_flic.h"
#include "hw/s390x/ioinst.h"
@@ -89,10 +90,11 @@ struct SubchDev {
bool thinint_active;
uint8_t ccw_no_data_cnt;
uint16_t migrated_schid; /* used for missmatch detection */
+ ORB orb;
/* transport-provided data: */
int (*ccw_cb) (SubchDev *, CCW1);
void (*disable_cb)(SubchDev *);
- int (*do_subchannel_work) (SubchDev *, ORB *);
+ int (*do_subchannel_work) (SubchDev *);
SenseId id;
void *driver_data;
};
@@ -112,7 +114,7 @@ typedef struct CssDevId {
bool valid;
} CssDevId;
-extern PropertyInfo css_devid_propinfo;
+extern const PropertyInfo css_devid_propinfo;
#define DEFINE_PROP_CSS_DEV_ID(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, css_devid_propinfo, CssDevId)
@@ -154,10 +156,9 @@ void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
void css_generate_css_crws(uint8_t cssid);
void css_clear_sei_pending(void);
-void css_adapter_interrupt(uint8_t isc);
int s390_ccw_cmd_request(ORB *orb, SCSW *scsw, void *data);
-int do_subchannel_work_virtual(SubchDev *sub, ORB *orb);
-int do_subchannel_work_passthrough(SubchDev *sub, ORB *orb);
+int do_subchannel_work_virtual(SubchDev *sub);
+int do_subchannel_work_passthrough(SubchDev *sub);
typedef enum {
CSS_IO_ADAPTER_VIRTIO = 0,
@@ -165,9 +166,17 @@ typedef enum {
CSS_IO_ADAPTER_TYPE_NUMS,
} CssIoAdapterType;
+void css_adapter_interrupt(CssIoAdapterType type, uint8_t isc);
+int css_do_sic(CPUS390XState *env, uint8_t isc, uint16_t mode);
uint32_t css_get_adapter_id(CssIoAdapterType type, uint8_t isc);
void css_register_io_adapters(CssIoAdapterType type, bool swap, bool maskable,
- Error **errp);
+ uint8_t flags, Error **errp);
+
+#ifndef CONFIG_KVM
+#define S390_ADAPTER_SUPPRESSIBLE 0x01
+#else
+#define S390_ADAPTER_SUPPRESSIBLE KVM_S390_ADAPTER_SUPPRESSIBLE
+#endif
#ifndef CONFIG_USER_ONLY
SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid,
@@ -196,7 +205,7 @@ int css_do_rchp(uint8_t cssid, uint8_t chpid);
bool css_present(uint8_t cssid);
#endif
-extern PropertyInfo css_devid_ro_propinfo;
+extern const PropertyInfo css_devid_ro_propinfo;
#define DEFINE_PROP_CSS_DEV_ID_RO(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, css_devid_ro_propinfo, CssDevId)
@@ -225,4 +234,8 @@ extern PropertyInfo css_devid_ro_propinfo;
*/
SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss,
Error **errp);
+
+/** Turn on css migration */
+void css_register_vmstate(void);
+
#endif
diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h
index 3027555f6d..41a9d2862b 100644
--- a/include/hw/s390x/s390-virtio-ccw.h
+++ b/include/hw/s390x/s390-virtio-ccw.h
@@ -39,11 +39,21 @@ typedef struct S390CcwMachineClass {
/*< public >*/
bool ri_allowed;
bool cpu_model_allowed;
+ bool css_migration_enabled;
+ bool gs_allowed;
} S390CcwMachineClass;
/* runtime-instrumentation allowed by the machine */
bool ri_allowed(void);
/* cpu model allowed by the machine */
bool cpu_model_allowed(void);
+/* guarded-storage allowed by the machine */
+bool gs_allowed(void);
+
+/**
+ * Returns true if (vmstate based) migration of the channel subsystem
+ * is enabled, false if it is disabled.
+ */
+bool css_migration_enabled(void);
#endif
diff --git a/include/hw/s390x/s390_flic.h b/include/hw/s390x/s390_flic.h
index caa6fc608d..7aab6ef7f0 100644
--- a/include/hw/s390x/s390_flic.h
+++ b/include/hw/s390x/s390_flic.h
@@ -44,7 +44,7 @@ typedef struct S390FLICState {
SysBusDevice parent_obj;
/* to limit AdapterRoutes.num_routes for compat */
uint32_t adapter_routes_max_batch;
-
+ bool ais_supported;
} S390FLICState;
#define S390_FLIC_COMMON_CLASS(klass) \
@@ -56,13 +56,16 @@ typedef struct S390FLICStateClass {
DeviceClass parent_class;
int (*register_io_adapter)(S390FLICState *fs, uint32_t id, uint8_t isc,
- bool swap, bool maskable);
+ bool swap, bool maskable, uint8_t flags);
int (*io_adapter_map)(S390FLICState *fs, uint32_t id, uint64_t map_addr,
bool do_map);
int (*add_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes);
void (*release_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes);
int (*clear_io_irq)(S390FLICState *fs, uint16_t subchannel_id,
uint16_t subchannel_nr);
+ int (*modify_ais_mode)(S390FLICState *fs, uint8_t isc, uint16_t mode);
+ int (*inject_airq)(S390FLICState *fs, uint8_t type, uint8_t isc,
+ uint8_t flags);
} S390FLICStateClass;
#define TYPE_KVM_S390_FLIC "s390-flic-kvm"
@@ -73,13 +76,20 @@ typedef struct S390FLICStateClass {
#define QEMU_S390_FLIC(obj) \
OBJECT_CHECK(QEMUS390FLICState, (obj), TYPE_QEMU_S390_FLIC)
+#define SIC_IRQ_MODE_ALL 0
+#define SIC_IRQ_MODE_SINGLE 1
+#define AIS_MODE_MASK(isc) (0x80 >> isc)
+
typedef struct QEMUS390FLICState {
S390FLICState parent_obj;
+ uint8_t simm;
+ uint8_t nimm;
} QEMUS390FLICState;
void s390_flic_init(void);
S390FLICState *s390_get_flic(void);
+bool ais_needed(void *opaque);
#ifdef CONFIG_KVM
DeviceState *s390_flic_kvm_create(void);
diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h
index 3008a5148a..e71d526605 100644
--- a/include/hw/s390x/sclp.h
+++ b/include/hw/s390x/sclp.h
@@ -123,8 +123,7 @@ typedef struct ReadInfo {
uint64_t facilities; /* 48-55 */
uint8_t _reserved0[76 - 56]; /* 56-75 */
uint32_t ibc_val;
- uint8_t conf_char[96 - 80]; /* 80-95 */
- uint8_t _reserved4[99 - 96]; /* 96-98 */
+ uint8_t conf_char[99 - 80]; /* 80-98 */
uint8_t mha_pow;
uint32_t rnsize2;
uint64_t rnmax2;
diff --git a/include/hw/s390x/storage-attributes.h b/include/hw/s390x/storage-attributes.h
new file mode 100644
index 0000000000..9be954d163
--- /dev/null
+++ b/include/hw/s390x/storage-attributes.h
@@ -0,0 +1,81 @@
+/*
+ * s390 storage attributes device
+ *
+ * Copyright 2016 IBM Corp.
+ * Author(s): Claudio Imbrenda <imbrenda@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef S390_STORAGE_ATTRIBUTES_H
+#define S390_STORAGE_ATTRIBUTES_H
+
+#include <hw/qdev.h>
+#include "monitor/monitor.h"
+
+#define TYPE_S390_STATTRIB "s390-storage_attributes"
+#define TYPE_QEMU_S390_STATTRIB "s390-storage_attributes-qemu"
+#define TYPE_KVM_S390_STATTRIB "s390-storage_attributes-kvm"
+
+#define S390_STATTRIB(obj) \
+ OBJECT_CHECK(S390StAttribState, (obj), TYPE_S390_STATTRIB)
+
+typedef struct S390StAttribState {
+ DeviceState parent_obj;
+ uint64_t migration_cur_gfn;
+ bool migration_enabled;
+} S390StAttribState;
+
+#define S390_STATTRIB_CLASS(klass) \
+ OBJECT_CLASS_CHECK(S390StAttribClass, (klass), TYPE_S390_STATTRIB)
+#define S390_STATTRIB_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(S390StAttribClass, (obj), TYPE_S390_STATTRIB)
+
+typedef struct S390StAttribClass {
+ DeviceClass parent_class;
+ /* Return value: < 0 on error, or new count */
+ int (*get_stattr)(S390StAttribState *sa, uint64_t *start_gfn,
+ uint32_t count, uint8_t *values);
+ int (*peek_stattr)(S390StAttribState *sa, uint64_t start_gfn,
+ uint32_t count, uint8_t *values);
+ int (*set_stattr)(S390StAttribState *sa, uint64_t start_gfn,
+ uint32_t count, uint8_t *values);
+ void (*synchronize)(S390StAttribState *sa);
+ int (*set_migrationmode)(S390StAttribState *sa, bool value);
+ int (*get_active)(S390StAttribState *sa);
+ long long (*get_dirtycount)(S390StAttribState *sa);
+} S390StAttribClass;
+
+#define QEMU_S390_STATTRIB(obj) \
+ OBJECT_CHECK(QEMUS390StAttribState, (obj), TYPE_QEMU_S390_STATTRIB)
+
+typedef struct QEMUS390StAttribState {
+ S390StAttribState parent_obj;
+} QEMUS390StAttribState;
+
+#define KVM_S390_STATTRIB(obj) \
+ OBJECT_CHECK(KVMS390StAttribState, (obj), TYPE_KVM_S390_STATTRIB)
+
+typedef struct KVMS390StAttribState {
+ S390StAttribState parent_obj;
+ uint64_t still_dirty;
+ uint8_t *incoming_buffer;
+} KVMS390StAttribState;
+
+void s390_stattrib_init(void);
+
+#ifdef CONFIG_KVM
+Object *kvm_s390_stattrib_create(void);
+#else
+static inline Object *kvm_s390_stattrib_create(void)
+{
+ return NULL;
+}
+#endif
+
+void hmp_info_cmma(Monitor *mon, const QDict *qdict);
+void hmp_migrationmode(Monitor *mon, const QDict *qdict);
+
+#endif /* S390_STORAGE_ATTRIBUTES_H */
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index 0b475a3596..f3a2ac9fee 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -95,7 +95,7 @@ typedef struct VFIOContainer {
typedef struct VFIOGuestIOMMU {
VFIOContainer *container;
- MemoryRegion *iommu;
+ IOMMUMemoryRegion *iommu;
hwaddr iommu_offset;
IOMMUNotifier n;
QLIST_ENTRY(VFIOGuestIOMMU) giommu_next;
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index d2b3aafdb4..83ea4a1aaf 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -23,13 +23,6 @@ void monitor_cleanup(void);
int monitor_suspend(Monitor *mon);
void monitor_resume(Monitor *mon);
-int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
- BlockCompletionFunc *completion_cb,
- void *opaque);
-int monitor_read_block_device_key(Monitor *mon, const char *device,
- BlockCompletionFunc *completion_cb,
- void *opaque);
-
int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp);
int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp);
diff --git a/include/qapi/error.h b/include/qapi/error.h
index 7e532d00e9..341b229066 100644
--- a/include/qapi/error.h
+++ b/include/qapi/error.h
@@ -125,7 +125,6 @@
typedef enum ErrorClass {
ERROR_CLASS_GENERIC_ERROR = QAPI_ERROR_CLASS_GENERICERROR,
ERROR_CLASS_COMMAND_NOT_FOUND = QAPI_ERROR_CLASS_COMMANDNOTFOUND,
- ERROR_CLASS_DEVICE_ENCRYPTED = QAPI_ERROR_CLASS_DEVICEENCRYPTED,
ERROR_CLASS_DEVICE_NOT_ACTIVE = QAPI_ERROR_CLASS_DEVICENOTACTIVE,
ERROR_CLASS_DEVICE_NOT_FOUND = QAPI_ERROR_CLASS_DEVICENOTFOUND,
ERROR_CLASS_KVM_MISSING_CAP = QAPI_ERROR_CLASS_KVMMISSINGCAP,
@@ -267,11 +266,22 @@ void error_free(Error *err);
void error_free_or_abort(Error **errp);
/*
+ * Convenience function to warn_report() and free @err.
+ */
+void warn_report_err(Error *err);
+
+/*
* Convenience function to error_report() and free @err.
*/
void error_report_err(Error *err);
/*
+ * Convenience function to error_prepend(), warn_report() and free @err.
+ */
+void warn_reportf_err(Error *err, const char *fmt, ...)
+ GCC_FMT_ATTR(2, 3);
+
+/*
* Convenience function to error_prepend(), error_report() and free @err.
*/
void error_reportf_err(Error *err, const char *fmt, ...)
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
index a4509bd977..9aff9a735e 100644
--- a/include/qemu/coroutine.h
+++ b/include/qemu/coroutine.h
@@ -229,6 +229,24 @@ void qemu_co_rwlock_init(CoRwlock *lock);
void qemu_co_rwlock_rdlock(CoRwlock *lock);
/**
+ * Write Locks the CoRwlock from a reader. This is a bit more efficient than
+ * @qemu_co_rwlock_unlock followed by a separate @qemu_co_rwlock_wrlock.
+ * However, if the lock cannot be upgraded immediately, control is transferred
+ * to the caller of the current coroutine. Also, @qemu_co_rwlock_upgrade
+ * only overrides CoRwlock fairness if there are no concurrent readers, so
+ * another writer might run while @qemu_co_rwlock_upgrade blocks.
+ */
+void qemu_co_rwlock_upgrade(CoRwlock *lock);
+
+/**
+ * Downgrades a write-side critical section to a reader. Downgrading with
+ * @qemu_co_rwlock_downgrade never blocks, unlike @qemu_co_rwlock_unlock
+ * followed by @qemu_co_rwlock_rdlock. This makes it more efficient, but
+ * may also sometimes be necessary for correctness.
+ */
+void qemu_co_rwlock_downgrade(CoRwlock *lock);
+
+/**
* Write Locks the mutex. If the lock cannot be taken immediately because
* of a parallel reader, control is transferred to the caller of the current
* coroutine.
diff --git a/include/qemu/error-report.h b/include/qemu/error-report.h
index 3001865896..e1c8ae1a52 100644
--- a/include/qemu/error-report.h
+++ b/include/qemu/error-report.h
@@ -35,8 +35,15 @@ void error_printf(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
void error_vprintf_unless_qmp(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0);
void error_printf_unless_qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
void error_set_progname(const char *argv0);
+
void error_vreport(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0);
+void warn_vreport(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0);
+void info_vreport(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0);
+
void error_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+void warn_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+void info_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+
const char *error_get_progname(void);
extern bool enable_timestamp_msg;
diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
index 9239fe515e..d3a74a21fc 100644
--- a/include/qemu/hbitmap.h
+++ b/include/qemu/hbitmap.h
@@ -229,6 +229,21 @@ void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
bool finish);
/**
+ * hbitmap_deserialize_ones
+ * @hb: HBitmap to operate on.
+ * @start: First bit to restore.
+ * @count: Number of bits to restore.
+ * @finish: Whether to call hbitmap_deserialize_finish automatically.
+ *
+ * Fills the bitmap with ones.
+ *
+ * If @finish is false, caller must call hbitmap_serialize_finish before using
+ * the bitmap.
+ */
+void hbitmap_deserialize_ones(HBitmap *hb, uint64_t start, uint64_t count,
+ bool finish);
+
+/**
* hbitmap_deserialize_finish
* @hb: HBitmap to operate on.
*
@@ -238,6 +253,14 @@ void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
void hbitmap_deserialize_finish(HBitmap *hb);
/**
+ * hbitmap_sha256:
+ * @bitmap: HBitmap to operate on.
+ *
+ * Returns SHA256 hash of the last level.
+ */
+char *hbitmap_sha256(const HBitmap *bitmap, Error **errp);
+
+/**
* hbitmap_free:
* @hb: HBitmap to operate on.
*
@@ -256,10 +279,9 @@ void hbitmap_free(HBitmap *hb);
* the lowest-numbered bit that is set in @hb, starting at @first.
*
* Concurrent setting of bits is acceptable, and will at worst cause the
- * iteration to miss some of those bits. Resetting bits before the current
- * position of the iterator is also okay. However, concurrent resetting of
- * bits can lead to unexpected behavior if the iterator has not yet reached
- * those bits.
+ * iteration to miss some of those bits.
+ *
+ * The concurrent resetting of bits is OK.
*/
void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first);
@@ -298,24 +320,7 @@ void hbitmap_free_meta(HBitmap *hb);
* Return the next bit that is set in @hbi's associated HBitmap,
* or -1 if all remaining bits are zero.
*/
-static inline int64_t hbitmap_iter_next(HBitmapIter *hbi)
-{
- unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1];
- int64_t item;
-
- if (cur == 0) {
- cur = hbitmap_iter_skip_words(hbi);
- if (cur == 0) {
- return -1;
- }
- }
-
- /* The next call will resume work from the next bit. */
- hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1);
- item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ctzl(cur);
-
- return item << hbi->granularity;
-}
+int64_t hbitmap_iter_next(HBitmapIter *hbi);
/**
* hbitmap_iter_next_word:
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 85596341fa..3b74f6fcb2 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -457,8 +457,6 @@ void qemu_set_tty_echo(int fd, bool echo);
void os_mem_prealloc(int fd, char *area, size_t sz, int smp_cpus,
Error **errp);
-int qemu_read_password(char *buf, int buf_size);
-
/**
* qemu_get_pid_name:
* @pid: pid of a process
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index 5c326db232..ef6b5591f7 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -106,21 +106,6 @@ SocketAddress *socket_local_address(int fd, Error **errp);
SocketAddress *socket_remote_address(int fd, Error **errp);
/**
- * socket_address_to_string:
- * @addr: the socket address struct
- * @errp: pointer to uninitialized error object
- *
- * Get the string representation of the socket
- * address. A pointer to the char array containing
- * string format will be returned, the caller is
- * required to release the returned value when no
- * longer required with g_free.
- *
- * Returns: the socket address in string format, or NULL on error
- */
-char *socket_address_to_string(struct SocketAddress *addr, Error **errp);
-
-/**
* socket_address_flatten:
* @addr: the socket address to flatten
*
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 2706aabedf..b19159104c 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -45,6 +45,7 @@ typedef struct MachineState MachineState;
typedef struct MemoryListener MemoryListener;
typedef struct MemoryMappingList MemoryMappingList;
typedef struct MemoryRegion MemoryRegion;
+typedef struct IOMMUMemoryRegion IOMMUMemoryRegion;
typedef struct MemoryRegionCache MemoryRegionCache;
typedef struct MemoryRegionSection MemoryRegionSection;
typedef struct MigrationIncomingState MigrationIncomingState;
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 7bfd50cc32..04c31e63eb 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -265,7 +265,6 @@ struct qemu_work_item;
* @cpu_index: CPU index (informative).
* @nr_cores: Number of cores within this CPU package.
* @nr_threads: Number of threads within this CPU.
- * @host_tid: Host thread ID.
* @running: #true if CPU is currently running (lockless).
* @has_waiter: #true if a CPU is currently waiting for the cpu_exec_end;
* valid under cpu_list_lock.
@@ -319,7 +318,6 @@ struct CPUState {
HANDLE hThread;
#endif
int thread_id;
- uint32_t host_tid;
bool running, has_waiter;
struct QemuCond *halt_cond;
bool thread_kicked;
@@ -1015,6 +1013,7 @@ AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx);
void QEMU_NORETURN cpu_abort(CPUState *cpu, const char *fmt, ...)
GCC_FMT_ATTR(2, 3);
+extern Property cpu_common_props[];
void cpu_exec_initfn(CPUState *cpu);
void cpu_exec_realizefn(CPUState *cpu, Error **errp);
void cpu_exec_unrealizefn(CPUState *cpu);
diff --git a/include/qom/object.h b/include/qom/object.h
index abaeb8cf4e..1b828994fa 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -764,7 +764,7 @@ ObjectClass *object_get_class(Object *obj);
*
* Returns: The QOM typename of @obj.
*/
-const char *object_get_typename(Object *obj);
+const char *object_get_typename(const Object *obj);
/**
* type_register_static:
@@ -1319,7 +1319,7 @@ typedef enum {
* callback function. It allows the link property to be set and never returns
* an error.
*/
-void object_property_allow_set_link(Object *, const char *,
+void object_property_allow_set_link(const Object *, const char *,
Object *, Error **);
/**
@@ -1352,7 +1352,7 @@ void object_property_allow_set_link(Object *, const char *,
*/
void object_property_add_link(Object *obj, const char *name,
const char *type, Object **child,
- void (*check)(Object *obj, const char *name,
+ void (*check)(const Object *obj, const char *name,
Object *val, Error **errp),
ObjectPropertyLinkFlags flags,
Error **errp);
diff --git a/include/standard-headers/asm-x86/hyperv.h b/include/standard-headers/asm-x86/hyperv.h
index d0c6e0a079..fac7651740 100644
--- a/include/standard-headers/asm-x86/hyperv.h
+++ b/include/standard-headers/asm-x86/hyperv.h
@@ -34,16 +34,10 @@
#define HV_X64_MSR_REFERENCE_TSC 0x40000021
/*
- * There is a single feature flag that signifies the presence of the MSR
- * that can be used to retrieve both the local APIC Timer frequency as
- * well as the TSC frequency.
+ * There is a single feature flag that signifies if the partition has access
+ * to MSRs with local APIC and TSC frequencies.
*/
-
-/* Local APIC timer frequency MSR (HV_X64_MSR_APIC_FREQUENCY) is available */
-#define HV_X64_MSR_APIC_FREQUENCY_AVAILABLE (1 << 11)
-
-/* TSC frequency MSR (HV_X64_MSR_TSC_FREQUENCY) is available */
-#define HV_X64_MSR_TSC_FREQUENCY_AVAILABLE (1 << 11)
+#define HV_X64_ACCESS_FREQUENCY_MSRS (1 << 11)
/*
* Basic SynIC MSRs (HV_X64_MSR_SCONTROL through HV_X64_MSR_EOM
@@ -73,6 +67,9 @@
*/
#define HV_X64_MSR_STAT_PAGES_AVAILABLE (1 << 8)
+/* Frequency MSRs available */
+#define HV_FEATURE_FREQUENCY_MSRS_AVAILABLE (1 << 8)
+
/* Crash MSR available */
#define HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE (1 << 10)
@@ -153,6 +150,12 @@
#define HV_X64_DEPRECATING_AEOI_RECOMMENDED (1 << 9)
/*
+ * HV_VP_SET available
+ */
+#define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED (1 << 11)
+
+
+/*
* Crash notification flag.
*/
#define HV_CRASH_CTL_CRASH_NOTIFY (1ULL << 63)
diff --git a/include/standard-headers/linux/input-event-codes.h b/include/standard-headers/linux/input-event-codes.h
index 29d463af37..2fa0f4ea6b 100644
--- a/include/standard-headers/linux/input-event-codes.h
+++ b/include/standard-headers/linux/input-event-codes.h
@@ -600,6 +600,7 @@
#define KEY_APPSELECT 0x244 /* AL Select Task/Application */
#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */
#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */
+#define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */
#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */
#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */
diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h
index d56bb00510..c22d3ebaca 100644
--- a/include/standard-headers/linux/pci_regs.h
+++ b/include/standard-headers/linux/pci_regs.h
@@ -517,6 +517,7 @@
#define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */
#define PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */
#define PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */
+#define PCI_EXP_LNKCAP_SLS_8_0GB 0x00000003 /* LNKCAP2 SLS Vector bit 2 */
#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */
#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */
#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 1e05281fff..d9ea0cdb0f 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -223,7 +223,8 @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
int bytes, BdrvRequestFlags flags);
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
int bytes);
-int blk_truncate(BlockBackend *blk, int64_t offset, Error **errp);
+int blk_truncate(BlockBackend *blk, int64_t offset, PreallocMode prealloc,
+ Error **errp);
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
int64_t pos, int size);
diff --git a/io/channel-websock.c b/io/channel-websock.c
index 8fabadea2f..5a3badbec2 100644
--- a/io/channel-websock.c
+++ b/io/channel-websock.c
@@ -856,7 +856,7 @@ static ssize_t qio_channel_websock_readv(QIOChannel *ioc,
ssize_t ret;
if (wioc->io_err) {
- *errp = error_copy(wioc->io_err);
+ error_propagate(errp, error_copy(wioc->io_err));
return -1;
}
@@ -902,7 +902,7 @@ static ssize_t qio_channel_websock_writev(QIOChannel *ioc,
ssize_t ret;
if (wioc->io_err) {
- *errp = error_copy(wioc->io_err);
+ error_propagate(errp, error_copy(wioc->io_err));
return -1;
}
diff --git a/io/dns-resolver.c b/io/dns-resolver.c
index 57a8896cbb..c072d121c3 100644
--- a/io/dns-resolver.c
+++ b/io/dns-resolver.c
@@ -116,8 +116,10 @@ static int qio_dns_resolver_lookup_sync_inet(QIODNSResolver *resolver,
.numeric = true,
.has_to = iaddr->has_to,
.to = iaddr->to,
- .has_ipv4 = false,
- .has_ipv6 = false,
+ .has_ipv4 = iaddr->has_ipv4,
+ .ipv4 = iaddr->ipv4,
+ .has_ipv6 = iaddr->has_ipv6,
+ .ipv6 = iaddr->ipv6,
};
(*addrs)[i] = newaddr;
diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h
index 7258a00225..fa9fae8dc2 100644
--- a/linux-headers/asm-arm/kvm.h
+++ b/linux-headers/asm-arm/kvm.h
@@ -203,6 +203,14 @@ struct kvm_arch_memory_slot {
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
#define VGIC_LEVEL_INFO_LINE_LEVEL 0
+/* Device Control API on vcpu fd */
+#define KVM_ARM_VCPU_PMU_V3_CTRL 0
+#define KVM_ARM_VCPU_PMU_V3_IRQ 0
+#define KVM_ARM_VCPU_PMU_V3_INIT 1
+#define KVM_ARM_VCPU_TIMER_CTRL 1
+#define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0
+#define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1
+
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
#define KVM_DEV_ARM_ITS_SAVE_TABLES 1
#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2
diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
index 31bb1dd924..d254700b08 100644
--- a/linux-headers/asm-arm64/kvm.h
+++ b/linux-headers/asm-arm64/kvm.h
@@ -232,6 +232,9 @@ struct kvm_arch_memory_slot {
#define KVM_ARM_VCPU_PMU_V3_CTRL 0
#define KVM_ARM_VCPU_PMU_V3_IRQ 0
#define KVM_ARM_VCPU_PMU_V3_INIT 1
+#define KVM_ARM_VCPU_TIMER_CTRL 1
+#define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0
+#define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1
/* KVM_IRQ_LINE irq field index values */
#define KVM_ARM_IRQ_TYPE_SHIFT 24
diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index 07fbeb9278..8cf8f0c969 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -60,6 +60,12 @@ struct kvm_regs {
#define KVM_SREGS_E_FSL_PIDn (1 << 0) /* PID1/PID2 */
+/* flags for kvm_run.flags */
+#define KVM_RUN_PPC_NMI_DISP_MASK (3 << 0)
+#define KVM_RUN_PPC_NMI_DISP_FULLY_RECOV (1 << 0)
+#define KVM_RUN_PPC_NMI_DISP_LIMITED_RECOV (2 << 0)
+#define KVM_RUN_PPC_NMI_DISP_NOT_RECOV (3 << 0)
+
/*
* Feature bits indicate which sections of the sregs struct are valid,
* both in KVM_GET_SREGS and KVM_SET_SREGS. On KVM_SET_SREGS, registers
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index 243f195776..8387d71c7e 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -28,6 +28,7 @@
#define KVM_DEV_FLIC_CLEAR_IO_IRQ 8
#define KVM_DEV_FLIC_AISM 9
#define KVM_DEV_FLIC_AIRQ_INJECT 10
+#define KVM_DEV_FLIC_AISM_ALL 11
/*
* We can have up to 4*64k pending subchannels + 8 adapter interrupts,
* as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts.
@@ -53,6 +54,11 @@ struct kvm_s390_ais_req {
__u16 mode;
};
+struct kvm_s390_ais_all {
+ __u8 simm;
+ __u8 nimm;
+};
+
#define KVM_S390_IO_ADAPTER_MASK 1
#define KVM_S390_IO_ADAPTER_MAP 2
#define KVM_S390_IO_ADAPTER_UNMAP 3
@@ -70,6 +76,7 @@ struct kvm_s390_io_adapter_req {
#define KVM_S390_VM_TOD 1
#define KVM_S390_VM_CRYPTO 2
#define KVM_S390_VM_CPU_MODEL 3
+#define KVM_S390_VM_MIGRATION 4
/* kvm attributes for mem_ctrl */
#define KVM_S390_VM_MEM_ENABLE_CMMA 0
@@ -151,6 +158,11 @@ struct kvm_s390_vm_cpu_subfunc {
#define KVM_S390_VM_CRYPTO_DISABLE_AES_KW 2
#define KVM_S390_VM_CRYPTO_DISABLE_DEA_KW 3
+/* kvm attributes for migration mode */
+#define KVM_S390_VM_MIGRATION_STOP 0
+#define KVM_S390_VM_MIGRATION_START 1
+#define KVM_S390_VM_MIGRATION_STATUS 2
+
/* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs {
/* general purpose regs for s390 */
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index d2892da172..43e2d82be1 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -155,6 +155,35 @@ struct kvm_s390_skeys {
__u32 reserved[9];
};
+#define KVM_S390_CMMA_PEEK (1 << 0)
+
+/**
+ * kvm_s390_cmma_log - Used for CMMA migration.
+ *
+ * Used both for input and output.
+ *
+ * @start_gfn: Guest page number to start from.
+ * @count: Size of the result buffer.
+ * @flags: Control operation mode via KVM_S390_CMMA_* flags
+ * @remaining: Used with KVM_S390_GET_CMMA_BITS. Indicates how many dirty
+ * pages are still remaining.
+ * @mask: Used with KVM_S390_SET_CMMA_BITS. Bitmap of bits to actually set
+ * in the PGSTE.
+ * @values: Pointer to the values buffer.
+ *
+ * Used in KVM_S390_{G,S}ET_CMMA_BITS ioctls.
+ */
+struct kvm_s390_cmma_log {
+ __u64 start_gfn;
+ __u32 count;
+ __u32 flags;
+ union {
+ __u64 remaining;
+ __u64 mask;
+ };
+ __u64 values;
+};
+
struct kvm_hyperv_exit {
#define KVM_EXIT_HYPERV_SYNIC 1
#define KVM_EXIT_HYPERV_HCALL 2
@@ -895,6 +924,9 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_SPAPR_TCE_VFIO 142
#define KVM_CAP_X86_GUEST_MWAIT 143
#define KVM_CAP_ARM_USER_IRQ 144
+#define KVM_CAP_S390_CMMA_MIGRATION 145
+#define KVM_CAP_PPC_FWNMI 146
+#define KVM_CAP_PPC_SMT_POSSIBLE 147
#ifdef KVM_CAP_IRQ_ROUTING
@@ -1318,6 +1350,9 @@ struct kvm_s390_ucas_mapping {
#define KVM_S390_GET_IRQ_STATE _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state)
/* Available with KVM_CAP_X86_SMM */
#define KVM_SMI _IO(KVMIO, 0xb7)
+/* Available with KVM_CAP_S390_CMMA_MIGRATION */
+#define KVM_S390_GET_CMMA_BITS _IOW(KVMIO, 0xb8, struct kvm_s390_cmma_log)
+#define KVM_S390_SET_CMMA_BITS _IOW(KVMIO, 0xb9, struct kvm_s390_cmma_log)
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 925ae11ea6..003943b736 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6219,7 +6219,6 @@ static void *clone_func(void *arg)
thread_cpu = cpu;
ts = (TaskState *)cpu->opaque;
info->tid = gettid();
- cpu->host_tid = info->tid;
task_settid(ts);
if (info->child_tidptr)
put_user_u32(info->tid, info->child_tidptr);
diff --git a/memory.c b/memory.c
index 1044bbaf0c..a7bc70aac1 100644
--- a/memory.c
+++ b/memory.c
@@ -32,6 +32,7 @@
#include "sysemu/sysemu.h"
#include "hw/misc/mmio_interface.h"
#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
//#define DEBUG_UNASSIGNED
@@ -977,12 +978,11 @@ static char *memory_region_escape_name(const char *name)
return escaped;
}
-void memory_region_init(MemoryRegion *mr,
- Object *owner,
- const char *name,
- uint64_t size)
+static void memory_region_do_init(MemoryRegion *mr,
+ Object *owner,
+ const char *name,
+ uint64_t size)
{
- object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
mr->size = int128_make64(size);
if (size == UINT64_MAX) {
mr->size = int128_2_64();
@@ -1006,6 +1006,15 @@ void memory_region_init(MemoryRegion *mr,
}
}
+void memory_region_init(MemoryRegion *mr,
+ Object *owner,
+ const char *name,
+ uint64_t size)
+{
+ object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
+ memory_region_do_init(mr, owner, name, size);
+}
+
static void memory_region_get_addr(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -1092,6 +1101,13 @@ static void memory_region_initfn(Object *obj)
NULL, NULL, &error_abort);
}
+static void iommu_memory_region_initfn(Object *obj)
+{
+ MemoryRegion *mr = MEMORY_REGION(obj);
+
+ mr->is_iommu = true;
+}
+
static uint64_t unassigned_mem_read(void *opaque, hwaddr addr,
unsigned size)
{
@@ -1350,11 +1366,11 @@ void memory_region_init_io(MemoryRegion *mr,
mr->terminates = true;
}
-void memory_region_init_ram(MemoryRegion *mr,
- Object *owner,
- const char *name,
- uint64_t size,
- Error **errp)
+void memory_region_init_ram_nomigrate(MemoryRegion *mr,
+ Object *owner,
+ const char *name,
+ uint64_t size,
+ Error **errp)
{
memory_region_init(mr, owner, name, size);
mr->ram = true;
@@ -1458,11 +1474,11 @@ void memory_region_init_alias(MemoryRegion *mr,
mr->alias_offset = offset;
}
-void memory_region_init_rom(MemoryRegion *mr,
- struct Object *owner,
- const char *name,
- uint64_t size,
- Error **errp)
+void memory_region_init_rom_nomigrate(MemoryRegion *mr,
+ struct Object *owner,
+ const char *name,
+ uint64_t size,
+ Error **errp)
{
memory_region_init(mr, owner, name, size);
mr->ram = true;
@@ -1473,13 +1489,13 @@ void memory_region_init_rom(MemoryRegion *mr,
mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
}
-void memory_region_init_rom_device(MemoryRegion *mr,
- Object *owner,
- const MemoryRegionOps *ops,
- void *opaque,
- const char *name,
- uint64_t size,
- Error **errp)
+void memory_region_init_rom_device_nomigrate(MemoryRegion *mr,
+ Object *owner,
+ const MemoryRegionOps *ops,
+ void *opaque,
+ const char *name,
+ uint64_t size,
+ Error **errp)
{
assert(ops);
memory_region_init(mr, owner, name, size);
@@ -1491,17 +1507,23 @@ void memory_region_init_rom_device(MemoryRegion *mr,
mr->ram_block = qemu_ram_alloc(size, mr, errp);
}
-void memory_region_init_iommu(MemoryRegion *mr,
+void memory_region_init_iommu(void *_iommu_mr,
+ size_t instance_size,
+ const char *mrtypename,
Object *owner,
- const MemoryRegionIOMMUOps *ops,
const char *name,
uint64_t size)
{
- memory_region_init(mr, owner, name, size);
- mr->iommu_ops = ops,
+ struct IOMMUMemoryRegion *iommu_mr;
+ struct MemoryRegion *mr;
+
+ object_initialize(_iommu_mr, instance_size, mrtypename);
+ mr = MEMORY_REGION(_iommu_mr);
+ memory_region_do_init(mr, owner, name, size);
+ iommu_mr = IOMMU_MEMORY_REGION(mr);
mr->terminates = true; /* then re-forwards */
- QLIST_INIT(&mr->iommu_notify);
- mr->iommu_notify_flags = IOMMU_NOTIFIER_NONE;
+ QLIST_INIT(&iommu_mr->iommu_notify);
+ iommu_mr->iommu_notify_flags = IOMMU_NOTIFIER_NONE;
}
static void memory_region_finalize(Object *obj)
@@ -1596,63 +1618,70 @@ bool memory_region_is_logging(MemoryRegion *mr, uint8_t client)
return memory_region_get_dirty_log_mask(mr) & (1 << client);
}
-static void memory_region_update_iommu_notify_flags(MemoryRegion *mr)
+static void memory_region_update_iommu_notify_flags(IOMMUMemoryRegion *iommu_mr)
{
IOMMUNotifierFlag flags = IOMMU_NOTIFIER_NONE;
IOMMUNotifier *iommu_notifier;
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
- IOMMU_NOTIFIER_FOREACH(iommu_notifier, mr) {
+ IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) {
flags |= iommu_notifier->notifier_flags;
}
- if (flags != mr->iommu_notify_flags &&
- mr->iommu_ops->notify_flag_changed) {
- mr->iommu_ops->notify_flag_changed(mr, mr->iommu_notify_flags,
- flags);
+ if (flags != iommu_mr->iommu_notify_flags && imrc->notify_flag_changed) {
+ imrc->notify_flag_changed(iommu_mr,
+ iommu_mr->iommu_notify_flags,
+ flags);
}
- mr->iommu_notify_flags = flags;
+ iommu_mr->iommu_notify_flags = flags;
}
void memory_region_register_iommu_notifier(MemoryRegion *mr,
IOMMUNotifier *n)
{
+ IOMMUMemoryRegion *iommu_mr;
+
if (mr->alias) {
memory_region_register_iommu_notifier(mr->alias, n);
return;
}
/* We need to register for at least one bitfield */
+ iommu_mr = IOMMU_MEMORY_REGION(mr);
assert(n->notifier_flags != IOMMU_NOTIFIER_NONE);
assert(n->start <= n->end);
- QLIST_INSERT_HEAD(&mr->iommu_notify, n, node);
- memory_region_update_iommu_notify_flags(mr);
+ QLIST_INSERT_HEAD(&iommu_mr->iommu_notify, n, node);
+ memory_region_update_iommu_notify_flags(iommu_mr);
}
-uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr)
+uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr)
{
- assert(memory_region_is_iommu(mr));
- if (mr->iommu_ops && mr->iommu_ops->get_min_page_size) {
- return mr->iommu_ops->get_min_page_size(mr);
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
+
+ if (imrc->get_min_page_size) {
+ return imrc->get_min_page_size(iommu_mr);
}
return TARGET_PAGE_SIZE;
}
-void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n)
+void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
{
+ MemoryRegion *mr = MEMORY_REGION(iommu_mr);
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
hwaddr addr, granularity;
IOMMUTLBEntry iotlb;
/* If the IOMMU has its own replay callback, override */
- if (mr->iommu_ops->replay) {
- mr->iommu_ops->replay(mr, n);
+ if (imrc->replay) {
+ imrc->replay(iommu_mr, n);
return;
}
- granularity = memory_region_iommu_get_min_page_size(mr);
+ granularity = memory_region_iommu_get_min_page_size(iommu_mr);
for (addr = 0; addr < memory_region_size(mr); addr += granularity) {
- iotlb = mr->iommu_ops->translate(mr, addr, IOMMU_NONE);
+ iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE);
if (iotlb.perm != IOMMU_NONE) {
n->notify(n, &iotlb);
}
@@ -1665,24 +1694,27 @@ void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n)
}
}
-void memory_region_iommu_replay_all(MemoryRegion *mr)
+void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr)
{
IOMMUNotifier *notifier;
- IOMMU_NOTIFIER_FOREACH(notifier, mr) {
- memory_region_iommu_replay(mr, notifier);
+ IOMMU_NOTIFIER_FOREACH(notifier, iommu_mr) {
+ memory_region_iommu_replay(iommu_mr, notifier);
}
}
void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
IOMMUNotifier *n)
{
+ IOMMUMemoryRegion *iommu_mr;
+
if (mr->alias) {
memory_region_unregister_iommu_notifier(mr->alias, n);
return;
}
QLIST_REMOVE(n, node);
- memory_region_update_iommu_notify_flags(mr);
+ iommu_mr = IOMMU_MEMORY_REGION(mr);
+ memory_region_update_iommu_notify_flags(iommu_mr);
}
void memory_region_notify_one(IOMMUNotifier *notifier,
@@ -1710,14 +1742,14 @@ void memory_region_notify_one(IOMMUNotifier *notifier,
}
}
-void memory_region_notify_iommu(MemoryRegion *mr,
+void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
IOMMUTLBEntry entry)
{
IOMMUNotifier *iommu_notifier;
- assert(memory_region_is_iommu(mr));
+ assert(memory_region_is_iommu(MEMORY_REGION(iommu_mr)));
- IOMMU_NOTIFIER_FOREACH(iommu_notifier, mr) {
+ IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) {
memory_region_notify_one(iommu_notifier, &entry);
}
}
@@ -2817,6 +2849,81 @@ void mtree_info(fprintf_function mon_printf, void *f, bool flatview)
}
}
+void memory_region_init_ram(MemoryRegion *mr,
+ struct Object *owner,
+ const char *name,
+ uint64_t size,
+ Error **errp)
+{
+ DeviceState *owner_dev;
+ Error *err = NULL;
+
+ memory_region_init_ram_nomigrate(mr, owner, name, size, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ /* This will assert if owner is neither NULL nor a DeviceState.
+ * We only want the owner here for the purposes of defining a
+ * unique name for migration. TODO: Ideally we should implement
+ * a naming scheme for Objects which are not DeviceStates, in
+ * which case we can relax this restriction.
+ */
+ owner_dev = DEVICE(owner);
+ vmstate_register_ram(mr, owner_dev);
+}
+
+void memory_region_init_rom(MemoryRegion *mr,
+ struct Object *owner,
+ const char *name,
+ uint64_t size,
+ Error **errp)
+{
+ DeviceState *owner_dev;
+ Error *err = NULL;
+
+ memory_region_init_rom_nomigrate(mr, owner, name, size, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ /* This will assert if owner is neither NULL nor a DeviceState.
+ * We only want the owner here for the purposes of defining a
+ * unique name for migration. TODO: Ideally we should implement
+ * a naming scheme for Objects which are not DeviceStates, in
+ * which case we can relax this restriction.
+ */
+ owner_dev = DEVICE(owner);
+ vmstate_register_ram(mr, owner_dev);
+}
+
+void memory_region_init_rom_device(MemoryRegion *mr,
+ struct Object *owner,
+ const MemoryRegionOps *ops,
+ void *opaque,
+ const char *name,
+ uint64_t size,
+ Error **errp)
+{
+ DeviceState *owner_dev;
+ Error *err = NULL;
+
+ memory_region_init_rom_device_nomigrate(mr, owner, ops, opaque,
+ name, size, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ /* This will assert if owner is neither NULL nor a DeviceState.
+ * We only want the owner here for the purposes of defining a
+ * unique name for migration. TODO: Ideally we should implement
+ * a naming scheme for Objects which are not DeviceStates, in
+ * which case we can relax this restriction.
+ */
+ owner_dev = DEVICE(owner);
+ vmstate_register_ram(mr, owner_dev);
+}
+
static const TypeInfo memory_region_info = {
.parent = TYPE_OBJECT,
.name = TYPE_MEMORY_REGION,
@@ -2825,9 +2932,19 @@ static const TypeInfo memory_region_info = {
.instance_finalize = memory_region_finalize,
};
+static const TypeInfo iommu_memory_region_info = {
+ .parent = TYPE_MEMORY_REGION,
+ .name = TYPE_IOMMU_MEMORY_REGION,
+ .class_size = sizeof(IOMMUMemoryRegionClass),
+ .instance_size = sizeof(IOMMUMemoryRegion),
+ .instance_init = iommu_memory_region_initfn,
+ .abstract = true,
+};
+
static void memory_register_types(void)
{
type_register_static(&memory_region_info);
+ type_register_static(&iommu_memory_region_info);
}
type_init(memory_register_types)
diff --git a/monitor.c b/monitor.c
index d8ac20f6ca..6d040e620f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -81,6 +81,7 @@
#if defined(TARGET_S390X)
#include "hw/s390x/storage-keys.h"
+#include "hw/s390x/storage-attributes.h"
#endif
/*
@@ -3842,7 +3843,7 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
req_json = qobject_to_json(req);
trace_handle_qmp_command(mon, qstring_get_str(req_json));
- qobject_decref(QOBJECT(req_json));
+ QDECREF(req_json);
rsp = qmp_dispatch(cur_mon->qmp.commands, req);
@@ -4110,12 +4111,12 @@ void monitor_init(Chardev *chr, int flags)
if (monitor_is_qmp(mon)) {
qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_qmp_read,
- monitor_qmp_event, mon, NULL, true);
+ monitor_qmp_event, NULL, mon, NULL, true);
qemu_chr_fe_set_echo(&mon->chr, true);
json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
} else {
qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read,
- monitor_event, mon, NULL, true);
+ monitor_event, NULL, mon, NULL, true);
}
qemu_mutex_lock(&monitor_lock);
@@ -4136,74 +4137,6 @@ void monitor_cleanup(void)
qemu_mutex_unlock(&monitor_lock);
}
-static void bdrv_password_cb(void *opaque, const char *password,
- void *readline_opaque)
-{
- Monitor *mon = opaque;
- BlockDriverState *bs = readline_opaque;
- int ret = 0;
- Error *local_err = NULL;
-
- bdrv_add_key(bs, password, &local_err);
- if (local_err) {
- error_report_err(local_err);
- ret = -EPERM;
- }
- if (mon->password_completion_cb)
- mon->password_completion_cb(mon->password_opaque, ret);
-
- monitor_read_command(mon, 1);
-}
-
-int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
- BlockCompletionFunc *completion_cb,
- void *opaque)
-{
- int err;
-
- monitor_printf(mon, "%s (%s) is encrypted.\n", bdrv_get_device_name(bs),
- bdrv_get_encrypted_filename(bs));
-
- mon->password_completion_cb = completion_cb;
- mon->password_opaque = opaque;
-
- err = monitor_read_password(mon, bdrv_password_cb, bs);
-
- if (err && completion_cb)
- completion_cb(opaque, err);
-
- return err;
-}
-
-int monitor_read_block_device_key(Monitor *mon, const char *device,
- BlockCompletionFunc *completion_cb,
- void *opaque)
-{
- Error *err = NULL;
- BlockBackend *blk;
-
- blk = blk_by_name(device);
- if (!blk) {
- monitor_printf(mon, "Device not found %s\n", device);
- return -1;
- }
- if (!blk_bs(blk)) {
- monitor_printf(mon, "Device '%s' has no medium\n", device);
- return -1;
- }
-
- bdrv_add_key(blk_bs(blk), NULL, &err);
- if (err) {
- error_free(err);
- return monitor_read_bdrv_key_start(mon, blk_bs(blk), completion_cb, opaque);
- }
-
- if (completion_cb) {
- completion_cb(opaque, 0);
- }
- return 0;
-}
-
QemuOptsList qemu_mon_opts = {
.name = "mon",
.implied_opt_name = "chardev",
diff --git a/nbd/client.c b/nbd/client.c
index 9c52b9b885..c3ee9f36b1 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Red Hat, Inc.
+ * Copyright (C) 2016-2017 Red Hat, Inc.
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device Client Side
@@ -104,7 +104,7 @@ static int nbd_send_option_request(QIOChannel *ioc, uint32_t opt,
if (len == -1) {
req.length = len = strlen(data);
}
- trace_nbd_send_option_request(opt, len);
+ trace_nbd_send_option_request(opt, nbd_opt_lookup(opt), len);
stq_be_p(&req.magic, NBD_OPTS_MAGIC);
stl_be_p(&req.option, opt);
@@ -154,7 +154,9 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt,
be32_to_cpus(&reply->type);
be32_to_cpus(&reply->length);
- trace_nbd_receive_option_reply(reply->option, reply->type, reply->length);
+ trace_nbd_receive_option_reply(reply->option, nbd_opt_lookup(reply->option),
+ reply->type, nbd_rep_lookup(reply->type),
+ reply->length);
if (reply->magic != NBD_REP_MAGIC) {
error_setg(errp, "Unexpected option reply magic");
@@ -188,12 +190,16 @@ static int nbd_handle_reply_err(QIOChannel *ioc, nbd_opt_reply *reply,
if (reply->length) {
if (reply->length > NBD_MAX_BUFFER_SIZE) {
- error_setg(errp, "server's error message is too long");
+ error_setg(errp, "server error 0x%" PRIx32
+ " (%s) message is too long",
+ reply->type, nbd_rep_lookup(reply->type));
goto cleanup;
}
msg = g_malloc(reply->length + 1);
if (nbd_read(ioc, msg, reply->length, errp) < 0) {
- error_prepend(errp, "failed to read option error message");
+ error_prepend(errp, "failed to read option error 0x%" PRIx32
+ " (%s) message",
+ reply->type, nbd_rep_lookup(reply->type));
goto cleanup;
}
msg[reply->length] = '\0';
@@ -201,38 +207,48 @@ static int nbd_handle_reply_err(QIOChannel *ioc, nbd_opt_reply *reply,
switch (reply->type) {
case NBD_REP_ERR_UNSUP:
- trace_nbd_reply_err_unsup(reply->option);
+ trace_nbd_reply_err_unsup(reply->option, nbd_opt_lookup(reply->option));
result = 0;
goto cleanup;
case NBD_REP_ERR_POLICY:
- error_setg(errp, "Denied by server for option %" PRIx32,
- reply->option);
+ error_setg(errp, "Denied by server for option %" PRIx32 " (%s)",
+ reply->option, nbd_opt_lookup(reply->option));
break;
case NBD_REP_ERR_INVALID:
- error_setg(errp, "Invalid data length for option %" PRIx32,
- reply->option);
+ error_setg(errp, "Invalid data length for option %" PRIx32 " (%s)",
+ reply->option, nbd_opt_lookup(reply->option));
break;
case NBD_REP_ERR_PLATFORM:
- error_setg(errp, "Server lacks support for option %" PRIx32,
- reply->option);
+ error_setg(errp, "Server lacks support for option %" PRIx32 " (%s)",
+ reply->option, nbd_opt_lookup(reply->option));
break;
case NBD_REP_ERR_TLS_REQD:
- error_setg(errp, "TLS negotiation required before option %" PRIx32,
- reply->option);
+ error_setg(errp, "TLS negotiation required before option %" PRIx32
+ " (%s)", reply->option, nbd_opt_lookup(reply->option));
+ break;
+
+ case NBD_REP_ERR_UNKNOWN:
+ error_setg(errp, "Requested export not available for option %" PRIx32
+ " (%s)", reply->option, nbd_opt_lookup(reply->option));
break;
case NBD_REP_ERR_SHUTDOWN:
- error_setg(errp, "Server shutting down before option %" PRIx32,
- reply->option);
+ error_setg(errp, "Server shutting down before option %" PRIx32 " (%s)",
+ reply->option, nbd_opt_lookup(reply->option));
+ break;
+
+ case NBD_REP_ERR_BLOCK_SIZE_REQD:
+ error_setg(errp, "Server requires INFO_BLOCK_SIZE for option %" PRIx32
+ " (%s)", reply->option, nbd_opt_lookup(reply->option));
break;
default:
- error_setg(errp, "Unknown error code when asking for option %" PRIx32,
- reply->option);
+ error_setg(errp, "Unknown error code when asking for option %" PRIx32
+ " (%s)", reply->option, nbd_opt_lookup(reply->option));
break;
}
@@ -334,6 +350,165 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
}
+/* Returns -1 if NBD_OPT_GO proves the export @wantname cannot be
+ * used, 0 if NBD_OPT_GO is unsupported (fall back to NBD_OPT_LIST and
+ * NBD_OPT_EXPORT_NAME in that case), and > 0 if the export is good to
+ * go (with @info populated). */
+static int nbd_opt_go(QIOChannel *ioc, const char *wantname,
+ NBDExportInfo *info, Error **errp)
+{
+ nbd_opt_reply reply;
+ uint32_t len = strlen(wantname);
+ uint16_t type;
+ int error;
+ char *buf;
+
+ /* The protocol requires that the server send NBD_INFO_EXPORT with
+ * a non-zero flags (at least NBD_FLAG_HAS_FLAGS must be set); so
+ * flags still 0 is a witness of a broken server. */
+ info->flags = 0;
+
+ trace_nbd_opt_go_start(wantname);
+ buf = g_malloc(4 + len + 2 + 2 * info->request_sizes + 1);
+ stl_be_p(buf, len);
+ memcpy(buf + 4, wantname, len);
+ /* At most one request, everything else up to server */
+ stw_be_p(buf + 4 + len, info->request_sizes);
+ if (info->request_sizes) {
+ stw_be_p(buf + 4 + len + 2, NBD_INFO_BLOCK_SIZE);
+ }
+ if (nbd_send_option_request(ioc, NBD_OPT_GO,
+ 4 + len + 2 + 2 * info->request_sizes, buf,
+ errp) < 0) {
+ return -1;
+ }
+
+ while (1) {
+ if (nbd_receive_option_reply(ioc, NBD_OPT_GO, &reply, errp) < 0) {
+ return -1;
+ }
+ error = nbd_handle_reply_err(ioc, &reply, errp);
+ if (error <= 0) {
+ return error;
+ }
+ len = reply.length;
+
+ if (reply.type == NBD_REP_ACK) {
+ /* Server is done sending info and moved into transmission
+ phase, but make sure it sent flags */
+ if (len) {
+ error_setg(errp, "server sent invalid NBD_REP_ACK");
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ if (!info->flags) {
+ error_setg(errp, "broken server omitted NBD_INFO_EXPORT");
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ trace_nbd_opt_go_success();
+ return 1;
+ }
+ if (reply.type != NBD_REP_INFO) {
+ error_setg(errp, "unexpected reply type %" PRIx32
+ " (%s), expected %x",
+ reply.type, nbd_rep_lookup(reply.type), NBD_REP_INFO);
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ if (len < sizeof(type)) {
+ error_setg(errp, "NBD_REP_INFO length %" PRIu32 " is too short",
+ len);
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ if (nbd_read(ioc, &type, sizeof(type), errp) < 0) {
+ error_prepend(errp, "failed to read info type");
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ len -= sizeof(type);
+ be16_to_cpus(&type);
+ switch (type) {
+ case NBD_INFO_EXPORT:
+ if (len != sizeof(info->size) + sizeof(info->flags)) {
+ error_setg(errp, "remaining export info len %" PRIu32
+ " is unexpected size", len);
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) {
+ error_prepend(errp, "failed to read info size");
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ be64_to_cpus(&info->size);
+ if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) {
+ error_prepend(errp, "failed to read info flags");
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ be16_to_cpus(&info->flags);
+ trace_nbd_receive_negotiate_size_flags(info->size, info->flags);
+ break;
+
+ case NBD_INFO_BLOCK_SIZE:
+ if (len != sizeof(info->min_block) * 3) {
+ error_setg(errp, "remaining export info len %" PRIu32
+ " is unexpected size", len);
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ if (nbd_read(ioc, &info->min_block, sizeof(info->min_block),
+ errp) < 0) {
+ error_prepend(errp, "failed to read info minimum block size");
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ be32_to_cpus(&info->min_block);
+ if (!is_power_of_2(info->min_block)) {
+ error_setg(errp, "server minimum block size %" PRId32
+ "is not a power of two", info->min_block);
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ if (nbd_read(ioc, &info->opt_block, sizeof(info->opt_block),
+ errp) < 0) {
+ error_prepend(errp, "failed to read info preferred block size");
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ be32_to_cpus(&info->opt_block);
+ if (!is_power_of_2(info->opt_block) ||
+ info->opt_block < info->min_block) {
+ error_setg(errp, "server preferred block size %" PRId32
+ "is not valid", info->opt_block);
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ if (nbd_read(ioc, &info->max_block, sizeof(info->max_block),
+ errp) < 0) {
+ error_prepend(errp, "failed to read info maximum block size");
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ be32_to_cpus(&info->max_block);
+ trace_nbd_opt_go_info_block_size(info->min_block, info->opt_block,
+ info->max_block);
+ break;
+
+ default:
+ trace_nbd_opt_go_info_unknown(type, nbd_info_lookup(type));
+ if (nbd_drop(ioc, len, errp) < 0) {
+ error_prepend(errp, "Failed to read info payload");
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ break;
+ }
+ }
+}
+
/* Return -1 on failure, 0 if wantname is an available export. */
static int nbd_receive_query_exports(QIOChannel *ioc,
const char *wantname,
@@ -425,13 +600,13 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc,
}
-int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
+int nbd_receive_negotiate(QIOChannel *ioc, const char *name,
QCryptoTLSCreds *tlscreds, const char *hostname,
- QIOChannel **outioc,
- off_t *size, Error **errp)
+ QIOChannel **outioc, NBDExportInfo *info,
+ Error **errp)
{
char buf[256];
- uint64_t magic, s;
+ uint64_t magic;
int rc;
bool zeroes = true;
@@ -515,11 +690,25 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
name = "";
}
if (fixedNewStyle) {
+ int result;
+
+ /* Try NBD_OPT_GO first - if it works, we are done (it
+ * also gives us a good message if the server requires
+ * TLS). If it is not available, fall back to
+ * NBD_OPT_LIST for nicer error messages about a missing
+ * export, then use NBD_OPT_EXPORT_NAME. */
+ result = nbd_opt_go(ioc, name, info, errp);
+ if (result < 0) {
+ goto fail;
+ }
+ if (result > 0) {
+ return 0;
+ }
/* Check our desired export is present in the
* server export list. Since NBD_OPT_EXPORT_NAME
* cannot return an error message, running this
- * query gives us good error reporting if the
- * server required TLS
+ * query gives us better error reporting if the
+ * export name is not available.
*/
if (nbd_receive_query_exports(ioc, name, errp) < 0) {
goto fail;
@@ -532,17 +721,17 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
}
/* Read the response */
- if (nbd_read(ioc, &s, sizeof(s), errp) < 0) {
+ if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) {
error_prepend(errp, "Failed to read export length");
goto fail;
}
- *size = be64_to_cpu(s);
+ be64_to_cpus(&info->size);
- if (nbd_read(ioc, flags, sizeof(*flags), errp) < 0) {
+ if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) {
error_prepend(errp, "Failed to read export flags");
goto fail;
}
- be16_to_cpus(flags);
+ be16_to_cpus(&info->flags);
} else if (magic == NBD_CLIENT_MAGIC) {
uint32_t oldflags;
@@ -555,11 +744,11 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
goto fail;
}
- if (nbd_read(ioc, &s, sizeof(s), errp) < 0) {
+ if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) {
error_prepend(errp, "Failed to read export length");
goto fail;
}
- *size = be64_to_cpu(s);
+ be64_to_cpus(&info->size);
if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) {
error_prepend(errp, "Failed to read export flags");
@@ -570,13 +759,13 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags);
goto fail;
}
- *flags = oldflags;
+ info->flags = oldflags;
} else {
error_setg(errp, "Bad magic received");
goto fail;
}
- trace_nbd_receive_negotiate_size_flags(*size, *flags);
+ trace_nbd_receive_negotiate_size_flags(info->size, info->flags);
if (zeroes && nbd_drop(ioc, 124, errp) < 0) {
error_prepend(errp, "Failed to read reserved block");
goto fail;
@@ -588,13 +777,19 @@ fail:
}
#ifdef __linux__
-int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size,
+int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
Error **errp)
{
- unsigned long sectors = size / BDRV_SECTOR_SIZE;
- if (size / BDRV_SECTOR_SIZE != sectors) {
- error_setg(errp, "Export size %lld too large for 32-bit kernel",
- (long long) size);
+ unsigned long sector_size = MAX(BDRV_SECTOR_SIZE, info->min_block);
+ unsigned long sectors = info->size / sector_size;
+
+ /* FIXME: Once the kernel module is patched to honor block sizes,
+ * and to advertise that fact to user space, we should update the
+ * hand-off to the kernel to use any block sizes we learned. */
+ assert(!info->request_sizes);
+ if (info->size / sector_size != sectors) {
+ error_setg(errp, "Export size %" PRIu64 " too large for 32-bit kernel",
+ info->size);
return -E2BIG;
}
@@ -606,17 +801,17 @@ int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size,
return -serrno;
}
- trace_nbd_init_set_block_size(BDRV_SECTOR_SIZE);
+ trace_nbd_init_set_block_size(sector_size);
- if (ioctl(fd, NBD_SET_BLKSIZE, (unsigned long)BDRV_SECTOR_SIZE) < 0) {
+ if (ioctl(fd, NBD_SET_BLKSIZE, sector_size) < 0) {
int serrno = errno;
error_setg(errp, "Failed setting NBD block size");
return -serrno;
}
trace_nbd_init_set_size(sectors);
- if (size % BDRV_SECTOR_SIZE) {
- trace_nbd_init_trailing_bytes(size % BDRV_SECTOR_SIZE);
+ if (info->size % sector_size) {
+ trace_nbd_init_trailing_bytes(info->size % sector_size);
}
if (ioctl(fd, NBD_SET_SIZE_BLOCKS, sectors) < 0) {
@@ -625,9 +820,9 @@ int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size,
return -serrno;
}
- if (ioctl(fd, NBD_SET_FLAGS, (unsigned long) flags) < 0) {
+ if (ioctl(fd, NBD_SET_FLAGS, (unsigned long) info->flags) < 0) {
if (errno == ENOTTY) {
- int read_only = (flags & NBD_FLAG_READ_ONLY) != 0;
+ int read_only = (info->flags & NBD_FLAG_READ_ONLY) != 0;
trace_nbd_init_set_readonly();
if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
@@ -685,7 +880,7 @@ int nbd_disconnect(int fd)
}
#else
-int nbd_init(int fd, QIOChannelSocket *ioc, uint16_t flags, off_t size,
+int nbd_init(int fd, QIOChannelSocket *ioc, NBDExportInfo *info,
Error **errp)
{
error_setg(errp, "nbd_init is only supported on Linux");
diff --git a/nbd/common.c b/nbd/common.c
index 4dab41e2c0..a2f28f2eec 100644
--- a/nbd/common.c
+++ b/nbd/common.c
@@ -101,3 +101,95 @@ void nbd_tls_handshake(QIOTask *task,
data->complete = true;
g_main_loop_quit(data->loop);
}
+
+
+const char *nbd_opt_lookup(uint32_t opt)
+{
+ switch (opt) {
+ case NBD_OPT_EXPORT_NAME:
+ return "export name";
+ case NBD_OPT_ABORT:
+ return "abort";
+ case NBD_OPT_LIST:
+ return "list";
+ case NBD_OPT_STARTTLS:
+ return "starttls";
+ case NBD_OPT_INFO:
+ return "info";
+ case NBD_OPT_GO:
+ return "go";
+ case NBD_OPT_STRUCTURED_REPLY:
+ return "structured reply";
+ default:
+ return "<unknown>";
+ }
+}
+
+
+const char *nbd_rep_lookup(uint32_t rep)
+{
+ switch (rep) {
+ case NBD_REP_ACK:
+ return "ack";
+ case NBD_REP_SERVER:
+ return "server";
+ case NBD_REP_INFO:
+ return "info";
+ case NBD_REP_ERR_UNSUP:
+ return "unsupported";
+ case NBD_REP_ERR_POLICY:
+ return "denied by policy";
+ case NBD_REP_ERR_INVALID:
+ return "invalid";
+ case NBD_REP_ERR_PLATFORM:
+ return "platform lacks support";
+ case NBD_REP_ERR_TLS_REQD:
+ return "TLS required";
+ case NBD_REP_ERR_UNKNOWN:
+ return "export unknown";
+ case NBD_REP_ERR_SHUTDOWN:
+ return "server shutting down";
+ case NBD_REP_ERR_BLOCK_SIZE_REQD:
+ return "block size required";
+ default:
+ return "<unknown>";
+ }
+}
+
+
+const char *nbd_info_lookup(uint16_t info)
+{
+ switch (info) {
+ case NBD_INFO_EXPORT:
+ return "export";
+ case NBD_INFO_NAME:
+ return "name";
+ case NBD_INFO_DESCRIPTION:
+ return "description";
+ case NBD_INFO_BLOCK_SIZE:
+ return "block size";
+ default:
+ return "<unknown>";
+ }
+}
+
+
+const char *nbd_cmd_lookup(uint16_t cmd)
+{
+ switch (cmd) {
+ case NBD_CMD_READ:
+ return "read";
+ case NBD_CMD_WRITE:
+ return "write";
+ case NBD_CMD_DISC:
+ return "discard";
+ case NBD_CMD_FLUSH:
+ return "flush";
+ case NBD_CMD_TRIM:
+ return "trim";
+ case NBD_CMD_WRITE_ZEROES:
+ return "write zeroes";
+ default:
+ return "<unknown>";
+ }
+}
diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
index cf6ecbf358..4065bc68ac 100644
--- a/nbd/nbd-internal.h
+++ b/nbd/nbd-internal.h
@@ -37,8 +37,11 @@
* https://github.com/yoe/nbd/blob/master/doc/proto.md
*/
+/* Size of all NBD_OPT_*, without payload */
#define NBD_REQUEST_SIZE (4 + 2 + 2 + 8 + 8 + 4)
+/* Size of all NBD_REP_* sent in answer to most NBD_OPT_*, without payload */
#define NBD_REPLY_SIZE (4 + 4 + 8)
+
#define NBD_REQUEST_MAGIC 0x25609513
#define NBD_REPLY_MAGIC 0x67446698
#define NBD_OPTS_MAGIC 0x49484156454F5054LL
@@ -57,12 +60,6 @@
#define NBD_SET_TIMEOUT _IO(0xab, 9)
#define NBD_SET_FLAGS _IO(0xab, 10)
-#define NBD_OPT_EXPORT_NAME (1)
-#define NBD_OPT_ABORT (2)
-#define NBD_OPT_LIST (3)
-#define NBD_OPT_PEEK_EXPORT (4)
-#define NBD_OPT_STARTTLS (5)
-
/* NBD errors are based on errno numbers, so there is a 1:1 mapping,
* but only a limited set of errno values is specified in the protocol.
* Everything else is squashed to EINVAL.
@@ -133,6 +130,10 @@ struct NBDTLSHandshakeData {
void nbd_tls_handshake(QIOTask *task,
void *opaque);
+const char *nbd_opt_lookup(uint32_t opt);
+const char *nbd_rep_lookup(uint32_t rep);
+const char *nbd_info_lookup(uint16_t info);
+const char *nbd_cmd_lookup(uint16_t info);
int nbd_drop(QIOChannel *ioc, size_t size, Error **errp);
diff --git a/nbd/server.c b/nbd/server.c
index 9b0c588146..49ed57455c 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Red Hat, Inc.
+ * Copyright (C) 2016-2017 Red Hat, Inc.
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device Server Side
@@ -84,7 +84,6 @@ struct NBDClient {
int refcount;
void (*close_fn)(NBDClient *client, bool negotiated);
- bool no_zeroes;
NBDExport *exp;
QCryptoTLSCreds *tlscreds;
char *tlsaclname;
@@ -139,8 +138,10 @@ static int nbd_negotiate_send_rep_len(QIOChannel *ioc, uint32_t type,
{
uint64_t magic;
- trace_nbd_negotiate_send_rep_len(opt, type, len);
+ trace_nbd_negotiate_send_rep_len(opt, nbd_opt_lookup(opt),
+ type, nbd_rep_lookup(type), len);
+ assert(len < NBD_MAX_BUFFER_SIZE);
magic = cpu_to_be64(NBD_REP_MAGIC);
if (nbd_write(ioc, &magic, sizeof(magic), errp) < 0) {
error_prepend(errp, "write failed (rep magic): ");
@@ -275,10 +276,16 @@ static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length,
return nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, NBD_OPT_LIST, errp);
}
+/* Send a reply to NBD_OPT_EXPORT_NAME.
+ * Return -errno on error, 0 on success. */
static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length,
+ uint16_t myflags, bool no_zeroes,
Error **errp)
{
char name[NBD_MAX_NAME_SIZE + 1];
+ char buf[8 + 4 + 124] = "";
+ size_t len;
+ int ret;
/* Client sends:
[20 .. xx] export name (length bytes)
@@ -302,12 +309,219 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length,
return -EINVAL;
}
+ trace_nbd_negotiate_new_style_size_flags(client->exp->size,
+ client->exp->nbdflags | myflags);
+ stq_be_p(buf, client->exp->size);
+ stw_be_p(buf + 8, client->exp->nbdflags | myflags);
+ len = no_zeroes ? 10 : sizeof(buf);
+ ret = nbd_write(client->ioc, buf, len, errp);
+ if (ret < 0) {
+ error_prepend(errp, "write failed: ");
+ return ret;
+ }
+
QTAILQ_INSERT_TAIL(&client->exp->clients, client, next);
nbd_export_get(client->exp);
return 0;
}
+/* Send a single NBD_REP_INFO, with a buffer @buf of @length bytes.
+ * The buffer does NOT include the info type prefix.
+ * Return -errno on error, 0 if ready to send more. */
+static int nbd_negotiate_send_info(NBDClient *client, uint32_t opt,
+ uint16_t info, uint32_t length, void *buf,
+ Error **errp)
+{
+ int rc;
+
+ trace_nbd_negotiate_send_info(info, nbd_info_lookup(info), length);
+ rc = nbd_negotiate_send_rep_len(client->ioc, NBD_REP_INFO, opt,
+ sizeof(info) + length, errp);
+ if (rc < 0) {
+ return rc;
+ }
+ cpu_to_be16s(&info);
+ if (nbd_write(client->ioc, &info, sizeof(info), errp) < 0) {
+ return -EIO;
+ }
+ if (nbd_write(client->ioc, buf, length, errp) < 0) {
+ return -EIO;
+ }
+ return 0;
+}
+
+/* Handle NBD_OPT_INFO and NBD_OPT_GO.
+ * Return -errno on error, 0 if ready for next option, and 1 to move
+ * into transmission phase. */
+static int nbd_negotiate_handle_info(NBDClient *client, uint32_t length,
+ uint32_t opt, uint16_t myflags,
+ Error **errp)
+{
+ int rc;
+ char name[NBD_MAX_NAME_SIZE + 1];
+ NBDExport *exp;
+ uint16_t requests;
+ uint16_t request;
+ uint32_t namelen;
+ bool sendname = false;
+ bool blocksize = false;
+ uint32_t sizes[3];
+ char buf[sizeof(uint64_t) + sizeof(uint16_t)];
+ const char *msg;
+
+ /* Client sends:
+ 4 bytes: L, name length (can be 0)
+ L bytes: export name
+ 2 bytes: N, number of requests (can be 0)
+ N * 2 bytes: N requests
+ */
+ if (length < sizeof(namelen) + sizeof(requests)) {
+ msg = "overall request too short";
+ goto invalid;
+ }
+ if (nbd_read(client->ioc, &namelen, sizeof(namelen), errp) < 0) {
+ return -EIO;
+ }
+ be32_to_cpus(&namelen);
+ length -= sizeof(namelen);
+ if (namelen > length - sizeof(requests) || (length - namelen) % 2) {
+ msg = "name length is incorrect";
+ goto invalid;
+ }
+ if (nbd_read(client->ioc, name, namelen, errp) < 0) {
+ return -EIO;
+ }
+ name[namelen] = '\0';
+ length -= namelen;
+ trace_nbd_negotiate_handle_export_name_request(name);
+
+ if (nbd_read(client->ioc, &requests, sizeof(requests), errp) < 0) {
+ return -EIO;
+ }
+ be16_to_cpus(&requests);
+ length -= sizeof(requests);
+ trace_nbd_negotiate_handle_info_requests(requests);
+ if (requests != length / sizeof(request)) {
+ msg = "incorrect number of requests for overall length";
+ goto invalid;
+ }
+ while (requests--) {
+ if (nbd_read(client->ioc, &request, sizeof(request), errp) < 0) {
+ return -EIO;
+ }
+ be16_to_cpus(&request);
+ length -= sizeof(request);
+ trace_nbd_negotiate_handle_info_request(request,
+ nbd_info_lookup(request));
+ /* We care about NBD_INFO_NAME and NBD_INFO_BLOCK_SIZE;
+ * everything else is either a request we don't know or
+ * something we send regardless of request */
+ switch (request) {
+ case NBD_INFO_NAME:
+ sendname = true;
+ break;
+ case NBD_INFO_BLOCK_SIZE:
+ blocksize = true;
+ break;
+ }
+ }
+
+ exp = nbd_export_find(name);
+ if (!exp) {
+ return nbd_negotiate_send_rep_err(client->ioc, NBD_REP_ERR_UNKNOWN,
+ opt, errp, "export '%s' not present",
+ name);
+ }
+
+ /* Don't bother sending NBD_INFO_NAME unless client requested it */
+ if (sendname) {
+ rc = nbd_negotiate_send_info(client, opt, NBD_INFO_NAME, length, name,
+ errp);
+ if (rc < 0) {
+ return rc;
+ }
+ }
+
+ /* Send NBD_INFO_DESCRIPTION only if available, regardless of
+ * client request */
+ if (exp->description) {
+ size_t len = strlen(exp->description);
+
+ rc = nbd_negotiate_send_info(client, opt, NBD_INFO_DESCRIPTION,
+ len, exp->description, errp);
+ if (rc < 0) {
+ return rc;
+ }
+ }
+
+ /* Send NBD_INFO_BLOCK_SIZE always, but tweak the minimum size
+ * according to whether the client requested it, and according to
+ * whether this is OPT_INFO or OPT_GO. */
+ /* minimum - 1 for back-compat, or 512 if client is new enough.
+ * TODO: consult blk_bs(blk)->bl.request_alignment? */
+ sizes[0] = (opt == NBD_OPT_INFO || blocksize) ? BDRV_SECTOR_SIZE : 1;
+ /* preferred - Hard-code to 4096 for now.
+ * TODO: is blk_bs(blk)->bl.opt_transfer appropriate? */
+ sizes[1] = 4096;
+ /* maximum - At most 32M, but smaller as appropriate. */
+ sizes[2] = MIN(blk_get_max_transfer(exp->blk), NBD_MAX_BUFFER_SIZE);
+ trace_nbd_negotiate_handle_info_block_size(sizes[0], sizes[1], sizes[2]);
+ cpu_to_be32s(&sizes[0]);
+ cpu_to_be32s(&sizes[1]);
+ cpu_to_be32s(&sizes[2]);
+ rc = nbd_negotiate_send_info(client, opt, NBD_INFO_BLOCK_SIZE,
+ sizeof(sizes), sizes, errp);
+ if (rc < 0) {
+ return rc;
+ }
+
+ /* Send NBD_INFO_EXPORT always */
+ trace_nbd_negotiate_new_style_size_flags(exp->size,
+ exp->nbdflags | myflags);
+ stq_be_p(buf, exp->size);
+ stw_be_p(buf + 8, exp->nbdflags | myflags);
+ rc = nbd_negotiate_send_info(client, opt, NBD_INFO_EXPORT,
+ sizeof(buf), buf, errp);
+ if (rc < 0) {
+ return rc;
+ }
+
+ /* If the client is just asking for NBD_OPT_INFO, but forgot to
+ * request block sizes, return an error.
+ * TODO: consult blk_bs(blk)->request_align, and only error if it
+ * is not 1? */
+ if (opt == NBD_OPT_INFO && !blocksize) {
+ return nbd_negotiate_send_rep_err(client->ioc,
+ NBD_REP_ERR_BLOCK_SIZE_REQD, opt,
+ errp,
+ "request NBD_INFO_BLOCK_SIZE to "
+ "use this export");
+ }
+
+ /* Final reply */
+ rc = nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, opt, errp);
+ if (rc < 0) {
+ return rc;
+ }
+
+ if (opt == NBD_OPT_GO) {
+ client->exp = exp;
+ QTAILQ_INSERT_TAIL(&client->exp->clients, client, next);
+ nbd_export_get(client->exp);
+ rc = 1;
+ }
+ return rc;
+
+ invalid:
+ if (nbd_drop(client->ioc, length, errp) < 0) {
+ return -EIO;
+ }
+ return nbd_negotiate_send_rep_err(client->ioc, NBD_REP_ERR_INVALID, opt,
+ errp, "%s", msg);
+}
+
+
/* Handle NBD_OPT_STARTTLS. Return NULL to drop connection, or else the
* new channel for all further (now-encrypted) communication. */
static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
@@ -365,22 +579,25 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
}
/* nbd_negotiate_options
- * Process all NBD_OPT_* client option commands.
+ * Process all NBD_OPT_* client option commands, during fixed newstyle
+ * negotiation.
* Return:
* -errno on error, errp is set
* 0 on successful negotiation, errp is not set
* 1 if client sent NBD_OPT_ABORT, i.e. on valid disconnect,
* errp is not set
*/
-static int nbd_negotiate_options(NBDClient *client, Error **errp)
+static int nbd_negotiate_options(NBDClient *client, uint16_t myflags,
+ Error **errp)
{
uint32_t flags;
bool fixedNewstyle = false;
- Error *local_err = NULL;
+ bool no_zeroes = false;
/* Client sends:
[ 0 .. 3] client flags
+ Then we loop until NBD_OPT_EXPORT_NAME or NBD_OPT_GO:
[ 0 .. 7] NBD_OPTS_MAGIC
[ 8 .. 11] NBD option
[12 .. 15] Data length
@@ -396,21 +613,19 @@ static int nbd_negotiate_options(NBDClient *client, Error **errp)
error_prepend(errp, "read failed: ");
return -EIO;
}
- trace_nbd_negotiate_options_flags();
be32_to_cpus(&flags);
+ trace_nbd_negotiate_options_flags(flags);
if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) {
- trace_nbd_negotiate_options_newstyle();
fixedNewstyle = true;
flags &= ~NBD_FLAG_C_FIXED_NEWSTYLE;
}
if (flags & NBD_FLAG_C_NO_ZEROES) {
- trace_nbd_negotiate_options_no_zeroes();
- client->no_zeroes = true;
+ no_zeroes = true;
flags &= ~NBD_FLAG_C_NO_ZEROES;
}
if (flags != 0) {
error_setg(errp, "Unknown client flags 0x%" PRIx32 " received", flags);
- return -EIO;
+ return -EINVAL;
}
while (1) {
@@ -442,7 +657,8 @@ static int nbd_negotiate_options(NBDClient *client, Error **errp)
}
length = be32_to_cpu(length);
- trace_nbd_negotiate_options_check_option(option);
+ trace_nbd_negotiate_options_check_option(option,
+ nbd_opt_lookup(option));
if (client->tlscreds &&
client->ioc == (QIOChannel *)client->sioc) {
QIOChannel *tioc;
@@ -479,7 +695,9 @@ static int nbd_negotiate_options(NBDClient *client, Error **errp)
if (ret < 0) {
return ret;
}
- /* Let the client keep trying, unless they asked to quit */
+ /* Let the client keep trying, unless they asked to
+ * quit. In this mode, we've already sent an error, so
+ * we can't ack the abort. */
if (option == NBD_OPT_ABORT) {
return 1;
}
@@ -498,19 +716,26 @@ static int nbd_negotiate_options(NBDClient *client, Error **errp)
/* NBD spec says we must try to reply before
* disconnecting, but that we must also tolerate
* guests that don't wait for our reply. */
- nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, option,
- &local_err);
-
- if (local_err != NULL) {
- const char *error = error_get_pretty(local_err);
- trace_nbd_opt_abort_reply_failed(error);
- error_free(local_err);
- }
-
+ nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, option, NULL);
return 1;
case NBD_OPT_EXPORT_NAME:
- return nbd_negotiate_handle_export_name(client, length, errp);
+ return nbd_negotiate_handle_export_name(client, length,
+ myflags, no_zeroes,
+ errp);
+
+ case NBD_OPT_INFO:
+ case NBD_OPT_GO:
+ ret = nbd_negotiate_handle_info(client, length, option,
+ myflags, errp);
+ if (ret == 1) {
+ assert(option == NBD_OPT_GO);
+ return 0;
+ }
+ if (ret) {
+ return ret;
+ }
+ break;
case NBD_OPT_STARTTLS:
if (nbd_drop(client->ioc, length, errp) < 0) {
@@ -539,8 +764,8 @@ static int nbd_negotiate_options(NBDClient *client, Error **errp)
NBD_REP_ERR_UNSUP,
option, errp,
"Unsupported option 0x%"
- PRIx32,
- option);
+ PRIx32 " (%s)", option,
+ nbd_opt_lookup(option));
if (ret < 0) {
return ret;
}
@@ -553,10 +778,13 @@ static int nbd_negotiate_options(NBDClient *client, Error **errp)
*/
switch (option) {
case NBD_OPT_EXPORT_NAME:
- return nbd_negotiate_handle_export_name(client, length, errp);
+ return nbd_negotiate_handle_export_name(client, length,
+ myflags, no_zeroes,
+ errp);
default:
- error_setg(errp, "Unsupported option 0x%" PRIx32, option);
+ error_setg(errp, "Unsupported option 0x%" PRIx32 " (%s)",
+ option, nbd_opt_lookup(option));
return -EINVAL;
}
}
@@ -578,7 +806,6 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp)
NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA |
NBD_FLAG_SEND_WRITE_ZEROES);
bool oldStyle;
- size_t len;
/* Old style negotiation header without options
[ 0 .. 7] passwd ("NBDMAGIC")
@@ -592,10 +819,7 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp)
[ 0 .. 7] passwd ("NBDMAGIC")
[ 8 .. 15] magic (NBD_OPTS_MAGIC)
[16 .. 17] server flags (0)
- ....options sent....
- [18 .. 25] size
- [26 .. 27] export flags
- [28 .. 151] reserved (0, omit if no_zeroes)
+ ....options sent, ending in NBD_OPT_EXPORT_NAME or NBD_OPT_GO....
*/
qio_channel_set_blocking(client->ioc, false, NULL);
@@ -624,24 +848,13 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp)
error_prepend(errp, "write failed: ");
return -EINVAL;
}
- ret = nbd_negotiate_options(client, errp);
+ ret = nbd_negotiate_options(client, myflags, errp);
if (ret != 0) {
if (ret < 0) {
error_prepend(errp, "option negotiation failed: ");
}
return ret;
}
-
- trace_nbd_negotiate_new_style_size_flags(
- client->exp->size, client->exp->nbdflags | myflags);
- stq_be_p(buf + 18, client->exp->size);
- stw_be_p(buf + 26, client->exp->nbdflags | myflags);
- len = client->no_zeroes ? 10 : sizeof(buf) - 18;
- ret = nbd_write(client->ioc, buf + 18, len, errp);
- if (ret < 0) {
- error_prepend(errp, "write failed: ");
- return ret;
- }
}
trace_nbd_negotiate_success();
@@ -1040,7 +1253,8 @@ static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request,
return -EIO;
}
- trace_nbd_co_receive_request_decode_type(request->handle, request->type);
+ trace_nbd_co_receive_request_decode_type(request->handle, request->type,
+ nbd_cmd_lookup(request->type));
if (request->type != NBD_CMD_WRITE) {
/* No payload, we are ready to read the next request. */
diff --git a/nbd/trace-events b/nbd/trace-events
index 4b233b8510..f5024d85a1 100644
--- a/nbd/trace-events
+++ b/nbd/trace-events
@@ -1,8 +1,12 @@
# nbd/client.c
nbd_unknown_error(int err) "Squashing unexpected error %d to EINVAL"
-nbd_send_option_request(uint32_t opt, uint32_t len) "Sending option request %" PRIu32", len %" PRIu32
-nbd_receive_option_reply(uint32_t option, uint32_t type, uint32_t length) "Received option reply %" PRIx32", type %" PRIx32", len %" PRIu32
-nbd_reply_err_unsup(uint32_t option) "server doesn't understand request %" PRIx32 ", attempting fallback"
+nbd_send_option_request(uint32_t opt, const char *name, uint32_t len) "Sending option request %" PRIu32" (%s), len %" PRIu32
+nbd_receive_option_reply(uint32_t option, const char *optname, uint32_t type, const char *typename, uint32_t length) "Received option reply %" PRIx32" (%s), type %" PRIx32" (%s), len %" PRIu32
+nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't understand request %" PRIx32 " (%s), attempting fallback"
+nbd_opt_go_start(const char *name) "Attempting NBD_OPT_GO for export '%s'"
+nbd_opt_go_success(void) "Export is good to go"
+nbd_opt_go_info_unknown(int info, const char *name) "Ignoring unknown info %d (%s)"
+nbd_opt_go_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t maximum) "Block sizes are 0x%" PRIx32 ", 0x%" PRIx32 ", 0x%" PRIx32
nbd_receive_query_exports_start(const char *wantname) "Querying export list for '%s'"
nbd_receive_query_exports_success(const char *wantname) "Found desired export name '%s'"
nbd_receive_starttls_request(void) "Requesting TLS from server"
@@ -28,19 +32,20 @@ nbd_send_request(uint64_t from, uint32_t len, uint64_t handle, uint16_t flags, u
nbd_receive_reply(uint32_t magic, int32_t error, uint64_t handle) "Got reply: { magic = 0x%" PRIx32 ", .error = % " PRId32 ", handle = %" PRIu64" }"
# nbd/server.c
-nbd_negotiate_send_rep_len(uint32_t opt, uint32_t type, uint32_t len) "Reply opt=%" PRIx32 " type=%" PRIx32 " len=%" PRIu32
+nbd_negotiate_send_rep_len(uint32_t opt, const char *optname, uint32_t type, const char *typename, uint32_t len) "Reply opt=%" PRIx32 " (%s), type=%" PRIx32 " (%s), len=%" PRIu32
nbd_negotiate_send_rep_err(const char *msg) "sending error message \"%s\""
nbd_negotiate_send_rep_list(const char *name, const char *desc) "Advertising export name '%s' description '%s'"
nbd_negotiate_handle_export_name(void) "Checking length"
nbd_negotiate_handle_export_name_request(const char *name) "Client requested export '%s'"
+nbd_negotiate_send_info(int info, const char *name, uint32_t length) "Sending NBD_REP_INFO type %d (%s) with remaining length %" PRIu32
+nbd_negotiate_handle_info_requests(int requests) "Client requested %d items of info"
+nbd_negotiate_handle_info_request(int request, const char *name) "Client requested info %d (%s)"
+nbd_negotiate_handle_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t maximum) "advertising minimum 0x%" PRIx32 ", preferred 0x%" PRIx32 ", maximum 0x%" PRIx32
nbd_negotiate_handle_starttls(void) "Setting up TLS"
nbd_negotiate_handle_starttls_handshake(void) "Starting TLS handshake"
-nbd_negotiate_options_flags(void) "Checking client flags"
-nbd_negotiate_options_newstyle(void) "Client supports fixed newstyle handshake"
-nbd_negotiate_options_no_zeroes(void) "Client supports no zeroes at handshake end"
+nbd_negotiate_options_flags(uint32_t flags) "Received client flags 0x%" PRIx32
nbd_negotiate_options_check_magic(uint64_t magic) "Checking opts magic 0x%" PRIx64
-nbd_negotiate_options_check_option(uint32_t option) "Checking option 0x%" PRIx32
-nbd_opt_abort_reply_failed(const char *error) "Reply to NBD_OPT_ABORT request failed: %s"
+nbd_negotiate_options_check_option(uint32_t option, const char *name) "Checking option 0x%" PRIx32 " (%s)"
nbd_negotiate_begin(void) "Beginning negotiation"
nbd_negotiate_old_style(uint64_t size, unsigned flags) "advertising size %" PRIu64 " and flags %x"
nbd_negotiate_new_style_size_flags(uint64_t size, unsigned flags) "advertising size %" PRIu64 " and flags %x"
@@ -50,7 +55,7 @@ nbd_send_reply(int32_t error, uint64_t handle) "Sending response to client: { .e
nbd_blk_aio_attached(const char *name, void *ctx) "Export %s: Attaching clients to AIO context %p\n"
nbd_blk_aio_detach(const char *name, void *ctx) "Export %s: Detaching clients from AIO context %p\n"
nbd_co_send_reply(uint64_t handle, uint32_t error, int len) "Send reply: handle = %" PRIu64 ", error = %" PRIu32 ", len = %d"
-nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type) "Decoding type: handle = %" PRIu64 ", type = %" PRIu16
+nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const char *name) "Decoding type: handle = %" PRIu64 ", type = %" PRIu16 " (%s)"
nbd_co_receive_request_payload_received(uint64_t handle, uint32_t len) "Payload received: handle = %" PRIu64 ", len = %" PRIu32
nbd_co_receive_request_cmd_write(uint32_t len) "Reading %" PRIu32 " byte(s)"
nbd_trip(void) "Reading request"
diff --git a/net/colo-compare.c b/net/colo-compare.c
index 6d500e1dc4..abfc23ce80 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -543,7 +543,7 @@ static void compare_pri_chr_in(void *opaque, const uint8_t *buf, int size)
ret = net_fill_rstate(&s->pri_rs, buf, size);
if (ret == -1) {
- qemu_chr_fe_set_handlers(&s->chr_pri_in, NULL, NULL, NULL,
+ qemu_chr_fe_set_handlers(&s->chr_pri_in, NULL, NULL, NULL, NULL,
NULL, NULL, true);
error_report("colo-compare primary_in error");
}
@@ -560,7 +560,7 @@ static void compare_sec_chr_in(void *opaque, const uint8_t *buf, int size)
ret = net_fill_rstate(&s->sec_rs, buf, size);
if (ret == -1) {
- qemu_chr_fe_set_handlers(&s->chr_sec_in, NULL, NULL, NULL,
+ qemu_chr_fe_set_handlers(&s->chr_sec_in, NULL, NULL, NULL, NULL,
NULL, NULL, true);
error_report("colo-compare secondary_in error");
}
@@ -588,9 +588,11 @@ static void *colo_compare_thread(void *opaque)
s->worker_context = g_main_context_new();
qemu_chr_fe_set_handlers(&s->chr_pri_in, compare_chr_can_read,
- compare_pri_chr_in, NULL, s, s->worker_context, true);
+ compare_pri_chr_in, NULL, NULL,
+ s, s->worker_context, true);
qemu_chr_fe_set_handlers(&s->chr_sec_in, compare_chr_can_read,
- compare_sec_chr_in, NULL, s, s->worker_context, true);
+ compare_sec_chr_in, NULL, NULL,
+ s, s->worker_context, true);
s->compare_loop = g_main_loop_new(s->worker_context, FALSE);
diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index 52d978fce2..6043549e5f 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -112,7 +112,7 @@ static void redirector_chr_read(void *opaque, const uint8_t *buf, int size)
if (ret == -1) {
qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL,
- NULL, NULL, true);
+ NULL, NULL, NULL, true);
}
}
@@ -124,7 +124,7 @@ static void redirector_chr_event(void *opaque, int event)
switch (event) {
case CHR_EVENT_CLOSED:
qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL,
- NULL, NULL, true);
+ NULL, NULL, NULL, true);
break;
default:
break;
@@ -163,7 +163,7 @@ static ssize_t filter_redirector_receive_iov(NetFilterState *nf,
MirrorState *s = FILTER_REDIRECTOR(nf);
int ret;
- if (qemu_chr_fe_get_driver(&s->chr_out)) {
+ if (qemu_chr_fe_backend_connected(&s->chr_out)) {
ret = filter_send(&s->chr_out, iov, iovcnt);
if (ret) {
error_report("filter redirector send failed(%s)", strerror(-ret));
@@ -245,7 +245,7 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp)
qemu_chr_fe_set_handlers(&s->chr_in, redirector_chr_can_read,
redirector_chr_read, redirector_chr_event,
- nf, NULL, true);
+ NULL, nf, NULL, true);
}
if (s->outdev) {
diff --git a/net/slirp.c b/net/slirp.c
index 6a6d727999..9fbc949e81 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -778,7 +778,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
fwd->slirp = s->slirp;
qemu_chr_fe_set_handlers(&fwd->hd, guestfwd_can_read, guestfwd_read,
- NULL, fwd, NULL, true);
+ NULL, NULL, fwd, NULL, true);
}
return 0;
diff --git a/net/tap-linux.c b/net/tap-linux.c
index a503fa9c6e..535b1ddb61 100644
--- a/net/tap-linux.c
+++ b/net/tap-linux.c
@@ -55,7 +55,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
if (ioctl(fd, TUNGETFEATURES, &features) == -1) {
- error_report("warning: TUNGETFEATURES failed: %s", strerror(errno));
+ warn_report("TUNGETFEATURES failed: %s", strerror(errno));
features = 0;
}
diff --git a/net/vhost-user.c b/net/vhost-user.c
index a042ec6a34..36f32a2d84 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -211,7 +211,7 @@ static void chr_closed_bh(void *opaque)
vhost_user_stop(queues, ncs);
qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event,
- opaque, NULL, true);
+ NULL, opaque, NULL, true);
if (err) {
error_report_err(err);
@@ -257,7 +257,7 @@ static void net_vhost_user_event(void *opaque, int event)
g_source_remove(s->watch);
s->watch = 0;
- qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL,
+ qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL,
NULL, NULL, false);
aio_bh_schedule_oneshot(ctx, chr_closed_bh, opaque);
@@ -305,7 +305,8 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
return -1;
}
qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
- net_vhost_user_event, nc0->name, NULL, true);
+ net_vhost_user_event, NULL, nc0->name, NULL,
+ true);
} while (!s->started);
assert(s->vhost_net);
diff --git a/numa.c b/numa.c
index b0e75f6268..e32af04cd2 100644
--- a/numa.c
+++ b/numa.c
@@ -542,14 +542,14 @@ static void allocate_system_memory_nonnuma(MemoryRegion *mr, Object *owner,
/* Legacy behavior: if allocation failed, fall back to
* regular RAM allocation.
*/
- memory_region_init_ram(mr, owner, name, ram_size, &error_fatal);
+ memory_region_init_ram_nomigrate(mr, owner, name, ram_size, &error_fatal);
}
#else
fprintf(stderr, "-mem-path not supported on this host\n");
exit(1);
#endif
} else {
- memory_region_init_ram(mr, owner, name, ram_size, &error_fatal);
+ memory_region_init_ram_nomigrate(mr, owner, name, ram_size, &error_fatal);
}
vmstate_register_ram_global(mr);
}
diff --git a/pc-bios/efi-e1000.rom b/pc-bios/efi-e1000.rom
index 675992428d..4da9de33da 100644
--- a/pc-bios/efi-e1000.rom
+++ b/pc-bios/efi-e1000.rom
Binary files differ
diff --git a/pc-bios/efi-e1000e.rom b/pc-bios/efi-e1000e.rom
index 145896c219..c2474a8fab 100644
--- a/pc-bios/efi-e1000e.rom
+++ b/pc-bios/efi-e1000e.rom
Binary files differ
diff --git a/pc-bios/efi-eepro100.rom b/pc-bios/efi-eepro100.rom
index ff2793f974..7950faf7cd 100644
--- a/pc-bios/efi-eepro100.rom
+++ b/pc-bios/efi-eepro100.rom
Binary files differ
diff --git a/pc-bios/efi-ne2k_pci.rom b/pc-bios/efi-ne2k_pci.rom
index c832ec017e..30edb1392a 100644
--- a/pc-bios/efi-ne2k_pci.rom
+++ b/pc-bios/efi-ne2k_pci.rom
Binary files differ
diff --git a/pc-bios/efi-pcnet.rom b/pc-bios/efi-pcnet.rom
index 4d803d30bc..23057c5724 100644
--- a/pc-bios/efi-pcnet.rom
+++ b/pc-bios/efi-pcnet.rom
Binary files differ
diff --git a/pc-bios/efi-rtl8139.rom b/pc-bios/efi-rtl8139.rom
index 83488cd54b..beb9301839 100644
--- a/pc-bios/efi-rtl8139.rom
+++ b/pc-bios/efi-rtl8139.rom
Binary files differ
diff --git a/pc-bios/efi-virtio.rom b/pc-bios/efi-virtio.rom
index 3563776dbd..f4de5957ec 100644
--- a/pc-bios/efi-virtio.rom
+++ b/pc-bios/efi-virtio.rom
Binary files differ
diff --git a/pc-bios/efi-vmxnet3.rom b/pc-bios/efi-vmxnet3.rom
index e22275253b..7501477ea6 100644
--- a/pc-bios/efi-vmxnet3.rom
+++ b/pc-bios/efi-vmxnet3.rom
Binary files differ
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index a4d9b2ca23..ad5b590ff9 100644
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32
index 767e0af5b2..da824ad726 100644
--- a/pc-bios/openbios-sparc32
+++ b/pc-bios/openbios-sparc32
Binary files differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
index 0c1048a83b..daabb83d21 100644
--- a/pc-bios/openbios-sparc64
+++ b/pc-bios/openbios-sparc64
Binary files differ
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index 5ad0564000..0a08c3936a 100644
--- a/pc-bios/s390-ccw.img
+++ b/pc-bios/s390-ccw.img
Binary files differ
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index fb88c13bc7..cbae74522a 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,14 +9,14 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
.PHONY : all clean build-all
-OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o
+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o virtio-blkdev.o
QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
QEMU_CFLAGS += $(call cc-option, $(QEMU_CFLAGS), -fno-stack-protector)
LDFLAGS += -Wl,-pie -nostdlib
-build-all: s390-ccw.img
+build-all: s390-ccw.img s390-netboot.img
s390-ccw.elf: $(OBJECTS)
$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS),"BUILD","$(TARGET_DIR)$@")
@@ -28,5 +28,12 @@ s390-ccw.img: s390-ccw.elf
$(OBJECTS): Makefile
+ifneq ($(wildcard $(SRC_PATH)/roms/SLOF/lib/libnet),)
+include $(SRC_PATH)/pc-bios/s390-ccw/netboot.mak
+else
+s390-netboot.img:
+ @echo "s390-netboot.img not built since roms/SLOF/ is not available."
+endif
+
clean:
- rm -f *.o *.d *.img *.elf *~
+ $(RM) *.o *.d *.img *.elf *~ *.a
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 523fa78c5f..67a6123ed4 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -8,9 +8,11 @@
* directory.
*/
+#include "libc.h"
#include "s390-ccw.h"
#include "bootmap.h"
#include "virtio.h"
+#include "bswap.h"
#ifdef DEBUG
/* #define DEBUG_FALLBACK */
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 7f367820f3..cf99a4c728 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -324,32 +324,6 @@ static inline int _memcmp(const void *s1, const void *s2, size_t n)
return 0;
}
-/* from include/qemu/bswap.h */
-
-/* El Torito is always little-endian */
-static inline uint16_t bswap16(uint16_t x)
-{
- return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
-}
-
-static inline uint32_t bswap32(uint32_t x)
-{
- return ((x & 0x000000ffU) << 24) | ((x & 0x0000ff00U) << 8) |
- ((x & 0x00ff0000U) >> 8) | ((x & 0xff000000U) >> 24);
-}
-
-static inline uint64_t bswap64(uint64_t x)
-{
- return ((x & 0x00000000000000ffULL) << 56) |
- ((x & 0x000000000000ff00ULL) << 40) |
- ((x & 0x0000000000ff0000ULL) << 24) |
- ((x & 0x00000000ff000000ULL) << 8) |
- ((x & 0x000000ff00000000ULL) >> 8) |
- ((x & 0x0000ff0000000000ULL) >> 24) |
- ((x & 0x00ff000000000000ULL) >> 40) |
- ((x & 0xff00000000000000ULL) >> 56);
-}
-
static inline uint32_t iso_733_to_u32(uint64_t x)
{
return (uint32_t)x;
diff --git a/pc-bios/s390-ccw/bswap.h b/pc-bios/s390-ccw/bswap.h
new file mode 100644
index 0000000000..a4226042bc
--- /dev/null
+++ b/pc-bios/s390-ccw/bswap.h
@@ -0,0 +1,30 @@
+/*
+ * Byte swap functions - taken from include/qemu/bswap.h
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+static inline uint16_t bswap16(uint16_t x)
+{
+ return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
+}
+
+static inline uint32_t bswap32(uint32_t x)
+{
+ return ((x & 0x000000ffU) << 24) | ((x & 0x0000ff00U) << 8) |
+ ((x & 0x00ff0000U) >> 8) | ((x & 0xff000000U) >> 24);
+}
+
+static inline uint64_t bswap64(uint64_t x)
+{
+ return ((x & 0x00000000000000ffULL) << 56) |
+ ((x & 0x000000000000ff00ULL) << 40) |
+ ((x & 0x0000000000ff0000ULL) << 24) |
+ ((x & 0x00000000ff000000ULL) << 8) |
+ ((x & 0x000000ff00000000ULL) >> 8) |
+ ((x & 0x0000ff0000000000ULL) >> 24) |
+ ((x & 0x00ff000000000000ULL) >> 40) |
+ ((x & 0xff00000000000000ULL) >> 56);
+}
diff --git a/pc-bios/s390-ccw/libc.h b/pc-bios/s390-ccw/libc.h
new file mode 100644
index 0000000000..0142ea8e7b
--- /dev/null
+++ b/pc-bios/s390-ccw/libc.h
@@ -0,0 +1,45 @@
+/*
+ * libc-style definitions and functions
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef S390_CCW_LIBC_H
+#define S390_CCW_LIBC_H
+
+typedef long size_t;
+typedef int bool;
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+static inline void *memset(void *s, int c, size_t n)
+{
+ int i;
+ unsigned char *p = s;
+
+ for (i = 0; i < n; i++) {
+ p[i] = c;
+ }
+
+ return s;
+}
+
+static inline void *memcpy(void *s1, const void *s2, size_t n)
+{
+ uint8_t *dest = s1;
+ const uint8_t *src = s2;
+ int i;
+
+ for (i = 0; i < n; i++) {
+ dest[i] = src[i];
+ }
+
+ return s1;
+}
+
+#endif
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 1cacc1b46f..401e9dbb5f 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -8,6 +8,7 @@
* directory.
*/
+#include "libc.h"
#include "s390-ccw.h"
#include "virtio.h"
@@ -16,17 +17,6 @@ static SubChannelId blk_schid = { .one = 1 };
IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-const unsigned char ebc2asc[256] =
- /* 0123456789abcdef0123456789abcdef */
- "................................" /* 1F */
- "................................" /* 3F */
- " ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */
- "-/.........,%_>?.........`:#@'=\""/* 7F */
- ".abcdefghi.......jklmnopqr......" /* 9F */
- "..stuvwxyz......................" /* BF */
- ".ABCDEFGHI.......JKLMNOPQR......" /* DF */
- "..STUVWXYZ......0123456789......";/* FF */
-
/*
* Priniciples of Operations (SA22-7832-09) chapter 17 requires that
* a subsystem-identification is at 184-187 and bytes 188-191 are zero
@@ -154,7 +144,7 @@ static void virtio_setup(void)
sclp_print("Network boot device detected\n");
vdev->netboot_start_addr = iplb.ccw.netboot_start_addr;
} else {
- virtio_setup_device(blk_schid);
+ virtio_blk_setup_device(blk_schid);
IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
}
diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak
new file mode 100644
index 0000000000..a9e1374e97
--- /dev/null
+++ b/pc-bios/s390-ccw/netboot.mak
@@ -0,0 +1,59 @@
+
+SLOF_DIR := $(SRC_PATH)/roms/SLOF
+
+NETOBJS := start.o sclp.o virtio.o virtio-net.o netmain.o libnet.a libc.a
+
+LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include
+LIBNET_INC := -I$(SLOF_DIR)/lib/libnet
+
+NETLDFLAGS := $(LDFLAGS) -Ttext=0x7800000
+
+$(NETOBJS): QEMU_CFLAGS += $(LIBC_INC) $(LIBNET_INC)
+
+s390-netboot.elf: $(NETOBJS)
+ $(call quiet-command,$(CC) $(NETLDFLAGS) -o $@ $(NETOBJS),"BUILD","$(TARGET_DIR)$@")
+
+s390-netboot.img: s390-netboot.elf
+ $(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@")
+
+# libc files:
+
+LIBC_CFLAGS := $(QEMU_CFLAGS) $(LIBC_INC) $(LIBNET_INC)
+
+CTYPE_OBJS = isdigit.o isxdigit.o toupper.o
+%.o : $(SLOF_DIR)/lib/libc/ctype/%.c
+ $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
+
+STRING_OBJS = strcat.o strchr.o strcmp.o strcpy.o strlen.o strncmp.o strncpy.o \
+ strstr.o memset.o memcpy.o memmove.o memcmp.o
+%.o : $(SLOF_DIR)/lib/libc/string/%.c
+ $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
+
+STDLIB_OBJS = atoi.o atol.o strtoul.o strtol.o rand.o malloc.o free.o
+%.o : $(SLOF_DIR)/lib/libc/stdlib/%.c
+ $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
+
+STDIO_OBJS = sprintf.o vfprintf.o vsnprintf.o vsprintf.o fprintf.o \
+ printf.o putc.o puts.o putchar.o stdchnls.o fileno.o
+%.o : $(SLOF_DIR)/lib/libc/stdio/%.c
+ $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
+
+sbrk.o: $(SLOF_DIR)/slof/sbrk.c
+ $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
+
+LIBCOBJS := $(STRING_OBJS) $(CTYPE_OBJS) $(STDLIB_OBJS) $(STDIO_OBJS) sbrk.o
+
+libc.a: $(LIBCOBJS)
+ $(call quiet-command,$(AR) -rc $@ $^,"AR","$(TARGET_DIR)$@")
+
+# libnet files:
+
+LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \
+ dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o
+LIBNETCFLAGS := $(QEMU_CFLAGS) $(LIBC_INC) $(LIBNET_INC)
+
+%.o : $(SLOF_DIR)/lib/libnet/%.c
+ $(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
+
+libnet.a: $(LIBNETOBJS)
+ $(call quiet-command,$(AR) -rc $@ $^,"AR","$(TARGET_DIR)$@")
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
new file mode 100644
index 0000000000..d86d46b03f
--- /dev/null
+++ b/pc-bios/s390-ccw/netmain.c
@@ -0,0 +1,361 @@
+/*
+ * S390 virtio-ccw network boot loading program
+ *
+ * Copyright 2017 Thomas Huth, Red Hat Inc.
+ *
+ * Based on the S390 virtio-ccw loading program (main.c)
+ * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
+ *
+ * And based on the network loading code from SLOF (netload.c)
+ * Copyright (c) 2004, 2008 IBM Corporation
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tftp.h>
+#include <ethernet.h>
+#include <dhcp.h>
+#include <dhcpv6.h>
+#include <ipv4.h>
+#include <ipv6.h>
+#include <dns.h>
+#include <time.h>
+
+#include "s390-ccw.h"
+#include "virtio.h"
+
+#define DEFAULT_BOOT_RETRIES 10
+#define DEFAULT_TFTP_RETRIES 20
+
+extern char _start[];
+
+char stack[PAGE_SIZE * 8] __attribute__((aligned(PAGE_SIZE)));
+IplParameterBlock iplb __attribute__((aligned(PAGE_SIZE)));
+
+static SubChannelId net_schid = { .one = 1 };
+static int ip_version = 4;
+static uint64_t dest_timer;
+
+static uint64_t get_timer_ms(void)
+{
+ uint64_t clk;
+
+ asm volatile(" stck %0 " : : "Q"(clk) : "memory");
+
+ /* Bit 51 is incremented each microsecond */
+ return (clk >> (63 - 51)) / 1000;
+}
+
+void set_timer(int val)
+{
+ dest_timer = get_timer_ms() + val;
+}
+
+int get_timer(void)
+{
+ return dest_timer - get_timer_ms();
+}
+
+int get_sec_ticks(void)
+{
+ return 1000; /* number of ticks in 1 second */
+}
+
+/**
+ * Obtain IP and configuration info from DHCP server (either IPv4 or IPv6).
+ * @param fn_ip contains the following configuration information:
+ * client MAC, client IP, TFTP-server MAC, TFTP-server IP,
+ * boot file name
+ * @param retries Number of DHCP attempts
+ * @return 0 : IP and configuration info obtained;
+ * non-0 : error condition occurred.
+ */
+static int dhcp(struct filename_ip *fn_ip, int retries)
+{
+ int i = retries + 1;
+ int rc = -1;
+
+ printf(" Requesting information via DHCP: ");
+
+ dhcpv4_generate_transaction_id();
+ dhcpv6_generate_transaction_id();
+
+ do {
+ printf("\b\b\b%03d", i - 1);
+ if (!--i) {
+ printf("\nGiving up after %d DHCP requests\n", retries);
+ return -1;
+ }
+ ip_version = 4;
+ rc = dhcpv4(NULL, fn_ip);
+ if (rc == -1) {
+ ip_version = 6;
+ set_ipv6_address(fn_ip->fd, 0);
+ rc = dhcpv6(NULL, fn_ip);
+ if (rc == 0) {
+ memcpy(&fn_ip->own_ip6, get_ipv6_address(), 16);
+ break;
+ }
+ }
+ if (rc != -1) { /* either success or non-dhcp failure */
+ break;
+ }
+ } while (1);
+ printf("\b\b\b\bdone\n");
+
+ return rc;
+}
+
+/**
+ * Seed the random number generator with our mac and current timestamp
+ */
+static void seed_rng(uint8_t mac[])
+{
+ uint64_t seed;
+
+ asm volatile(" stck %0 " : : "Q"(seed) : "memory");
+ seed ^= (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5];
+ srand(seed);
+}
+
+static int tftp_load(filename_ip_t *fnip, void *buffer, int len,
+ unsigned int retries, int ip_vers)
+{
+ tftp_err_t tftp_err;
+ int rc;
+
+ rc = tftp(fnip, buffer, len, retries, &tftp_err, 1, 1428, ip_vers);
+
+ if (rc > 0) {
+ printf(" TFTP: Received %s (%d KBytes)\n", fnip->filename,
+ rc / 1024);
+ } else if (rc == -1) {
+ puts("unknown TFTP error");
+ } else if (rc == -2) {
+ printf("TFTP buffer of %d bytes is too small for %s\n",
+ len, fnip->filename);
+ } else if (rc == -3) {
+ printf("file not found: %s\n", fnip->filename);
+ } else if (rc == -4) {
+ puts("TFTP access violation");
+ } else if (rc == -5) {
+ puts("illegal TFTP operation");
+ } else if (rc == -6) {
+ puts("unknown TFTP transfer ID");
+ } else if (rc == -7) {
+ puts("no such TFTP user");
+ } else if (rc == -8) {
+ puts("TFTP blocksize negotiation failed");
+ } else if (rc == -9) {
+ puts("file exceeds maximum TFTP transfer size");
+ } else if (rc <= -10 && rc >= -15) {
+ const char *icmp_err_str;
+ switch (rc) {
+ case -ICMP_NET_UNREACHABLE - 10:
+ icmp_err_str = "net unreachable";
+ break;
+ case -ICMP_HOST_UNREACHABLE - 10:
+ icmp_err_str = "host unreachable";
+ break;
+ case -ICMP_PROTOCOL_UNREACHABLE - 10:
+ icmp_err_str = "protocol unreachable";
+ break;
+ case -ICMP_PORT_UNREACHABLE - 10:
+ icmp_err_str = "port unreachable";
+ break;
+ case -ICMP_FRAGMENTATION_NEEDED - 10:
+ icmp_err_str = "fragmentation needed and DF set";
+ break;
+ case -ICMP_SOURCE_ROUTE_FAILED - 10:
+ icmp_err_str = "source route failed";
+ break;
+ default:
+ icmp_err_str = " UNKNOWN";
+ break;
+ }
+ printf("ICMP ERROR \"%s\"\n", icmp_err_str);
+ } else if (rc == -40) {
+ printf("TFTP error occurred after %d bad packets received",
+ tftp_err.bad_tftp_packets);
+ } else if (rc == -41) {
+ printf("TFTP error occurred after missing %d responses",
+ tftp_err.no_packets);
+ } else if (rc == -42) {
+ printf("TFTP error missing block %d, expected block was %d",
+ tftp_err.blocks_missed,
+ tftp_err.blocks_received);
+ }
+
+ return rc;
+}
+
+static int net_load(char *buffer, int len)
+{
+ filename_ip_t fn_ip;
+ uint8_t mac[6];
+ int rc;
+
+ memset(&fn_ip, 0, sizeof(filename_ip_t));
+
+ rc = virtio_net_init(mac);
+ if (rc < 0) {
+ puts("Could not initialize network device");
+ return -101;
+ }
+ fn_ip.fd = rc;
+
+ printf(" Using MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ set_mac_address(mac); /* init ethernet layer */
+ seed_rng(mac);
+
+ rc = dhcp(&fn_ip, DEFAULT_BOOT_RETRIES);
+ if (rc >= 0) {
+ if (ip_version == 4) {
+ set_ipv4_address(fn_ip.own_ip);
+ }
+ } else {
+ puts("Could not get IP address");
+ return -101;
+ }
+
+ if (ip_version == 4) {
+ printf(" Using IPv4 address: %d.%d.%d.%d\n",
+ (fn_ip.own_ip >> 24) & 0xFF, (fn_ip.own_ip >> 16) & 0xFF,
+ (fn_ip.own_ip >> 8) & 0xFF, fn_ip.own_ip & 0xFF);
+ } else if (ip_version == 6) {
+ char ip6_str[40];
+ ipv6_to_str(fn_ip.own_ip6.addr, ip6_str);
+ printf(" Using IPv6 address: %s\n", ip6_str);
+ }
+
+ if (rc == -2) {
+ printf("ARP request to TFTP server (%d.%d.%d.%d) failed\n",
+ (fn_ip.server_ip >> 24) & 0xFF, (fn_ip.server_ip >> 16) & 0xFF,
+ (fn_ip.server_ip >> 8) & 0xFF, fn_ip.server_ip & 0xFF);
+ return -102;
+ }
+ if (rc == -4 || rc == -3) {
+ puts("Can't obtain TFTP server IP address");
+ return -107;
+ }
+
+ if (ip_version == 4) {
+ printf(" Requesting file \"%s\" via TFTP from %d.%d.%d.%d\n",
+ fn_ip.filename,
+ (fn_ip.server_ip >> 24) & 0xFF, (fn_ip.server_ip >> 16) & 0xFF,
+ (fn_ip.server_ip >> 8) & 0xFF, fn_ip.server_ip & 0xFF);
+ } else if (ip_version == 6) {
+ char ip6_str[40];
+ printf(" Requesting file \"%s\" via TFTP from ", fn_ip.filename);
+ ipv6_to_str(fn_ip.server_ip6.addr, ip6_str);
+ printf("%s\n", ip6_str);
+ }
+
+ /* Do the TFTP load and print error message if necessary */
+ rc = tftp_load(&fn_ip, buffer, len, DEFAULT_TFTP_RETRIES, ip_version);
+
+ if (ip_version == 4) {
+ dhcp_send_release(fn_ip.fd);
+ }
+
+ return rc;
+}
+
+void panic(const char *string)
+{
+ sclp_print(string);
+ for (;;) {
+ disabled_wait();
+ }
+}
+
+static bool find_net_dev(Schib *schib, int dev_no)
+{
+ int i, r;
+
+ for (i = 0; i < 0x10000; i++) {
+ net_schid.sch_no = i;
+ r = stsch_err(net_schid, schib);
+ if (r == 3 || r == -EIO) {
+ break;
+ }
+ if (!schib->pmcw.dnv) {
+ continue;
+ }
+ if (!virtio_is_supported(net_schid)) {
+ continue;
+ }
+ if (virtio_get_device_type() != VIRTIO_ID_NET) {
+ continue;
+ }
+ if (dev_no < 0 || schib->pmcw.dev == dev_no) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void virtio_setup(void)
+{
+ Schib schib;
+ int ssid;
+ bool found = false;
+ uint16_t dev_no;
+
+ /*
+ * We unconditionally enable mss support. In every sane configuration,
+ * this will succeed; and even if it doesn't, stsch_err() can deal
+ * with the consequences.
+ */
+ enable_mss_facility();
+
+ if (store_iplb(&iplb)) {
+ IPL_assert(iplb.pbt == S390_IPL_TYPE_CCW, "IPL_TYPE_CCW expected");
+ dev_no = iplb.ccw.devno;
+ debug_print_int("device no. ", dev_no);
+ net_schid.ssid = iplb.ccw.ssid & 0x3;
+ debug_print_int("ssid ", net_schid.ssid);
+ found = find_net_dev(&schib, dev_no);
+ } else {
+ for (ssid = 0; ssid < 0x3; ssid++) {
+ net_schid.ssid = ssid;
+ found = find_net_dev(&schib, -1);
+ if (found) {
+ break;
+ }
+ }
+ }
+
+ IPL_assert(found, "No virtio net device found");
+}
+
+void main(void)
+{
+ int rc;
+
+ sclp_setup();
+ sclp_print("Network boot starting...\n");
+
+ virtio_setup();
+
+ rc = net_load(NULL, (long)_start);
+ if (rc > 0) {
+ sclp_print("Network loading done, starting kernel...\n");
+ asm volatile (" lpsw 0(%0) " : : "r"(0) : "memory");
+ }
+
+ panic("Failed to load OS from network\n");
+}
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 2089274842..25d4d213ea 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -18,12 +18,6 @@ typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef unsigned long ulong;
-typedef long size_t;
-typedef int bool;
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
typedef unsigned char __u8;
typedef unsigned short __u16;
typedef unsigned int __u32;
@@ -50,6 +44,8 @@ typedef unsigned long long __u64;
((b) == 0 ? (a) : (MIN(a, b))))
#endif
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
#include "cio.h"
#include "iplb.h"
@@ -80,7 +76,7 @@ void sclp_get_loadparm_ascii(char *loadparm);
unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
ulong subchan_id, void *load_addr);
bool virtio_is_supported(SubChannelId schid);
-void virtio_setup_device(SubChannelId schid);
+void virtio_blk_setup_device(SubChannelId schid);
int virtio_read(ulong sector, void *load_addr);
int enable_mss_facility(void);
ulong get_second(void);
@@ -88,18 +84,6 @@ ulong get_second(void);
/* bootmap.c */
void zipl_load(void);
-static inline void *memset(void *s, int c, size_t n)
-{
- int i;
- unsigned char *p = s;
-
- for (i = 0; i < n; i++) {
- p[i] = c;
- }
-
- return s;
-}
-
static inline void fill_hex(char *out, unsigned char val)
{
const char hex[] = "0123456789abcdef";
@@ -169,17 +153,6 @@ static inline void sleep(unsigned int seconds)
}
}
-static inline void *memcpy(void *s1, const void *s2, size_t n)
-{
- uint8_t *p1 = s1;
- const uint8_t *p2 = s2;
-
- while (n--) {
- p1[n] = p2[n];
- }
- return s1;
-}
-
static inline void IPL_assert(bool term, const char *message)
{
if (!term) {
diff --git a/pc-bios/s390-ccw/sclp.c b/pc-bios/s390-ccw/sclp.c
index a1639baed7..b1fc8ff44b 100644
--- a/pc-bios/s390-ccw/sclp.c
+++ b/pc-bios/s390-ccw/sclp.c
@@ -8,11 +8,25 @@
* directory.
*/
+#include "libc.h"
#include "s390-ccw.h"
#include "sclp.h"
+long write(int fd, const void *str, size_t len);
+
static char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096)));
+const unsigned char ebc2asc[256] =
+ /* 0123456789abcdef0123456789abcdef */
+ "................................" /* 1F */
+ "................................" /* 3F */
+ " ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */
+ "-/.........,%_>?.........`:#@'=\""/* 7F */
+ ".abcdefghi.......jklmnopqr......" /* 9F */
+ "..stuvwxyz......................" /* BF */
+ ".ABCDEFGHI.......JKLMNOPQR......" /* DF */
+ "..STUVWXYZ......0123456789......";/* FF */
+
/* Perform service call. Return 0 on success, non-zero otherwise. */
static int sclp_service_call(unsigned int command, void *sccb)
{
@@ -59,26 +73,29 @@ static int _strlen(const char *str)
return i;
}
-static void _memcpy(char *dest, const char *src, int len)
-{
- int i;
- for (i = 0; i < len; i++)
- dest[i] = src[i];
-}
-
-void sclp_print(const char *str)
+long write(int fd, const void *str, size_t len)
{
- int len = _strlen(str);
WriteEventData *sccb = (void *)_sccb;
+ if (fd != 1 && fd != 2) {
+ return -EIO;
+ }
+
sccb->h.length = sizeof(WriteEventData) + len;
sccb->h.function_code = SCLP_FC_NORMAL_WRITE;
sccb->ebh.length = sizeof(EventBufferHeader) + len;
sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
sccb->ebh.flags = 0;
- _memcpy(sccb->data, str, len);
+ memcpy(sccb->data, str, len);
sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb);
+
+ return len;
+}
+
+void sclp_print(const char *str)
+{
+ write(1, str, _strlen(str));
}
void sclp_get_loadparm_ascii(char *loadparm)
diff --git a/pc-bios/s390-ccw/virtio-blkdev.c b/pc-bios/s390-ccw/virtio-blkdev.c
new file mode 100644
index 0000000000..11c56261ca
--- /dev/null
+++ b/pc-bios/s390-ccw/virtio-blkdev.c
@@ -0,0 +1,296 @@
+/*
+ * Virtio driver bits
+ *
+ * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "libc.h"
+#include "s390-ccw.h"
+#include "virtio.h"
+#include "virtio-scsi.h"
+
+static int virtio_blk_read_many(VDev *vdev, ulong sector, void *load_addr,
+ int sec_num)
+{
+ VirtioBlkOuthdr out_hdr;
+ u8 status;
+ VRing *vr = &vdev->vrings[vdev->cmd_vr_idx];
+
+ /* Tell the host we want to read */
+ out_hdr.type = VIRTIO_BLK_T_IN;
+ out_hdr.ioprio = 99;
+ out_hdr.sector = virtio_sector_adjust(sector);
+
+ vring_send_buf(vr, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
+
+ /* This is where we want to receive data */
+ vring_send_buf(vr, load_addr, virtio_get_block_size() * sec_num,
+ VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN |
+ VRING_DESC_F_NEXT);
+
+ /* status field */
+ vring_send_buf(vr, &status, sizeof(u8),
+ VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN);
+
+ /* Now we can tell the host to read */
+ vring_wait_reply();
+
+ if (drain_irqs(vr->schid)) {
+ /* Well, whatever status is supposed to contain... */
+ status = 1;
+ }
+ return status;
+}
+
+int virtio_read_many(ulong sector, void *load_addr, int sec_num)
+{
+ VDev *vdev = virtio_get_device();
+
+ switch (vdev->senseid.cu_model) {
+ case VIRTIO_ID_BLOCK:
+ return virtio_blk_read_many(vdev, sector, load_addr, sec_num);
+ case VIRTIO_ID_SCSI:
+ return virtio_scsi_read_many(vdev, sector, load_addr, sec_num);
+ }
+ panic("\n! No readable IPL device !\n");
+ return -1;
+}
+
+unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
+ ulong subchan_id, void *load_addr)
+{
+ u8 status;
+ int sec = rec_list1;
+ int sec_num = ((rec_list2 >> 32) & 0xffff) + 1;
+ int sec_len = rec_list2 >> 48;
+ ulong addr = (ulong)load_addr;
+
+ if (sec_len != virtio_get_block_size()) {
+ return -1;
+ }
+
+ sclp_print(".");
+ status = virtio_read_many(sec, (void *)addr, sec_num);
+ if (status) {
+ panic("I/O Error");
+ }
+ addr += sec_num * virtio_get_block_size();
+
+ return addr;
+}
+
+int virtio_read(ulong sector, void *load_addr)
+{
+ return virtio_read_many(sector, load_addr, 1);
+}
+
+/*
+ * Other supported value pairs, if any, would need to be added here.
+ * Note: head count is always 15.
+ */
+static inline u8 virtio_eckd_sectors_for_block_size(int size)
+{
+ switch (size) {
+ case 512:
+ return 49;
+ case 1024:
+ return 33;
+ case 2048:
+ return 21;
+ case 4096:
+ return 12;
+ }
+ return 0;
+}
+
+VirtioGDN virtio_guessed_disk_nature(void)
+{
+ return virtio_get_device()->guessed_disk_nature;
+}
+
+void virtio_assume_scsi(void)
+{
+ VDev *vdev = virtio_get_device();
+
+ switch (vdev->senseid.cu_model) {
+ case VIRTIO_ID_BLOCK:
+ vdev->guessed_disk_nature = VIRTIO_GDN_SCSI;
+ vdev->config.blk.blk_size = VIRTIO_SCSI_BLOCK_SIZE;
+ vdev->config.blk.physical_block_exp = 0;
+ vdev->blk_factor = 1;
+ break;
+ case VIRTIO_ID_SCSI:
+ vdev->scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE;
+ break;
+ }
+}
+
+void virtio_assume_iso9660(void)
+{
+ VDev *vdev = virtio_get_device();
+
+ switch (vdev->senseid.cu_model) {
+ case VIRTIO_ID_BLOCK:
+ vdev->guessed_disk_nature = VIRTIO_GDN_SCSI;
+ vdev->config.blk.blk_size = VIRTIO_ISO_BLOCK_SIZE;
+ vdev->config.blk.physical_block_exp = 0;
+ vdev->blk_factor = VIRTIO_ISO_BLOCK_SIZE / VIRTIO_SECTOR_SIZE;
+ break;
+ case VIRTIO_ID_SCSI:
+ vdev->scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
+ break;
+ }
+}
+
+void virtio_assume_eckd(void)
+{
+ VDev *vdev = virtio_get_device();
+
+ vdev->guessed_disk_nature = VIRTIO_GDN_DASD;
+ vdev->blk_factor = 1;
+ vdev->config.blk.physical_block_exp = 0;
+ switch (vdev->senseid.cu_model) {
+ case VIRTIO_ID_BLOCK:
+ vdev->config.blk.blk_size = 4096;
+ break;
+ case VIRTIO_ID_SCSI:
+ vdev->config.blk.blk_size = vdev->scsi_block_size;
+ break;
+ }
+ vdev->config.blk.geometry.heads = 15;
+ vdev->config.blk.geometry.sectors =
+ virtio_eckd_sectors_for_block_size(vdev->config.blk.blk_size);
+}
+
+bool virtio_disk_is_scsi(void)
+{
+ VDev *vdev = virtio_get_device();
+
+ if (vdev->guessed_disk_nature == VIRTIO_GDN_SCSI) {
+ return true;
+ }
+ switch (vdev->senseid.cu_model) {
+ case VIRTIO_ID_BLOCK:
+ return (vdev->config.blk.geometry.heads == 255)
+ && (vdev->config.blk.geometry.sectors == 63)
+ && (virtio_get_block_size() == VIRTIO_SCSI_BLOCK_SIZE);
+ case VIRTIO_ID_SCSI:
+ return true;
+ }
+ return false;
+}
+
+bool virtio_disk_is_eckd(void)
+{
+ VDev *vdev = virtio_get_device();
+ const int block_size = virtio_get_block_size();
+
+ if (vdev->guessed_disk_nature == VIRTIO_GDN_DASD) {
+ return true;
+ }
+ switch (vdev->senseid.cu_model) {
+ case VIRTIO_ID_BLOCK:
+ return (vdev->config.blk.geometry.heads == 15)
+ && (vdev->config.blk.geometry.sectors ==
+ virtio_eckd_sectors_for_block_size(block_size));
+ case VIRTIO_ID_SCSI:
+ return false;
+ }
+ return false;
+}
+
+bool virtio_ipl_disk_is_valid(void)
+{
+ return virtio_disk_is_scsi() || virtio_disk_is_eckd();
+}
+
+int virtio_get_block_size(void)
+{
+ VDev *vdev = virtio_get_device();
+
+ switch (vdev->senseid.cu_model) {
+ case VIRTIO_ID_BLOCK:
+ return vdev->config.blk.blk_size << vdev->config.blk.physical_block_exp;
+ case VIRTIO_ID_SCSI:
+ return vdev->scsi_block_size;
+ }
+ return 0;
+}
+
+uint8_t virtio_get_heads(void)
+{
+ VDev *vdev = virtio_get_device();
+
+ switch (vdev->senseid.cu_model) {
+ case VIRTIO_ID_BLOCK:
+ return vdev->config.blk.geometry.heads;
+ case VIRTIO_ID_SCSI:
+ return vdev->guessed_disk_nature == VIRTIO_GDN_DASD
+ ? vdev->config.blk.geometry.heads : 255;
+ }
+ return 0;
+}
+
+uint8_t virtio_get_sectors(void)
+{
+ VDev *vdev = virtio_get_device();
+
+ switch (vdev->senseid.cu_model) {
+ case VIRTIO_ID_BLOCK:
+ return vdev->config.blk.geometry.sectors;
+ case VIRTIO_ID_SCSI:
+ return vdev->guessed_disk_nature == VIRTIO_GDN_DASD
+ ? vdev->config.blk.geometry.sectors : 63;
+ }
+ return 0;
+}
+
+uint64_t virtio_get_blocks(void)
+{
+ VDev *vdev = virtio_get_device();
+ const uint64_t factor = virtio_get_block_size() / VIRTIO_SECTOR_SIZE;
+
+ switch (vdev->senseid.cu_model) {
+ case VIRTIO_ID_BLOCK:
+ return vdev->config.blk.capacity / factor;
+ case VIRTIO_ID_SCSI:
+ return vdev->scsi_last_block / factor;
+ }
+ return 0;
+}
+
+void virtio_blk_setup_device(SubChannelId schid)
+{
+ VDev *vdev = virtio_get_device();
+
+ vdev->schid = schid;
+ virtio_setup_ccw(vdev);
+
+ switch (vdev->senseid.cu_model) {
+ case VIRTIO_ID_BLOCK:
+ sclp_print("Using virtio-blk.\n");
+ if (!virtio_ipl_disk_is_valid()) {
+ /* make sure all getters but blocksize return 0 for
+ * invalid IPL disk
+ */
+ memset(&vdev->config.blk, 0, sizeof(vdev->config.blk));
+ virtio_assume_scsi();
+ }
+ break;
+ case VIRTIO_ID_SCSI:
+ IPL_assert(vdev->config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE,
+ "Config: sense size mismatch");
+ IPL_assert(vdev->config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE,
+ "Config: CDB size mismatch");
+
+ sclp_print("Using virtio-scsi.\n");
+ virtio_scsi_setup(vdev);
+ break;
+ default:
+ panic("\n! No IPL device available !\n");
+ }
+}
diff --git a/pc-bios/s390-ccw/virtio-net.c b/pc-bios/s390-ccw/virtio-net.c
new file mode 100644
index 0000000000..ff7f4dad25
--- /dev/null
+++ b/pc-bios/s390-ccw/virtio-net.c
@@ -0,0 +1,135 @@
+/*
+ * Virtio-net driver for the s390-ccw firmware
+ *
+ * Copyright 2017 Thomas Huth, Red Hat Inc.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <ethernet.h>
+#include "s390-ccw.h"
+#include "virtio.h"
+
+#ifndef DEBUG_VIRTIO_NET
+#define DEBUG_VIRTIO_NET 0
+#endif
+
+#define VIRTIO_NET_F_MAC_BIT (1 << 5)
+
+#define VQ_RX 0 /* Receive queue */
+#define VQ_TX 1 /* Transmit queue */
+
+struct VirtioNetHdr {
+ uint8_t flags;
+ uint8_t gso_type;
+ uint16_t hdr_len;
+ uint16_t gso_size;
+ uint16_t csum_start;
+ uint16_t csum_offset;
+ /*uint16_t num_buffers;*/ /* Only with VIRTIO_NET_F_MRG_RXBUF or VIRTIO1 */
+};
+typedef struct VirtioNetHdr VirtioNetHdr;
+
+static uint16_t rx_last_idx; /* Last index in receive queue "used" ring */
+
+int virtio_net_init(void *mac_addr)
+{
+ VDev *vdev = virtio_get_device();
+ VRing *rxvq = &vdev->vrings[VQ_RX];
+ void *buf;
+ int i;
+
+ vdev->guest_features[0] = VIRTIO_NET_F_MAC_BIT;
+ virtio_setup_ccw(vdev);
+
+ IPL_assert(vdev->guest_features[0] & VIRTIO_NET_F_MAC_BIT,
+ "virtio-net device does not support the MAC address feature");
+ memcpy(mac_addr, vdev->config.net.mac, ETH_ALEN);
+
+ for (i = 0; i < 64; i++) {
+ buf = malloc(ETH_MTU_SIZE + sizeof(VirtioNetHdr));
+ IPL_assert(buf != NULL, "Can not allocate memory for receive buffers");
+ vring_send_buf(rxvq, buf, ETH_MTU_SIZE + sizeof(VirtioNetHdr),
+ VRING_DESC_F_WRITE);
+ }
+ vring_notify(rxvq);
+
+ return 0;
+}
+
+int send(int fd, const void *buf, int len, int flags)
+{
+ VirtioNetHdr tx_hdr;
+ VDev *vdev = virtio_get_device();
+ VRing *txvq = &vdev->vrings[VQ_TX];
+
+ /* Set up header - we do not use anything special, so simply clear it */
+ memset(&tx_hdr, 0, sizeof(tx_hdr));
+
+ vring_send_buf(txvq, &tx_hdr, sizeof(tx_hdr), VRING_DESC_F_NEXT);
+ vring_send_buf(txvq, (void *)buf, len, VRING_HIDDEN_IS_CHAIN);
+ while (!vr_poll(txvq)) {
+ yield();
+ }
+ if (drain_irqs(txvq->schid)) {
+ puts("send: drain irqs failed");
+ return -1;
+ }
+
+ return len;
+}
+
+int recv(int fd, void *buf, int maxlen, int flags)
+{
+ VDev *vdev = virtio_get_device();
+ VRing *rxvq = &vdev->vrings[VQ_RX];
+ int len, id;
+ uint8_t *pkt;
+
+ if (rx_last_idx == rxvq->used->idx) {
+ return 0;
+ }
+
+ len = rxvq->used->ring[rx_last_idx % rxvq->num].len - sizeof(VirtioNetHdr);
+ if (len > maxlen) {
+ puts("virtio-net: Receive buffer too small");
+ len = maxlen;
+ }
+ id = rxvq->used->ring[rx_last_idx % rxvq->num].id % rxvq->num;
+ pkt = (uint8_t *)(rxvq->desc[id].addr + sizeof(VirtioNetHdr));
+
+#if DEBUG_VIRTIO_NET /* Dump packet */
+ int i;
+ printf("\nbuf %p: len=%i\n", (void *)rxvq->desc[id].addr, len);
+ for (i = 0; i < 64; i++) {
+ printf(" %02x", pkt[i]);
+ if ((i % 16) == 15) {
+ printf("\n");
+ }
+ }
+ printf("\n");
+#endif
+
+ /* Copy data to destination buffer */
+ memcpy(buf, pkt, len);
+
+ /* Mark buffer as available to the host again */
+ rxvq->avail->ring[rxvq->avail->idx % rxvq->num] = id;
+ rxvq->avail->idx = rxvq->avail->idx + 1;
+ vring_notify(rxvq);
+
+ /* Move index to next entry */
+ rx_last_idx = rx_last_idx + 1;
+
+ return len;
+}
diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c
index f61ecf0205..c92f5d3fa0 100644
--- a/pc-bios/s390-ccw/virtio-scsi.c
+++ b/pc-bios/s390-ccw/virtio-scsi.c
@@ -9,6 +9,7 @@
* directory.
*/
+#include "libc.h"
#include "s390-ccw.h"
#include "virtio.h"
#include "scsi.h"
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 6ee93d56db..c890a0330b 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -8,9 +8,11 @@
* directory.
*/
+#include "libc.h"
#include "s390-ccw.h"
#include "virtio.h"
#include "virtio-scsi.h"
+#include "bswap.h"
#define VRING_WAIT_REPLY_TIMEOUT 3
@@ -69,7 +71,7 @@ static long virtio_notify(SubChannelId schid, int vq_idx, long cookie)
* Virtio functions *
***********************************************/
-static int drain_irqs(SubChannelId schid)
+int drain_irqs(SubChannelId schid)
{
Irb irb = {};
int r = 0;
@@ -148,13 +150,13 @@ static void vring_init(VRing *vr, VqInfo *info)
debug_print_addr("init vr", vr);
}
-static bool vring_notify(VRing *vr)
+bool vring_notify(VRing *vr)
{
vr->cookie = virtio_notify(vr->schid, vr->id, vr->cookie);
return vr->cookie >= 0;
}
-static void vring_send_buf(VRing *vr, void *p, int len, int flags)
+void vring_send_buf(VRing *vr, void *p, int len, int flags)
{
/* For follow-up chains we need to keep the first entry point */
if (!(flags & VRING_HIDDEN_IS_CHAIN)) {
@@ -187,7 +189,7 @@ ulong get_second(void)
return (get_clock() >> 12) / 1000000;
}
-static int vr_poll(VRing *vr)
+int vr_poll(VRing *vr)
{
if (vr->used->idx == vr->used_idx) {
vring_notify(vr);
@@ -209,7 +211,7 @@ static int vr_poll(VRing *vr)
*
* Returns 0 on success, 1 on timeout.
*/
-static int vring_wait_reply(void)
+int vring_wait_reply(void)
{
ulong target_second = get_second() + vdev.wait_reply_timeout;
@@ -246,245 +248,14 @@ int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
return 0;
}
-/***********************************************
- * Virtio block *
- ***********************************************/
-
-static int virtio_blk_read_many(VDev *vdev,
- ulong sector, void *load_addr, int sec_num)
-{
- VirtioBlkOuthdr out_hdr;
- u8 status;
- VRing *vr = &vdev->vrings[vdev->cmd_vr_idx];
-
- /* Tell the host we want to read */
- out_hdr.type = VIRTIO_BLK_T_IN;
- out_hdr.ioprio = 99;
- out_hdr.sector = virtio_sector_adjust(sector);
-
- vring_send_buf(vr, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
-
- /* This is where we want to receive data */
- vring_send_buf(vr, load_addr, virtio_get_block_size() * sec_num,
- VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN |
- VRING_DESC_F_NEXT);
-
- /* status field */
- vring_send_buf(vr, &status, sizeof(u8),
- VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN);
-
- /* Now we can tell the host to read */
- vring_wait_reply();
-
- if (drain_irqs(vr->schid)) {
- /* Well, whatever status is supposed to contain... */
- status = 1;
- }
- return status;
-}
-
-int virtio_read_many(ulong sector, void *load_addr, int sec_num)
-{
- switch (vdev.senseid.cu_model) {
- case VIRTIO_ID_BLOCK:
- return virtio_blk_read_many(&vdev, sector, load_addr, sec_num);
- case VIRTIO_ID_SCSI:
- return virtio_scsi_read_many(&vdev, sector, load_addr, sec_num);
- }
- panic("\n! No readable IPL device !\n");
- return -1;
-}
-
-unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
- ulong subchan_id, void *load_addr)
-{
- u8 status;
- int sec = rec_list1;
- int sec_num = ((rec_list2 >> 32) & 0xffff) + 1;
- int sec_len = rec_list2 >> 48;
- ulong addr = (ulong)load_addr;
-
- if (sec_len != virtio_get_block_size()) {
- return -1;
- }
-
- sclp_print(".");
- status = virtio_read_many(sec, (void *)addr, sec_num);
- if (status) {
- panic("I/O Error");
- }
- addr += sec_num * virtio_get_block_size();
-
- return addr;
-}
-
-int virtio_read(ulong sector, void *load_addr)
-{
- return virtio_read_many(sector, load_addr, 1);
-}
-
-/*
- * Other supported value pairs, if any, would need to be added here.
- * Note: head count is always 15.
- */
-static inline u8 virtio_eckd_sectors_for_block_size(int size)
-{
- switch (size) {
- case 512:
- return 49;
- case 1024:
- return 33;
- case 2048:
- return 21;
- case 4096:
- return 12;
- }
- return 0;
-}
-
-VirtioGDN virtio_guessed_disk_nature(void)
-{
- return vdev.guessed_disk_nature;
-}
-
-void virtio_assume_scsi(void)
-{
- switch (vdev.senseid.cu_model) {
- case VIRTIO_ID_BLOCK:
- vdev.guessed_disk_nature = VIRTIO_GDN_SCSI;
- vdev.config.blk.blk_size = VIRTIO_SCSI_BLOCK_SIZE;
- vdev.config.blk.physical_block_exp = 0;
- vdev.blk_factor = 1;
- break;
- case VIRTIO_ID_SCSI:
- vdev.scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE;
- break;
- }
-}
-
-void virtio_assume_iso9660(void)
-{
- switch (vdev.senseid.cu_model) {
- case VIRTIO_ID_BLOCK:
- vdev.guessed_disk_nature = VIRTIO_GDN_SCSI;
- vdev.config.blk.blk_size = VIRTIO_ISO_BLOCK_SIZE;
- vdev.config.blk.physical_block_exp = 0;
- vdev.blk_factor = VIRTIO_ISO_BLOCK_SIZE / VIRTIO_SECTOR_SIZE;
- break;
- case VIRTIO_ID_SCSI:
- vdev.scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
- break;
- }
-}
-
-void virtio_assume_eckd(void)
-{
- vdev.guessed_disk_nature = VIRTIO_GDN_DASD;
- vdev.blk_factor = 1;
- vdev.config.blk.physical_block_exp = 0;
- switch (vdev.senseid.cu_model) {
- case VIRTIO_ID_BLOCK:
- vdev.config.blk.blk_size = 4096;
- break;
- case VIRTIO_ID_SCSI:
- vdev.config.blk.blk_size = vdev.scsi_block_size;
- break;
- }
- vdev.config.blk.geometry.heads = 15;
- vdev.config.blk.geometry.sectors =
- virtio_eckd_sectors_for_block_size(vdev.config.blk.blk_size);
-}
-
-bool virtio_disk_is_scsi(void)
+void virtio_setup_ccw(VDev *vdev)
{
- if (vdev.guessed_disk_nature == VIRTIO_GDN_SCSI) {
- return true;
- }
- switch (vdev.senseid.cu_model) {
- case VIRTIO_ID_BLOCK:
- return (vdev.config.blk.geometry.heads == 255)
- && (vdev.config.blk.geometry.sectors == 63)
- && (virtio_get_block_size() == VIRTIO_SCSI_BLOCK_SIZE);
- case VIRTIO_ID_SCSI:
- return true;
- }
- return false;
-}
-
-bool virtio_disk_is_eckd(void)
-{
- const int block_size = virtio_get_block_size();
-
- if (vdev.guessed_disk_nature == VIRTIO_GDN_DASD) {
- return true;
- }
- switch (vdev.senseid.cu_model) {
- case VIRTIO_ID_BLOCK:
- return (vdev.config.blk.geometry.heads == 15)
- && (vdev.config.blk.geometry.sectors ==
- virtio_eckd_sectors_for_block_size(block_size));
- case VIRTIO_ID_SCSI:
- return false;
- }
- return false;
-}
-
-bool virtio_ipl_disk_is_valid(void)
-{
- return virtio_disk_is_scsi() || virtio_disk_is_eckd();
-}
-
-int virtio_get_block_size(void)
-{
- switch (vdev.senseid.cu_model) {
- case VIRTIO_ID_BLOCK:
- return vdev.config.blk.blk_size << vdev.config.blk.physical_block_exp;
- case VIRTIO_ID_SCSI:
- return vdev.scsi_block_size;
- }
- return 0;
-}
-
-uint8_t virtio_get_heads(void)
-{
- switch (vdev.senseid.cu_model) {
- case VIRTIO_ID_BLOCK:
- return vdev.config.blk.geometry.heads;
- case VIRTIO_ID_SCSI:
- return vdev.guessed_disk_nature == VIRTIO_GDN_DASD
- ? vdev.config.blk.geometry.heads : 255;
- }
- return 0;
-}
-
-uint8_t virtio_get_sectors(void)
-{
- switch (vdev.senseid.cu_model) {
- case VIRTIO_ID_BLOCK:
- return vdev.config.blk.geometry.sectors;
- case VIRTIO_ID_SCSI:
- return vdev.guessed_disk_nature == VIRTIO_GDN_DASD
- ? vdev.config.blk.geometry.sectors : 63;
- }
- return 0;
-}
-
-uint64_t virtio_get_blocks(void)
-{
- const uint64_t factor = virtio_get_block_size() / VIRTIO_SECTOR_SIZE;
- switch (vdev.senseid.cu_model) {
- case VIRTIO_ID_BLOCK:
- return vdev.config.blk.capacity / factor;
- case VIRTIO_ID_SCSI:
- return vdev.scsi_last_block / factor;
- }
- return 0;
-}
-
-static void virtio_setup_ccw(VDev *vdev)
-{
- int i, cfg_size = 0;
+ int i, rc, cfg_size = 0;
unsigned char status = VIRTIO_CONFIG_S_DRIVER_OK;
+ struct VirtioFeatureDesc {
+ uint32_t features;
+ uint8_t index;
+ } __attribute__((packed)) feats;
IPL_assert(virtio_is_supported(vdev->schid), "PE");
/* device ID has been established now */
@@ -495,6 +266,11 @@ static void virtio_setup_ccw(VDev *vdev)
run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0);
switch (vdev->senseid.cu_model) {
+ case VIRTIO_ID_NET:
+ vdev->nr_vqs = 2;
+ vdev->cmd_vr_idx = 0;
+ cfg_size = sizeof(vdev->config.net);
+ break;
case VIRTIO_ID_BLOCK:
vdev->nr_vqs = 1;
vdev->cmd_vr_idx = 0;
@@ -511,11 +287,17 @@ static void virtio_setup_ccw(VDev *vdev)
IPL_assert(run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size) == 0,
"Could not get block device configuration");
- /*
- * Skipping CCW_CMD_READ_FEAT. We're not doing anything fancy, and
- * we'll just stop dead anyway if anything does not work like we
- * expect it.
- */
+ /* Feature negotiation */
+ for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
+ feats.features = 0;
+ feats.index = i;
+ rc = run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats));
+ IPL_assert(rc == 0, "Could not get features bits");
+ vdev->guest_features[i] &= bswap32(feats.features);
+ feats.features = bswap32(vdev->guest_features[i]);
+ rc = run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats));
+ IPL_assert(rc == 0, "Could not set features bits");
+ }
for (i = 0; i < vdev->nr_vqs; i++) {
VqInfo info = {
@@ -543,36 +325,6 @@ static void virtio_setup_ccw(VDev *vdev)
"Could not write status to host");
}
-void virtio_setup_device(SubChannelId schid)
-{
- vdev.schid = schid;
- virtio_setup_ccw(&vdev);
-
- switch (vdev.senseid.cu_model) {
- case VIRTIO_ID_BLOCK:
- sclp_print("Using virtio-blk.\n");
- if (!virtio_ipl_disk_is_valid()) {
- /* make sure all getters but blocksize return 0 for
- * invalid IPL disk
- */
- memset(&vdev.config.blk, 0, sizeof(vdev.config.blk));
- virtio_assume_scsi();
- }
- break;
- case VIRTIO_ID_SCSI:
- IPL_assert(vdev.config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE,
- "Config: sense size mismatch");
- IPL_assert(vdev.config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE,
- "Config: CDB size mismatch");
-
- sclp_print("Using virtio-scsi.\n");
- virtio_scsi_setup(&vdev);
- break;
- default:
- panic("\n! No IPL device available !\n");
- }
-}
-
bool virtio_is_supported(SubChannelId schid)
{
vdev.schid = schid;
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index 1eaf865b1f..19fceb6495 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -11,8 +11,6 @@
#ifndef VIRTIO_H
#define VIRTIO_H
-#include "s390-ccw.h"
-
/* Status byte for guest to report progress, and synchronize features. */
/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
@@ -32,24 +30,6 @@ enum VirtioDevType {
};
typedef enum VirtioDevType VirtioDevType;
-struct VirtioDevHeader {
- VirtioDevType type:8;
- uint8_t num_vq;
- uint8_t feature_len;
- uint8_t config_len;
- uint8_t status;
- uint8_t vqconfig[];
-} __attribute__((packed));
-typedef struct VirtioDevHeader VirtioDevHeader;
-
-struct VirtioVqConfig {
- uint64_t token;
- uint64_t address;
- uint16_t num;
- uint8_t pad[6];
-} __attribute__((packed));
-typedef struct VirtioVqConfig VirtioVqConfig;
-
struct VqInfo {
uint64_t queue;
uint32_t align;
@@ -64,15 +44,6 @@ struct VqConfig {
} __attribute__((packed));
typedef struct VqConfig VqConfig;
-struct VirtioDev {
- VirtioDevHeader *header;
- VirtioVqConfig *vqconfig;
- char *host_features;
- char *guest_features;
- char *config;
-};
-typedef struct VirtioDev VirtioDev;
-
#define VIRTIO_RING_SIZE (PAGE_SIZE * 8)
#define VIRTIO_MAX_VQS 3
#define KVM_S390_VIRTIO_RING_ALIGN 4096
@@ -254,6 +225,13 @@ struct ScsiDevice {
};
typedef struct ScsiDevice ScsiDevice;
+struct VirtioNetConfig {
+ uint8_t mac[6];
+ /* uint16_t status; */ /* Only with VIRTIO_NET_F_STATUS */
+ /* uint16_t max_virtqueue_pairs; */ /* Only with VIRTIO_NET_F_MQ */
+};
+typedef struct VirtioNetConfig VirtioNetConfig;
+
struct VDev {
int nr_vqs;
VRing *vrings;
@@ -266,6 +244,7 @@ struct VDev {
union {
VirtioBlkConfig blk;
VirtioScsiConfig scsi;
+ VirtioNetConfig net;
} config;
ScsiDevice *scsi_device;
bool is_cdrom;
@@ -278,6 +257,7 @@ struct VDev {
ScsiDevice selected_scsi_device;
uint64_t netboot_start_addr;
uint32_t max_transfer;
+ uint32_t guest_features[2];
};
typedef struct VDev VDev;
@@ -291,6 +271,14 @@ struct VirtioCmd {
};
typedef struct VirtioCmd VirtioCmd;
+bool vring_notify(VRing *vr);
+int drain_irqs(SubChannelId schid);
+void vring_send_buf(VRing *vr, void *p, int len, int flags);
+int vr_poll(VRing *vr);
+int vring_wait_reply(void);
int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd);
+void virtio_setup_ccw(VDev *vdev);
+
+int virtio_net_init(void *mac_addr);
#endif /* VIRTIO_H */
diff --git a/pc-bios/s390-netboot.img b/pc-bios/s390-netboot.img
new file mode 100755
index 0000000000..295ddfcf6a
--- /dev/null
+++ b/pc-bios/s390-netboot.img
Binary files differ
diff --git a/pc-bios/u-boot.e500 b/pc-bios/u-boot.e500
index 6e547de6f9..25537f8fe3 100755
--- a/pc-bios/u-boot.e500
+++ b/pc-bios/u-boot.e500
Binary files differ
diff --git a/qapi-schema.json b/qapi-schema.json
index 37c4b95aad..ab438ead70 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2431,8 +2431,6 @@
# Since: 0.14.0
#
# Returns: If successful, nothing
-# If QEMU was started with an encrypted block device and a key has
-# not yet been set, DeviceEncrypted.
#
# Notes: This command will succeed if the guest is currently running. It
# will also succeed if the guest is in the "inmigrate" state; in
@@ -2713,8 +2711,7 @@
# * This command is stateless, this means that commands that depend
# on state information (such as getfd) might not work
#
-# * Commands that prompt the user for data (eg. 'cont' when the block
-# device is encrypted) don't currently work
+# * Commands that prompt the user for data don't currently work
#
# Example:
#
@@ -3019,11 +3016,6 @@
#
# Returns: Nothing on success.
# If @device is not a valid block device, DeviceNotFound
-# If the new block device is encrypted, DeviceEncrypted. Note that
-# if this error is returned, the device has been opened successfully
-# and an additional call to @block_passwd is required to set the
-# device's password. The behavior of reads and writes to the block
-# device between when these calls are executed is undefined.
#
# Notes: This interface is deprecated, and it is strongly recommended that you
# avoid using it. For changing block devices, use
@@ -5098,6 +5090,46 @@
'returns': 'ChardevReturn' }
##
+# @chardev-change:
+#
+# Change a character device backend
+#
+# @id: the chardev's ID, must exist
+# @backend: new backend type and parameters
+#
+# Returns: ChardevReturn.
+#
+# Since: 2.10
+#
+# Example:
+#
+# -> { "execute" : "chardev-change",
+# "arguments" : { "id" : "baz",
+# "backend" : { "type" : "pty", "data" : {} } } }
+# <- { "return": { "pty" : "/dev/pty/42" } }
+#
+# -> {"execute" : "chardev-change",
+# "arguments" : {
+# "id" : "charchannel2",
+# "backend" : {
+# "type" : "socket",
+# "data" : {
+# "addr" : {
+# "type" : "unix" ,
+# "data" : {
+# "path" : "/tmp/charchannel2.socket"
+# }
+# },
+# "server" : true,
+# "wait" : false }}}}
+# <- {"return": {}}
+#
+##
+{ 'command': 'chardev-change', 'data': {'id' : 'str',
+ 'backend' : 'ChardevBackend' },
+ 'returns': 'ChardevReturn' }
+
+##
# @chardev-remove:
#
# Remove a character device backend
diff --git a/qapi/block-core.json b/qapi/block-core.json
index f85c2235c7..c437aa50ef 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -33,6 +33,27 @@
'vm-clock-sec': 'int', 'vm-clock-nsec': 'int' } }
##
+# @ImageInfoSpecificQCow2EncryptionBase:
+#
+# @format: The encryption format
+#
+# Since: 2.10
+##
+{ 'struct': 'ImageInfoSpecificQCow2EncryptionBase',
+ 'data': { 'format': 'BlockdevQcow2EncryptionFormat'}}
+
+##
+# @ImageInfoSpecificQCow2Encryption:
+#
+# Since: 2.10
+##
+{ 'union': 'ImageInfoSpecificQCow2Encryption',
+ 'base': 'ImageInfoSpecificQCow2EncryptionBase',
+ 'discriminator': 'format',
+ 'data': { 'aes': 'QCryptoBlockInfoQCow',
+ 'luks': 'QCryptoBlockInfoLUKS' } }
+
+##
# @ImageInfoSpecificQCow2:
#
# @compat: compatibility level
@@ -44,6 +65,9 @@
#
# @refcount-bits: width of a refcount entry in bits (since 2.3)
#
+# @encrypt: details about encryption parameters; only set if image
+# is encrypted (since 2.10)
+#
# Since: 1.7
##
{ 'struct': 'ImageInfoSpecificQCow2',
@@ -51,7 +75,8 @@
'compat': 'str',
'*lazy-refcounts': 'bool',
'*corrupt': 'bool',
- 'refcount-bits': 'int'
+ 'refcount-bits': 'int',
+ '*encrypt': 'ImageInfoSpecificQCow2Encryption'
} }
##
@@ -259,8 +284,7 @@
#
# @encrypted: true if the backing device is encrypted
#
-# @encryption_key_missing: true if the backing device is encrypted but an
-# valid encryption key is missing
+# @encryption_key_missing: Deprecated; always false
#
# @detect_zeroes: detect and optimize zero writes (Since 2.1)
#
@@ -464,6 +488,31 @@
'*dirty-bitmaps': ['BlockDirtyInfo'] } }
##
+# @BlockMeasureInfo:
+#
+# Image file size calculation information. This structure describes the size
+# requirements for creating a new image file.
+#
+# The size requirements depend on the new image file format. File size always
+# equals virtual disk size for the 'raw' format, even for sparse POSIX files.
+# Compact formats such as 'qcow2' represent unallocated and zero regions
+# efficiently so file size may be smaller than virtual disk size.
+#
+# The values are upper bounds that are guaranteed to fit the new image file.
+# Subsequent modification, such as internal snapshot or bitmap creation, may
+# require additional space and is not covered here.
+#
+# @required: Size required for a new image file, in bytes.
+#
+# @fully-allocated: Image file size, in bytes, once data has been written
+# to all sectors.
+#
+# Since: 2.10
+##
+{ 'struct': 'BlockMeasureInfo',
+ 'data': {'required': 'int', 'fully-allocated': 'int'} }
+
+##
# @query-block:
#
# Get a list of BlockInfo for all virtual block devices.
@@ -946,39 +995,7 @@
# This command sets the password of a block device that has not been open
# with a password and requires one.
#
-# The two cases where this can happen are a block device is created through
-# QEMU's initial command line or a block device is changed through the legacy
-# @change interface.
-#
-# In the event that the block device is created through the initial command
-# line, the VM will start in the stopped state regardless of whether '-S' is
-# used. The intention is for a management tool to query the block devices to
-# determine which ones are encrypted, set the passwords with this command, and
-# then start the guest with the @cont command.
-#
-# Either @device or @node-name must be set but not both.
-#
-# @device: the name of the block backend device to set the password on
-#
-# @node-name: graph node name to set the password on (Since 2.0)
-#
-# @password: the password to use for the device
-#
-# Returns: nothing on success
-# If @device is not a valid block device, DeviceNotFound
-# If @device is not encrypted, DeviceNotEncrypted
-#
-# Notes: Not all block formats support encryption and some that do are not
-# able to validate that a password is correct. Disk corruption may
-# occur if an invalid password is specified.
-#
-# Since: 0.14.0
-#
-# Example:
-#
-# -> { "execute": "block_passwd", "arguments": { "device": "ide0-hd0",
-# "password": "12345" } }
-# <- { "return": {} }
+# This command is now obsolete and will always return an error since 2.10
#
##
{ 'command': 'block_passwd', 'data': {'*device': 'str',
@@ -1561,10 +1578,20 @@
# @granularity: the bitmap granularity, default is 64k for
# block-dirty-bitmap-add
#
+# @persistent: the bitmap is persistent, i.e. it will be saved to the
+# corresponding block device image file on its close. For now only
+# Qcow2 disks support persistent bitmaps. Default is false for
+# block-dirty-bitmap-add. (Since: 2.10)
+#
+# @autoload: the bitmap will be automatically loaded when the image it is stored
+# in is opened. This flag may only be specified for persistent
+# bitmaps. Default is false for block-dirty-bitmap-add. (Since: 2.10)
+#
# Since: 2.4
##
{ 'struct': 'BlockDirtyBitmapAdd',
- 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32' } }
+ 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32',
+ '*persistent': 'bool', '*autoload': 'bool' } }
##
# @block-dirty-bitmap-add:
@@ -1591,7 +1618,8 @@
# @block-dirty-bitmap-remove:
#
# Stop write tracking and remove the dirty bitmap that was created
-# with block-dirty-bitmap-add.
+# with block-dirty-bitmap-add. If the bitmap is persistent, remove it from its
+# storage too.
#
# Returns: nothing on success
# If @node is not a valid block device or node, DeviceNotFound
@@ -1634,6 +1662,33 @@
'data': 'BlockDirtyBitmap' }
##
+# @BlockDirtyBitmapSha256:
+#
+# SHA256 hash of dirty bitmap data
+#
+# @sha256: ASCII representation of SHA256 bitmap hash
+#
+# Since: 2.10
+##
+ { 'struct': 'BlockDirtyBitmapSha256',
+ 'data': {'sha256': 'str'} }
+
+##
+# @x-debug-block-dirty-bitmap-sha256:
+#
+# Get bitmap SHA256
+#
+# Returns: BlockDirtyBitmapSha256 on success
+# If @node is not a valid block device, DeviceNotFound
+# If @name is not found or if hashing has failed, GenericError with an
+# explanation
+#
+# Since: 2.10
+##
+ { 'command': 'x-debug-block-dirty-bitmap-sha256',
+ 'data': 'BlockDirtyBitmap', 'returns': 'BlockDirtyBitmapSha256' }
+
+##
# @blockdev-mirror:
#
# Start mirroring a block device's writes to a new destination.
@@ -2282,6 +2337,63 @@
'mode': 'Qcow2OverlapCheckMode' } }
##
+# @BlockdevQcowEncryptionFormat:
+#
+# @aes: AES-CBC with plain64 initialization vectors
+#
+# Since: 2.10
+##
+{ 'enum': 'BlockdevQcowEncryptionFormat',
+ 'data': [ 'aes' ] }
+
+##
+# @BlockdevQcowEncryption:
+#
+# Since: 2.10
+##
+{ 'union': 'BlockdevQcowEncryption',
+ 'base': { 'format': 'BlockdevQcowEncryptionFormat' },
+ 'discriminator': 'format',
+ 'data': { 'aes': 'QCryptoBlockOptionsQCow' } }
+
+##
+# @BlockdevOptionsQcow:
+#
+# Driver specific block device options for qcow.
+#
+# @encrypt: Image decryption options. Mandatory for
+# encrypted images, except when doing a metadata-only
+# probe of the image.
+#
+# Since: 2.10
+##
+{ 'struct': 'BlockdevOptionsQcow',
+ 'base': 'BlockdevOptionsGenericCOWFormat',
+ 'data': { '*encrypt': 'BlockdevQcowEncryption' } }
+
+
+
+##
+# @BlockdevQcow2EncryptionFormat:
+# @aes: AES-CBC with plain64 initialization venctors
+#
+# Since: 2.10
+##
+{ 'enum': 'BlockdevQcow2EncryptionFormat',
+ 'data': [ 'aes', 'luks' ] }
+
+##
+# @BlockdevQcow2Encryption:
+#
+# Since: 2.10
+##
+{ 'union': 'BlockdevQcow2Encryption',
+ 'base': { 'format': 'BlockdevQcow2EncryptionFormat' },
+ 'discriminator': 'format',
+ 'data': { 'aes': 'QCryptoBlockOptionsQCow',
+ 'luks': 'QCryptoBlockOptionsLUKS'} }
+
+##
# @BlockdevOptionsQcow2:
#
# Driver specific block device options for qcow2.
@@ -2315,6 +2427,9 @@
# @cache-clean-interval: clean unused entries in the L2 and refcount
# caches. The interval is in seconds. The default value
# is 0 and it disables this feature (since 2.5)
+# @encrypt: Image decryption options. Mandatory for
+# encrypted images, except when doing a metadata-only
+# probe of the image. (since 2.10)
#
# Since: 2.9
##
@@ -2328,8 +2443,8 @@
'*cache-size': 'int',
'*l2-cache-size': 'int',
'*refcount-cache-size': 'int',
- '*cache-clean-interval': 'int' } }
-
+ '*cache-clean-interval': 'int',
+ '*encrypt': 'BlockdevQcow2Encryption' } }
##
# @BlockdevOptionsSsh:
@@ -2976,7 +3091,7 @@
'null-co': 'BlockdevOptionsNull',
'parallels': 'BlockdevOptionsGenericFormat',
'qcow2': 'BlockdevOptionsQcow2',
- 'qcow': 'BlockdevOptionsGenericCOWFormat',
+ 'qcow': 'BlockdevOptionsQcow',
'qed': 'BlockdevOptionsGenericCOWFormat',
'quorum': 'BlockdevOptionsQuorum',
'raw': 'BlockdevOptionsRaw',
diff --git a/qapi/common.json b/qapi/common.json
index b626647b2f..8355d5a2f3 100644
--- a/qapi/common.json
+++ b/qapi/common.json
@@ -14,9 +14,6 @@
#
# @CommandNotFound: the requested command has not been found
#
-# @DeviceEncrypted: the requested operation can't be fulfilled because the
-# selected device is encrypted
-#
# @DeviceNotActive: a device has failed to be become active
#
# @DeviceNotFound: the requested device has not been found
@@ -28,7 +25,7 @@
##
{ 'enum': 'QapiErrorClass',
# Keep this in sync with ErrorClass in error.h
- 'data': [ 'GenericError', 'CommandNotFound', 'DeviceEncrypted',
+ 'data': [ 'GenericError', 'CommandNotFound',
'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap' ] }
##
diff --git a/qemu-doc.texi b/qemu-doc.texi
index d2986cba50..48af5155c7 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -540,10 +540,20 @@ File name of a base image (see @option{create} subcommand)
@item backing_fmt
Image format of the base image
@item encryption
-If this option is set to @code{on}, the image is encrypted with 128-bit AES-CBC.
+This option is deprecated and equivalent to @code{encrypt.format=aes}
-The use of encryption in qcow and qcow2 images is considered to be flawed by
-modern cryptography standards, suffering from a number of design problems:
+@item encrypt.format
+
+If this is set to @code{luks}, it requests that the qcow2 payload (not
+qcow2 header) be encrypted using the LUKS format. The passphrase to
+use to unlock the LUKS key slot is given by the @code{encrypt.key-secret}
+parameter. LUKS encryption parameters can be tuned with the other
+@code{encrypt.*} parameters.
+
+If this is set to @code{aes}, the image is encrypted with 128-bit AES-CBC.
+The encryption key is given by the @code{encrypt.key-secret} parameter.
+This encryption format is considered to be flawed by modern cryptography
+standards, suffering from a number of design problems:
@itemize @minus
@item The AES-CBC cipher is used with predictable initialization vectors based
@@ -558,10 +568,45 @@ original file must then be securely erased using a program like shred,
though even this is ineffective with many modern storage technologies.
@end itemize
-Use of qcow / qcow2 encryption with QEMU is deprecated, and support for
-it will go away in a future release. Users are recommended to use an
-alternative encryption technology such as the Linux dm-crypt / LUKS
-system.
+The use of this is no longer supported in system emulators. Support only
+remains in the command line utilities, for the purposes of data liberation
+and interoperability with old versions of QEMU. The @code{luks} format
+should be used instead.
+
+@item encrypt.key-secret
+
+Provides the ID of a @code{secret} object that contains the passphrase
+(@code{encrypt.format=luks}) or encryption key (@code{encrypt.format=aes}).
+
+@item encrypt.cipher-alg
+
+Name of the cipher algorithm and key length. Currently defaults
+to @code{aes-256}. Only used when @code{encrypt.format=luks}.
+
+@item encrypt.cipher-mode
+
+Name of the encryption mode to use. Currently defaults to @code{xts}.
+Only used when @code{encrypt.format=luks}.
+
+@item encrypt.ivgen-alg
+
+Name of the initialization vector generator algorithm. Currently defaults
+to @code{plain64}. Only used when @code{encrypt.format=luks}.
+
+@item encrypt.ivgen-hash-alg
+
+Name of the hash algorithm to use with the initialization vector generator
+(if required). Defaults to @code{sha256}. Only used when @code{encrypt.format=luks}.
+
+@item encrypt.hash-alg
+
+Name of the hash algorithm to use for PBKDF algorithm
+Defaults to @code{sha256}. Only used when @code{encrypt.format=luks}.
+
+@item encrypt.iter-time
+
+Amount of time, in milliseconds, to use for PBKDF algorithm per key slot.
+Defaults to @code{2000}. Only used when @code{encrypt.format=luks}.
@item cluster_size
Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster
@@ -636,7 +681,69 @@ Supported options:
@item backing_file
File name of a base image (see @option{create} subcommand)
@item encryption
-If this option is set to @code{on}, the image is encrypted.
+This option is deprecated and equivalent to @code{encrypt.format=aes}
+
+@item encrypt.format
+If this is set to @code{aes}, the image is encrypted with 128-bit AES-CBC.
+The encryption key is given by the @code{encrypt.key-secret} parameter.
+This encryption format is considered to be flawed by modern cryptography
+standards, suffering from a number of design problems enumerated previously
+against the @code{qcow2} image format.
+
+The use of this is no longer supported in system emulators. Support only
+remains in the command line utilities, for the purposes of data liberation
+and interoperability with old versions of QEMU.
+
+Users requiring native encryption should use the @code{qcow2} format
+instead with @code{encrypt.format=luks}.
+
+@item encrypt.key-secret
+
+Provides the ID of a @code{secret} object that contains the encryption
+key (@code{encrypt.format=aes}).
+
+@end table
+
+@item luks
+
+LUKS v1 encryption format, compatible with Linux dm-crypt/cryptsetup
+
+Supported options:
+@table @code
+
+@item key-secret
+
+Provides the ID of a @code{secret} object that contains the passphrase.
+
+@item cipher-alg
+
+Name of the cipher algorithm and key length. Currently defaults
+to @code{aes-256}.
+
+@item cipher-mode
+
+Name of the encryption mode to use. Currently defaults to @code{xts}.
+
+@item ivgen-alg
+
+Name of the initialization vector generator algorithm. Currently defaults
+to @code{plain64}.
+
+@item ivgen-hash-alg
+
+Name of the hash algorithm to use with the initialization vector generator
+(if required). Defaults to @code{sha256}.
+
+@item hash-alg
+
+Name of the hash algorithm to use for PBKDF algorithm
+Defaults to @code{sha256}.
+
+@item iter-time
+
+Amount of time, in milliseconds, to use for PBKDF algorithm per key slot.
+Defaults to @code{2000}.
+
@end table
@item vdi
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index a39fcdba71..ac5946bc4f 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -63,6 +63,12 @@ STEXI
@item map [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] [-U] @var{filename}
ETEXI
+DEF("measure", img_measure,
+"measure [--output=ofmt] [-O output_fmt] [-o options] [--size N | [--object objectdef] [--image-opts] [-f fmt] [-l snapshot_param] filename]")
+STEXI
+@item measure [--output=@var{ofmt}] [-O @var{output_fmt}] [-o @var{options}] [--size @var{N} | [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [-l @var{snapshot_param}] @var{filename}]
+ETEXI
+
DEF("snapshot", img_snapshot,
"snapshot [--object objectdef] [--image-opts] [-U] [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename")
STEXI
diff --git a/qemu-img.c b/qemu-img.c
index f7ffb79db6..182e697f81 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -24,6 +24,7 @@
#include "qemu/osdep.h"
#include "qemu-version.h"
#include "qapi/error.h"
+#include "qapi/util.h"
#include "qapi-visit.h"
#include "qapi/qobject-output-visitor.h"
#include "qapi/qmp/qerror.h"
@@ -61,6 +62,8 @@ enum {
OPTION_FLUSH_INTERVAL = 261,
OPTION_NO_DRAIN = 262,
OPTION_TARGET_IMAGE_OPTS = 263,
+ OPTION_SIZE = 264,
+ OPTION_PREALLOCATION = 265,
};
typedef enum OutputFormat {
@@ -260,29 +263,6 @@ static int print_block_option_help(const char *filename, const char *fmt)
}
-static int img_open_password(BlockBackend *blk, const char *filename,
- int flags, bool quiet)
-{
- BlockDriverState *bs;
- char password[256];
-
- bs = blk_bs(blk);
- if (bdrv_is_encrypted(bs) && bdrv_key_required(bs) &&
- !(flags & BDRV_O_NO_IO)) {
- qprintf(quiet, "Disk image '%s' is encrypted.\n", filename);
- if (qemu_read_password(password, sizeof(password)) < 0) {
- error_report("No password given");
- return -1;
- }
- if (bdrv_set_key(bs, password) < 0) {
- error_report("invalid password");
- return -1;
- }
- }
- return 0;
-}
-
-
static BlockBackend *img_open_opts(const char *optstr,
QemuOpts *opts, int flags, bool writethrough,
bool quiet, bool force_share)
@@ -307,10 +287,6 @@ static BlockBackend *img_open_opts(const char *optstr,
}
blk_set_enable_write_cache(blk, !writethrough);
- if (img_open_password(blk, optstr, flags, quiet) < 0) {
- blk_unref(blk);
- return NULL;
- }
return blk;
}
@@ -340,10 +316,6 @@ static BlockBackend *img_open_file(const char *filename,
}
blk_set_enable_write_cache(blk, !writethrough);
- if (img_open_password(blk, filename, flags, quiet) < 0) {
- blk_unref(blk);
- return NULL;
- }
return blk;
}
@@ -355,7 +327,7 @@ static int img_add_key_secrets(void *opaque,
QDict *options = opaque;
if (g_str_has_suffix(name, "key-secret")) {
- qdict_put(options, name, qstring_from_str(value));
+ qdict_put_str(options, name, value);
}
return 0;
@@ -2264,6 +2236,8 @@ static int img_convert(int argc, char **argv)
if (s.compressed) {
bool encryption =
qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, false);
+ const char *encryptfmt =
+ qemu_opt_get(opts, BLOCK_OPT_ENCRYPT_FORMAT);
const char *preallocation =
qemu_opt_get(opts, BLOCK_OPT_PREALLOC);
@@ -2273,7 +2247,7 @@ static int img_convert(int argc, char **argv)
goto out;
}
- if (encryption) {
+ if (encryption || encryptfmt) {
error_report("Compression and encryption not supported at "
"the same time");
ret = -1;
@@ -3436,9 +3410,10 @@ static int img_resize(int argc, char **argv)
Error *err = NULL;
int c, ret, relative;
const char *filename, *fmt, *size;
- int64_t n, total_size;
+ int64_t n, total_size, current_size;
bool quiet = false;
BlockBackend *blk = NULL;
+ PreallocMode prealloc = PREALLOC_MODE_OFF;
QemuOpts *param;
static QemuOptsList resize_options = {
@@ -3472,6 +3447,7 @@ static int img_resize(int argc, char **argv)
{"help", no_argument, 0, 'h'},
{"object", required_argument, 0, OPTION_OBJECT},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"preallocation", required_argument, 0, OPTION_PREALLOCATION},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, ":f:hq",
@@ -3506,6 +3482,15 @@ static int img_resize(int argc, char **argv)
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
+ case OPTION_PREALLOCATION:
+ prealloc = qapi_enum_parse(PreallocMode_lookup, optarg,
+ PREALLOC_MODE__MAX, PREALLOC_MODE__MAX,
+ NULL);
+ if (prealloc == PREALLOC_MODE__MAX) {
+ error_report("Invalid preallocation mode '%s'", optarg);
+ return 1;
+ }
+ break;
}
}
if (optind != argc - 1) {
@@ -3554,8 +3539,16 @@ static int img_resize(int argc, char **argv)
goto out;
}
+ current_size = blk_getlength(blk);
+ if (current_size < 0) {
+ error_report("Failed to inquire current image length: %s",
+ strerror(-current_size));
+ ret = -1;
+ goto out;
+ }
+
if (relative) {
- total_size = blk_getlength(blk) + n * relative;
+ total_size = current_size + n * relative;
} else {
total_size = n;
}
@@ -3565,7 +3558,13 @@ static int img_resize(int argc, char **argv)
goto out;
}
- ret = blk_truncate(blk, total_size, &err);
+ if (total_size <= current_size && prealloc != PREALLOC_MODE_OFF) {
+ error_report("Preallocation can only be used for growing images");
+ ret = -1;
+ goto out;
+ }
+
+ ret = blk_truncate(blk, total_size, prealloc, &err);
if (!ret) {
qprintf(quiet, "Image resized.\n");
} else {
@@ -4448,6 +4447,239 @@ out:
return 0;
}
+static void dump_json_block_measure_info(BlockMeasureInfo *info)
+{
+ QString *str;
+ QObject *obj;
+ Visitor *v = qobject_output_visitor_new(&obj);
+
+ visit_type_BlockMeasureInfo(v, NULL, &info, &error_abort);
+ visit_complete(v, &obj);
+ str = qobject_to_json_pretty(obj);
+ assert(str != NULL);
+ printf("%s\n", qstring_get_str(str));
+ qobject_decref(obj);
+ visit_free(v);
+ QDECREF(str);
+}
+
+static int img_measure(int argc, char **argv)
+{
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"object", required_argument, 0, OPTION_OBJECT},
+ {"output", required_argument, 0, OPTION_OUTPUT},
+ {"size", required_argument, 0, OPTION_SIZE},
+ {"force-share", no_argument, 0, 'U'},
+ {0, 0, 0, 0}
+ };
+ OutputFormat output_format = OFORMAT_HUMAN;
+ BlockBackend *in_blk = NULL;
+ BlockDriver *drv;
+ const char *filename = NULL;
+ const char *fmt = NULL;
+ const char *out_fmt = "raw";
+ char *options = NULL;
+ char *snapshot_name = NULL;
+ bool force_share = false;
+ QemuOpts *opts = NULL;
+ QemuOpts *object_opts = NULL;
+ QemuOpts *sn_opts = NULL;
+ QemuOptsList *create_opts = NULL;
+ bool image_opts = false;
+ uint64_t img_size = UINT64_MAX;
+ BlockMeasureInfo *info = NULL;
+ Error *local_err = NULL;
+ int ret = 1;
+ int c;
+
+ while ((c = getopt_long(argc, argv, "hf:O:o:l:U",
+ long_options, NULL)) != -1) {
+ switch (c) {
+ case '?':
+ case 'h':
+ help();
+ break;
+ case 'f':
+ fmt = optarg;
+ break;
+ case 'O':
+ out_fmt = optarg;
+ break;
+ case 'o':
+ if (!is_valid_option_list(optarg)) {
+ error_report("Invalid option list: %s", optarg);
+ goto out;
+ }
+ if (!options) {
+ options = g_strdup(optarg);
+ } else {
+ char *old_options = options;
+ options = g_strdup_printf("%s,%s", options, optarg);
+ g_free(old_options);
+ }
+ break;
+ case 'l':
+ if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {
+ sn_opts = qemu_opts_parse_noisily(&internal_snapshot_opts,
+ optarg, false);
+ if (!sn_opts) {
+ error_report("Failed in parsing snapshot param '%s'",
+ optarg);
+ goto out;
+ }
+ } else {
+ snapshot_name = optarg;
+ }
+ break;
+ case 'U':
+ force_share = true;
+ break;
+ case OPTION_OBJECT:
+ object_opts = qemu_opts_parse_noisily(&qemu_object_opts,
+ optarg, true);
+ if (!object_opts) {
+ goto out;
+ }
+ break;
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
+ break;
+ case OPTION_OUTPUT:
+ if (!strcmp(optarg, "json")) {
+ output_format = OFORMAT_JSON;
+ } else if (!strcmp(optarg, "human")) {
+ output_format = OFORMAT_HUMAN;
+ } else {
+ error_report("--output must be used with human or json "
+ "as argument.");
+ goto out;
+ }
+ break;
+ case OPTION_SIZE:
+ {
+ int64_t sval;
+
+ sval = cvtnum(optarg);
+ if (sval < 0) {
+ if (sval == -ERANGE) {
+ error_report("Image size must be less than 8 EiB!");
+ } else {
+ error_report("Invalid image size specified! You may use "
+ "k, M, G, T, P or E suffixes for ");
+ error_report("kilobytes, megabytes, gigabytes, terabytes, "
+ "petabytes and exabytes.");
+ }
+ goto out;
+ }
+ img_size = (uint64_t)sval;
+ }
+ break;
+ }
+ }
+
+ if (qemu_opts_foreach(&qemu_object_opts,
+ user_creatable_add_opts_foreach,
+ NULL, NULL)) {
+ goto out;
+ }
+
+ if (argc - optind > 1) {
+ error_report("At most one filename argument is allowed.");
+ goto out;
+ } else if (argc - optind == 1) {
+ filename = argv[optind];
+ }
+
+ if (!filename &&
+ (object_opts || image_opts || fmt || snapshot_name || sn_opts)) {
+ error_report("--object, --image-opts, -f, and -l "
+ "require a filename argument.");
+ goto out;
+ }
+ if (filename && img_size != UINT64_MAX) {
+ error_report("--size N cannot be used together with a filename.");
+ goto out;
+ }
+ if (!filename && img_size == UINT64_MAX) {
+ error_report("Either --size N or one filename must be specified.");
+ goto out;
+ }
+
+ if (filename) {
+ in_blk = img_open(image_opts, filename, fmt, 0,
+ false, false, force_share);
+ if (!in_blk) {
+ goto out;
+ }
+
+ if (sn_opts) {
+ bdrv_snapshot_load_tmp(blk_bs(in_blk),
+ qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
+ qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
+ &local_err);
+ } else if (snapshot_name != NULL) {
+ bdrv_snapshot_load_tmp_by_id_or_name(blk_bs(in_blk),
+ snapshot_name, &local_err);
+ }
+ if (local_err) {
+ error_reportf_err(local_err, "Failed to load snapshot: ");
+ goto out;
+ }
+ }
+
+ drv = bdrv_find_format(out_fmt);
+ if (!drv) {
+ error_report("Unknown file format '%s'", out_fmt);
+ goto out;
+ }
+ if (!drv->create_opts) {
+ error_report("Format driver '%s' does not support image creation",
+ drv->format_name);
+ goto out;
+ }
+
+ create_opts = qemu_opts_append(create_opts, drv->create_opts);
+ create_opts = qemu_opts_append(create_opts, bdrv_file.create_opts);
+ opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
+ if (options) {
+ qemu_opts_do_parse(opts, options, NULL, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ error_report("Invalid options for file format '%s'", out_fmt);
+ goto out;
+ }
+ }
+ if (img_size != UINT64_MAX) {
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, &error_abort);
+ }
+
+ info = bdrv_measure(drv, opts, in_blk ? blk_bs(in_blk) : NULL, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ goto out;
+ }
+
+ if (output_format == OFORMAT_HUMAN) {
+ printf("required size: %" PRIu64 "\n", info->required);
+ printf("fully allocated size: %" PRIu64 "\n", info->fully_allocated);
+ } else {
+ dump_json_block_measure_info(info);
+ }
+
+ ret = 0;
+
+out:
+ qapi_free_BlockMeasureInfo(info);
+ qemu_opts_del(object_opts);
+ qemu_opts_del(opts);
+ qemu_opts_del(sn_opts);
+ qemu_opts_free(create_opts);
+ g_free(options);
+ blk_unref(in_blk);
+ return ret;
+}
static const img_cmd_t img_cmds[] = {
#define DEF(option, callback, arg_string) \
diff --git a/qemu-img.texi b/qemu-img.texi
index 5b925ecf41..f11f6036ad 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -438,6 +438,36 @@ preallocated.
For more information, consult @file{include/block/block.h} in QEMU's
source code.
+@item measure [--output=@var{ofmt}] [-O @var{output_fmt}] [-o @var{options}] [--size @var{N} | [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [-l @var{snapshot_param}] @var{filename}]
+
+Calculate the file size required for a new image. This information can be used
+to size logical volumes or SAN LUNs appropriately for the image that will be
+placed in them. The values reported are guaranteed to be large enough to fit
+the image. The command can output in the format @var{ofmt} which is either
+@code{human} or @code{json}.
+
+If the size @var{N} is given then act as if creating a new empty image file
+using @command{qemu-img create}. If @var{filename} is given then act as if
+converting an existing image file using @command{qemu-img convert}. The format
+of the new file is given by @var{output_fmt} while the format of an existing
+file is given by @var{fmt}.
+
+A snapshot in an existing image can be specified using @var{snapshot_param}.
+
+The following fields are reported:
+@example
+required size: 524288
+fully allocated size: 1074069504
+@end example
+
+The @code{required size} is the file size of the new image. It may be smaller
+than the virtual disk size if the image format supports compact representation.
+
+The @code{fully allocated size} is the file size of the new image once data has
+been written to all sectors. This is the maximum size that the image file can
+occupy with the exception of internal snapshots, dirty bitmaps, vmstate data,
+and other advanced image format features.
+
@item snapshot [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot} ] @var{filename}
List, apply, create or delete snapshots in image @var{filename}.
@@ -499,7 +529,7 @@ qemu-img rebase -b base.img diff.qcow2
At this point, @code{modified.img} can be discarded, since
@code{base.img + diff.qcow2} contains the same information.
-@item resize @var{filename} [+ | -]@var{size}
+@item resize [--preallocation=@var{prealloc}] @var{filename} [+ | -]@var{size}
Change the disk image as if it had been created with @var{size}.
@@ -511,6 +541,11 @@ After using this command to grow a disk image, you must use file system and
partitioning tools inside the VM to actually begin using the new space on the
device.
+When growing an image, the @code{--preallocation} option may be used to specify
+how the additional image area should be allocated on the host. See the format
+description in the @code{NOTES} section which values are allowed. Using this
+option may result in slightly more data being allocated than necessary.
+
@item amend [-p] [-f @var{fmt}] [-t @var{cache}] -o @var{options} @var{filename}
Amends the image format specific @var{options} for the image file
@@ -567,16 +602,29 @@ The use of encryption in qcow and qcow2 images is considered to be flawed by
modern cryptography standards, suffering from a number of design problems:
@itemize @minus
-@item The AES-CBC cipher is used with predictable initialization vectors based
+@item
+The AES-CBC cipher is used with predictable initialization vectors based
on the sector number. This makes it vulnerable to chosen plaintext attacks
which can reveal the existence of encrypted data.
-@item The user passphrase is directly used as the encryption key. A poorly
+@item
+The user passphrase is directly used as the encryption key. A poorly
chosen or short passphrase will compromise the security of the encryption.
-@item In the event of the passphrase being compromised there is no way to
+@item
+In the event of the passphrase being compromised there is no way to
change the passphrase to protect data in any qcow images. The files must
be cloned, using a different encryption passphrase in the new file. The
original file must then be securely erased using a program like shred,
though even this is ineffective with many modern storage technologies.
+@item
+Initialization vectors used to encrypt sectors are based on the
+guest virtual sector number, instead of the host physical sector. When
+a disk image has multiple internal snapshots this means that data in
+multiple physical sectors is encrypted with the same initialization
+vector. With the CBC mode, this opens the possibility of watermarking
+attacks if the attack can collect multiple sectors encrypted with the
+same IV and some predictable data. Having multiple qcow2 images with
+the same passphrase also exposes this weakness since the passphrase
+is directly used as the key.
@end itemize
Use of qcow / qcow2 encryption is thus strongly discouraged. Users are
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index f4fdf2dcce..3eb42c6728 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -1577,7 +1577,7 @@ static int truncate_f(BlockBackend *blk, int argc, char **argv)
return 0;
}
- ret = blk_truncate(blk, offset, &local_err);
+ ret = blk_truncate(blk, offset, PREALLOC_MODE_OFF, &local_err);
if (ret < 0) {
error_report_err(local_err);
return 0;
diff --git a/qemu-io.c b/qemu-io.c
index 8074656b7c..4cfa41c8f9 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -58,7 +58,6 @@ static int openfile(char *name, int flags, bool writethrough, bool force_share,
QDict *opts)
{
Error *local_err = NULL;
- BlockDriverState *bs;
if (qemuio_blk) {
error_report("file open already, try 'help close'");
@@ -85,28 +84,9 @@ static int openfile(char *name, int flags, bool writethrough, bool force_share,
return 1;
}
- bs = blk_bs(qemuio_blk);
- if (bdrv_is_encrypted(bs) && bdrv_key_required(bs)) {
- char password[256];
- printf("Disk image '%s' is encrypted.\n", name);
- if (qemu_read_password(password, sizeof(password)) < 0) {
- error_report("No password given");
- goto error;
- }
- if (bdrv_set_key(bs, password) < 0) {
- error_report("invalid password");
- goto error;
- }
- }
-
blk_set_enable_write_cache(qemuio_blk, !writethrough);
return 0;
-
- error:
- blk_unref(qemuio_blk);
- qemuio_blk = NULL;
- return 1;
}
static void open_help(void)
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 4dd3fd4732..78d05bea2d 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -255,8 +255,7 @@ static void *show_parts(void *arg)
static void *nbd_client_thread(void *arg)
{
char *device = arg;
- off_t size;
- uint16_t nbdflags;
+ NBDExportInfo info = { .request_sizes = false, };
QIOChannelSocket *sioc;
int fd;
int ret;
@@ -271,9 +270,8 @@ static void *nbd_client_thread(void *arg)
goto out;
}
- ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), NULL, &nbdflags,
- NULL, NULL, NULL,
- &size, &local_error);
+ ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), NULL,
+ NULL, NULL, NULL, &info, &local_error);
if (ret < 0) {
if (local_error) {
error_report_err(local_error);
@@ -288,7 +286,7 @@ static void *nbd_client_thread(void *arg)
goto out_socket;
}
- ret = nbd_init(fd, sioc, nbdflags, size, &local_error);
+ ret = nbd_init(fd, sioc, &info, &local_error);
if (ret < 0) {
error_report_err(local_error);
goto out_fd;
diff --git a/qemu-options.hx b/qemu-options.hx
index 6909285e85..9bd6bf0eee 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4374,7 +4374,7 @@ The simplest (insecure) usage is to provide the secret inline
The simplest secure usage is to provide the secret via a file
- # echo -n "letmein" > mypasswd.txt
+ # printf "letmein" > mypasswd.txt
# $QEMU -object secret,id=sec0,file=mypasswd.txt,format=raw
For greater security, AES-256-CBC should be used. To illustrate usage,
@@ -4402,7 +4402,7 @@ telling openssl to base64 encode the result, but it could be left
as raw bytes if desired.
@example
- # SECRET=$(echo -n "letmein" |
+ # SECRET=$(printf "letmein" |
openssl enc -aes-256-cbc -a -K $KEY -iv $IV)
@end example
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 439d229225..6f1645747b 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -512,7 +512,7 @@ static GuestPCIAddress *get_pci_info(char *guid, Error **errp)
} else {
error_setg_win32(errp, GetLastError(),
"failed to get device name");
- goto out;
+ goto free_dev_info;
}
}
@@ -560,6 +560,9 @@ static GuestPCIAddress *get_pci_info(char *guid, Error **errp)
pci->bus = bus;
break;
}
+
+free_dev_info:
+ SetupDiDestroyDeviceInfoList(dev_info);
out:
g_free(buffer);
g_free(name);
diff --git a/qmp.c b/qmp.c
index 7ee9bcfdcf..2cd40c3080 100644
--- a/qmp.c
+++ b/qmp.c
@@ -164,10 +164,8 @@ SpiceInfo *qmp_query_spice(Error **errp)
void qmp_cont(Error **errp)
{
- Error *local_err = NULL;
BlockBackend *blk;
- BlockDriverState *bs;
- BdrvNextIterator it;
+ Error *local_err = NULL;
/* if there is a dump in background, we should wait until the dump
* finished */
@@ -187,14 +185,6 @@ void qmp_cont(Error **errp)
blk_iostatus_reset(blk);
}
- for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
- bdrv_add_key(bs, NULL, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- }
-
/* Continuing after completed migration. Images have been inactivated to
* allow the destination to take control. Need to get control back now.
*
@@ -490,13 +480,14 @@ static DevicePropertyInfo *make_device_property_info(ObjectClass *klass,
* for removal. This conditional should be removed along with
* it.
*/
- if (!prop->info->set) {
+ if (!prop->info->set && !prop->info->create) {
return NULL; /* no way to set it, don't show */
}
info = g_malloc0(sizeof(*info));
info->name = g_strdup(prop->name);
- info->type = g_strdup(prop->info->name);
+ info->type = default_type ? g_strdup(default_type)
+ : g_strdup(prop->info->name);
info->has_description = !!prop->info->description;
info->description = g_strdup(prop->info->description);
return info;
diff --git a/qom/cpu.c b/qom/cpu.c
index 8757f033a0..a39ff6c19c 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -458,6 +458,7 @@ static void cpu_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_CPU, dc->categories);
dc->realize = cpu_common_realizefn;
dc->unrealize = cpu_common_unrealizefn;
+ dc->props = cpu_common_props;
/*
* Reason: CPUs still need special care by board code: wiring up
* IRQs, adding reset handlers, halting non-first CPUs, ...
diff --git a/qom/object.c b/qom/object.c
index 5f6fdfa6e6..dfdbd50f04 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -740,7 +740,7 @@ out:
return ret;
}
-const char *object_get_typename(Object *obj)
+const char *object_get_typename(const Object *obj)
{
return obj->class->type->name;
}
@@ -1428,7 +1428,7 @@ out:
g_free(type);
}
-void object_property_allow_set_link(Object *obj, const char *name,
+void object_property_allow_set_link(const Object *obj, const char *name,
Object *val, Error **errp)
{
/* Allow the link to be set, always */
@@ -1436,7 +1436,7 @@ void object_property_allow_set_link(Object *obj, const char *name,
typedef struct {
Object **child;
- void (*check)(Object *, const char *, Object *, Error **);
+ void (*check)(const Object *, const char *, Object *, Error **);
ObjectPropertyLinkFlags flags;
} LinkProperty;
@@ -1552,7 +1552,7 @@ static void object_release_link_property(Object *obj, const char *name,
void object_property_add_link(Object *obj, const char *name,
const char *type, Object **child,
- void (*check)(Object *, const char *,
+ void (*check)(const Object *, const char *,
Object *, Error **),
ObjectPropertyLinkFlags flags,
Error **errp)
diff --git a/qtest.c b/qtest.c
index 9a5d1dc50d..88a09e9afc 100644
--- a/qtest.c
+++ b/qtest.c
@@ -691,7 +691,7 @@ void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp)
qemu_chr_fe_init(&qtest_chr, chr, errp);
qemu_chr_fe_set_handlers(&qtest_chr, qtest_can_read, qtest_read,
- qtest_event, &qtest_chr, NULL, true);
+ qtest_event, NULL, &qtest_chr, NULL, true);
qemu_chr_fe_set_echo(&qtest_chr, true);
inbuf = g_string_new("");
diff --git a/roms/SLOF b/roms/SLOF
-Subproject 66d250ef0fd06bb88b7399b9563b5008201f2d6
+Subproject 834113a1c67d6fb53dea153c3313d182238f2d3
diff --git a/roms/ipxe b/roms/ipxe
-Subproject b991c67c1d91574ef22336cc3a5944d1e63230c
+Subproject 0600d3ae94f93efd10fc6b3c7420a9557a3a167
diff --git a/roms/openbios b/roms/openbios
-Subproject 3ebaaa2e22eec2ed3debfd956604f395f28c46e
+Subproject fbc1b4ab5be4314a127a92b9234d655db8c05d0
diff --git a/roms/u-boot b/roms/u-boot
-Subproject 2072e7262965bb48d7fffb1e283101e6ed8b21a
+Subproject d85ca029f257b53a96da6c2fb421e78a003a994
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 73efc927a9..4e91122813 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2533,9 +2533,14 @@ sub process {
error_setg_file_open|
error_set|
error_prepend|
+ warn_reportf_err|
error_reportf_err|
error_vreport|
- error_report}x;
+ warn_vreport|
+ info_vreport|
+ error_report|
+ warn_report|
+ info_report}x;
if ($rawline =~ /\b(?:$qemu_error_funcs)\s*\(.*\".*\\n/) {
ERROR("Error messages should not contain newlines\n" . $herecurr);
diff --git a/scripts/coccinelle/memory-region-init-ram.cocci b/scripts/coccinelle/memory-region-init-ram.cocci
new file mode 100644
index 0000000000..d290150872
--- /dev/null
+++ b/scripts/coccinelle/memory-region-init-ram.cocci
@@ -0,0 +1,38 @@
+// Replace by-hand memory_region_init_ram_nomigrate/vmstate_register_ram
+// code sequences with use of the new memory_region_init_ram function.
+// Similarly for the _rom and _rom_device functions.
+// We don't try to replace sequences with a non-NULL owner, because
+// there are none in the tree that can be automatically converted
+// (and only a handful that can be manually converted).
+@@
+expression MR;
+expression NAME;
+expression SIZE;
+expression ERRP;
+@@
+-memory_region_init_ram_nomigrate(MR, NULL, NAME, SIZE, ERRP);
++memory_region_init_ram(MR, NULL, NAME, SIZE, ERRP);
+ ...
+-vmstate_register_ram_global(MR);
+@@
+expression MR;
+expression NAME;
+expression SIZE;
+expression ERRP;
+@@
+-memory_region_init_rom_nomigrate(MR, NULL, NAME, SIZE, ERRP);
++memory_region_init_rom(MR, NULL, NAME, SIZE, ERRP);
+ ...
+-vmstate_register_ram_global(MR);
+@@
+expression MR;
+expression OPS;
+expression OPAQUE;
+expression NAME;
+expression SIZE;
+expression ERRP;
+@@
+-memory_region_init_rom_device_nomigrate(MR, NULL, OPS, OPAQUE, NAME, SIZE, ERRP);
++memory_region_init_rom_device(MR, NULL, OPS, OPAQUE, NAME, SIZE, ERRP);
+ ...
+-vmstate_register_ram_global(MR);
diff --git a/scripts/coccinelle/qobject.cocci b/scripts/coccinelle/qobject.cocci
index c3253deb1b..c518caf7b1 100644
--- a/scripts/coccinelle/qobject.cocci
+++ b/scripts/coccinelle/qobject.cocci
@@ -3,6 +3,12 @@
expression Obj, Key, E;
@@
(
+- qobject_incref(QOBJECT(E));
++ QINCREF(E);
+|
+- qobject_decref(QOBJECT(E));
++ QDECREF(E);
+|
- qdict_put_obj(Obj, Key, QOBJECT(E));
+ qdict_put(Obj, Key, E);
|
diff --git a/scripts/hxtool b/scripts/hxtool
index 5468cd7782..1e2c97c5e6 100644
--- a/scripts/hxtool
+++ b/scripts/hxtool
@@ -7,7 +7,7 @@ hxtoh()
case $str in
HXCOMM*)
;;
- STEXI*|ETEXI*|SQMP*|EQMP*) flag=$(($flag^1))
+ STEXI*|ETEXI*) flag=$(($flag^1))
;;
*)
test $flag -eq 1 && printf "%s\n" "$str"
@@ -45,12 +45,6 @@ hxtotexi()
fi
flag=0
;;
- SQMP*|EQMP*)
- if test $flag -eq 1 ; then
- printf "line %d: syntax error: expected ETEXI, found '%s'\n" "$line" "$str" >&2
- exit 1
- fi
- ;;
DEFHEADING*)
print_texi_heading "$(expr "$str" : "DEFHEADING(\(.*\))")"
;;
@@ -65,47 +59,9 @@ hxtotexi()
done
}
-hxtoqmp()
-{
- IFS=
- flag=0
- line=1
- while read -r str; do
- case "$str" in
- HXCOMM*)
- ;;
- SQMP*)
- if test $flag -eq 1 ; then
- printf "line %d: syntax error: expected EQMP, found '%s'\n" "$line" "$str" >&2
- exit 1
- fi
- flag=1
- ;;
- EQMP*)
- if test $flag -ne 1 ; then
- printf "line %d: syntax error: expected SQMP, found '%s'\n" "$line" "$str" >&2
- exit 1
- fi
- flag=0
- ;;
- STEXI*|ETEXI*)
- if test $flag -eq 1 ; then
- printf "line %d: syntax error: expected EQMP, found '%s'\n" "$line" "$str" >&2
- exit 1
- fi
- ;;
- *)
- test $flag -eq 1 && printf '%s\n' "$str"
- ;;
- esac
- line=$((line+1))
- done
-}
-
case "$1" in
"-h") hxtoh ;;
"-t") hxtotexi ;;
-"-q") hxtoqmp ;;
*) exit 1 ;;
esac
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 1943de4852..974d0a4a80 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -21,7 +21,7 @@ def gen_command_decl(name, arg_type, boxed, ret_type):
''',
c_type=(ret_type and ret_type.c_type()) or 'void',
c_name=c_name(name),
- params=gen_params(arg_type, boxed, 'Error **errp'))
+ params=build_params(arg_type, boxed, 'Error **errp'))
def gen_call(name, arg_type, boxed, ret_type):
@@ -82,7 +82,7 @@ static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out,
c_type=ret_type.c_type(), c_name=ret_type.c_name())
-def gen_marshal_proto(name):
+def build_marshal_proto(name):
return ('void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)'
% c_name(name))
@@ -91,7 +91,7 @@ def gen_marshal_decl(name):
return mcgen('''
%(proto)s;
''',
- proto=gen_marshal_proto(name))
+ proto=build_marshal_proto(name))
def gen_marshal(name, arg_type, boxed, ret_type):
@@ -103,7 +103,7 @@ def gen_marshal(name, arg_type, boxed, ret_type):
{
Error *err = NULL;
''',
- proto=gen_marshal_proto(name))
+ proto=build_marshal_proto(name))
if ret_type:
ret += mcgen('''
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index 0485e39145..bcbef1035f 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -14,10 +14,10 @@
from qapi import *
-def gen_event_send_proto(name, arg_type, boxed):
+def build_event_send_proto(name, arg_type, boxed):
return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
'c_name': c_name(name.lower()),
- 'param': gen_params(arg_type, boxed, 'Error **errp')}
+ 'param': build_params(arg_type, boxed, 'Error **errp')}
def gen_event_send_decl(name, arg_type, boxed):
@@ -25,10 +25,10 @@ def gen_event_send_decl(name, arg_type, boxed):
%(proto)s;
''',
- proto=gen_event_send_proto(name, arg_type, boxed))
+ proto=build_event_send_proto(name, arg_type, boxed))
-# Declare and initialize an object 'qapi' using parameters from gen_params()
+# Declare and initialize an object 'qapi' using parameters from build_params()
def gen_param_var(typ):
assert not typ.variants
ret = mcgen('''
@@ -42,7 +42,7 @@ def gen_param_var(typ):
if memb.optional:
ret += 'has_' + c_name(memb.name) + sep
if memb.type.name == 'str':
- # Cast away const added in gen_params()
+ # Cast away const added in build_params()
ret += '(char *)'
ret += c_name(memb.name)
ret += mcgen('''
@@ -72,7 +72,7 @@ def gen_event_send(name, arg_type, boxed):
Error *err = NULL;
QMPEventFuncEmit emit;
''',
- proto=gen_event_send_proto(name, arg_type, boxed))
+ proto=build_event_send_proto(name, arg_type, boxed))
if arg_type and not arg_type.is_empty():
ret += mcgen('''
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 0de809f56b..84e2eb441b 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1897,7 +1897,7 @@ extern const char *const %(c_name)s_lookup[];
return ret
-def gen_params(arg_type, boxed, extra):
+def build_params(arg_type, boxed, extra):
if not arg_type:
assert not boxed
return extra
diff --git a/slirp/ip6.h b/slirp/ip6.h
index 0908855f0f..b1bea43b3c 100644
--- a/slirp/ip6.h
+++ b/slirp/ip6.h
@@ -57,9 +57,9 @@ static inline bool in6_equal_mach(const struct in6_addr *a,
const struct in6_addr *b,
int prefix_len)
{
- if (memcmp(&(a->s6_addr[(prefix_len + 7) / 8]),
- &(b->s6_addr[(prefix_len + 7) / 8]),
- 16 - (prefix_len + 7) / 8) != 0) {
+ if (memcmp(&(a->s6_addr[DIV_ROUND_UP(prefix_len, 8)]),
+ &(b->s6_addr[DIV_ROUND_UP(prefix_len, 8)]),
+ 16 - DIV_ROUND_UP(prefix_len, 8)) != 0) {
return 0;
}
diff --git a/slirp/misc.c b/slirp/misc.c
index 88e9d94197..260187b6b6 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -112,7 +112,9 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
listen(s, 1) < 0) {
error_report("Error: inet socket: %s", strerror(errno));
- closesocket(s);
+ if (s >= 0) {
+ closesocket(s);
+ }
return 0;
}
diff --git a/slirp/sbuf.c b/slirp/sbuf.c
index 10119d3ad5..912f235f65 100644
--- a/slirp/sbuf.c
+++ b/slirp/sbuf.c
@@ -91,7 +91,7 @@ sbappend(struct socket *so, struct mbuf *m)
if (so->so_urgc) {
sbappendsb(&so->so_rcv, m);
m_free(m);
- sosendoob(so);
+ (void)sosendoob(so);
return;
}
diff --git a/slirp/socket.c b/slirp/socket.c
index 3b49a69a93..ecec0295a9 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -345,33 +345,40 @@ sosendoob(struct socket *so)
if (sb->sb_rptr < sb->sb_wptr) {
/* We can send it directly */
n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
- so->so_urgc -= n;
-
- DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
} else {
/*
* Since there's no sendv or sendtov like writev,
* we must copy all data to a linear buffer then
* send it all
*/
+ uint32_t urgc = so->so_urgc;
len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
- if (len > so->so_urgc) len = so->so_urgc;
+ if (len > urgc) {
+ len = urgc;
+ }
memcpy(buff, sb->sb_rptr, len);
- so->so_urgc -= len;
- if (so->so_urgc) {
+ urgc -= len;
+ if (urgc) {
n = sb->sb_wptr - sb->sb_data;
- if (n > so->so_urgc) n = so->so_urgc;
+ if (n > urgc) {
+ n = urgc;
+ }
memcpy((buff + len), sb->sb_data, n);
- so->so_urgc -= n;
len += n;
}
n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
+ }
+
#ifdef DEBUG
- if (n != len)
- DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
+ if (n != len) {
+ DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
+ }
#endif
- DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
+ if (n < 0) {
+ return n;
}
+ so->so_urgc -= n;
+ DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
sb->sb_cc -= n;
sb->sb_rptr += n;
@@ -397,7 +404,15 @@ sowrite(struct socket *so)
DEBUG_ARG("so = %p", so);
if (so->so_urgc) {
- sosendoob(so);
+ uint32_t expected = so->so_urgc;
+ if (sosendoob(so) < expected) {
+ /* Treat a short write as a fatal error too,
+ * rather than continuing on and sending the urgent
+ * data as if it were non-urgent and leaving the
+ * so_urgc count wrong.
+ */
+ goto err_disconnected;
+ }
if (sb->sb_cc == 0)
return 0;
}
@@ -441,11 +456,7 @@ sowrite(struct socket *so)
return 0;
if (nn <= 0) {
- DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
- so->so_state, errno));
- sofcantsendmore(so);
- tcp_sockclosed(sototcpcb(so));
- return -1;
+ goto err_disconnected;
}
#ifndef HAVE_READV
@@ -472,6 +483,13 @@ sowrite(struct socket *so)
sofcantsendmore(so);
return nn;
+
+err_disconnected:
+ DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
+ so->so_state, errno));
+ sofcantsendmore(so);
+ tcp_sockclosed(sototcpcb(so));
+ return -1;
}
/*
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index c57177278b..4de91d5801 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1961,7 +1961,7 @@ static void x86_set_hv_spinlocks(Object *obj, Visitor *v, const char *name,
cpu->hyperv_spinlock_attempts = value;
}
-static PropertyInfo qdev_prop_spinlocks = {
+static const PropertyInfo qdev_prop_spinlocks = {
.name = "int",
.get = x86_get_hv_spinlocks,
.set = x86_set_hv_spinlocks,
@@ -2060,15 +2060,15 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features,
name = featurestr;
if (g_list_find_custom(plus_features, name, compare_string)) {
- error_report("warning: Ambiguous CPU model string. "
- "Don't mix both \"+%s\" and \"%s=%s\"",
- name, name, val);
+ warn_report("Ambiguous CPU model string. "
+ "Don't mix both \"+%s\" and \"%s=%s\"",
+ name, name, val);
ambiguous = true;
}
if (g_list_find_custom(minus_features, name, compare_string)) {
- error_report("warning: Ambiguous CPU model string. "
- "Don't mix both \"-%s\" and \"%s=%s\"",
- name, name, val);
+ warn_report("Ambiguous CPU model string. "
+ "Don't mix both \"-%s\" and \"%s=%s\"",
+ name, name, val);
ambiguous = true;
}
@@ -2096,8 +2096,8 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features,
}
if (ambiguous) {
- error_report("warning: Compatibility of ambiguous CPU model "
- "strings won't be kept on future QEMU versions");
+ warn_report("Compatibility of ambiguous CPU model "
+ "strings won't be kept on future QEMU versions");
}
}
@@ -3547,9 +3547,9 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
*/
if (cpu->phys_bits != host_phys_bits && cpu->phys_bits != 0 &&
!warned) {
- error_report("Warning: Host physical bits (%u)"
- " does not match phys-bits property (%u)",
- host_phys_bits, cpu->phys_bits);
+ warn_report("Host physical bits (%u)"
+ " does not match phys-bits property (%u)",
+ host_phys_bits, cpu->phys_bits);
warned = true;
}
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index f84a49d366..a6613e19f2 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -600,10 +600,10 @@ static int kvm_arch_set_tsc_khz(CPUState *cs)
kvm_vcpu_ioctl(cs, KVM_GET_TSC_KHZ) :
-ENOTSUP;
if (cur_freq <= 0 || cur_freq != env->tsc_khz) {
- error_report("warning: TSC frequency mismatch between "
- "VM (%" PRId64 " kHz) and host (%d kHz), "
- "and TSC scaling unavailable",
- env->tsc_khz, cur_freq);
+ warn_report("TSC frequency mismatch between "
+ "VM (%" PRId64 " kHz) and host (%d kHz), "
+ "and TSC scaling unavailable",
+ env->tsc_khz, cur_freq);
return r;
}
}
@@ -919,8 +919,8 @@ int kvm_arch_init_vcpu(CPUState *cs)
error_report("kvm: LMCE not supported");
return -ENOTSUP;
}
- error_report("warning: Unsupported MCG_CAP bits: 0x%" PRIx64,
- unsupported_caps);
+ warn_report("Unsupported MCG_CAP bits: 0x%" PRIx64,
+ unsupported_caps);
}
env->mcg_cap &= mcg_cap | MCG_CAP_BANKS_MASK;
diff --git a/target/mips/translate.c b/target/mips/translate.c
index 559f8fed89..befb87f814 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -18712,10 +18712,14 @@ static void gen_msa_elm_df(CPUMIPSState *env, DisasContext *ctx, uint32_t df,
#endif
switch (MASK_MSA_ELM(ctx->opcode)) {
case OPC_COPY_S_df:
- gen_helper_msa_copy_s_df(cpu_env, tdf, twd, tws, tn);
+ if (likely(wd != 0)) {
+ gen_helper_msa_copy_s_df(cpu_env, tdf, twd, tws, tn);
+ }
break;
case OPC_COPY_U_df:
- gen_helper_msa_copy_u_df(cpu_env, tdf, twd, tws, tn);
+ if (likely(wd != 0)) {
+ gen_helper_msa_copy_u_df(cpu_env, tdf, twd, tws, tn);
+ }
break;
case OPC_INSERT_df:
gen_helper_msa_insert_df(cpu_env, tdf, twd, tws, tn);
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index f7a7ea5858..85713795de 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -22,6 +22,7 @@
#include <linux/kvm.h>
#include "qemu-common.h"
+#include "qapi/error.h"
#include "qemu/error-report.h"
#include "cpu.h"
#include "cpu-models.h"
@@ -88,6 +89,7 @@ static int cap_fixup_hcalls;
static int cap_htm; /* Hardware transactional memory support */
static int cap_mmu_radix;
static int cap_mmu_hash_v3;
+static int cap_resize_hpt;
static uint32_t debug_inst_opcode;
@@ -144,6 +146,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_htm = kvm_vm_check_extension(s, KVM_CAP_PPC_HTM);
cap_mmu_radix = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_RADIX);
cap_mmu_hash_v3 = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3);
+ cap_resize_hpt = kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT);
if (!cap_interrupt_level) {
fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
@@ -2709,3 +2712,76 @@ int kvmppc_enable_hwrng(void)
return kvmppc_enable_hcall(kvm_state, H_RANDOM);
}
+
+void kvmppc_check_papr_resize_hpt(Error **errp)
+{
+ if (!kvm_enabled()) {
+ return; /* No KVM, we're good */
+ }
+
+ if (cap_resize_hpt) {
+ return; /* Kernel has explicit support, we're good */
+ }
+
+ /* Otherwise fallback on looking for PR KVM */
+ if (kvmppc_is_pr(kvm_state)) {
+ return;
+ }
+
+ error_setg(errp,
+ "Hash page table resizing not available with this KVM version");
+}
+
+int kvmppc_resize_hpt_prepare(PowerPCCPU *cpu, target_ulong flags, int shift)
+{
+ CPUState *cs = CPU(cpu);
+ struct kvm_ppc_resize_hpt rhpt = {
+ .flags = flags,
+ .shift = shift,
+ };
+
+ if (!cap_resize_hpt) {
+ return -ENOSYS;
+ }
+
+ return kvm_vm_ioctl(cs->kvm_state, KVM_PPC_RESIZE_HPT_PREPARE, &rhpt);
+}
+
+int kvmppc_resize_hpt_commit(PowerPCCPU *cpu, target_ulong flags, int shift)
+{
+ CPUState *cs = CPU(cpu);
+ struct kvm_ppc_resize_hpt rhpt = {
+ .flags = flags,
+ .shift = shift,
+ };
+
+ if (!cap_resize_hpt) {
+ return -ENOSYS;
+ }
+
+ return kvm_vm_ioctl(cs->kvm_state, KVM_PPC_RESIZE_HPT_COMMIT, &rhpt);
+}
+
+static void kvmppc_pivot_hpt_cpu(CPUState *cs, run_on_cpu_data arg)
+{
+ target_ulong sdr1 = arg.target_ptr;
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
+ /* This is just for the benefit of PR KVM */
+ cpu_synchronize_state(cs);
+ env->spr[SPR_SDR1] = sdr1;
+ if (kvmppc_put_books_sregs(cpu) < 0) {
+ error_report("Unable to update SDR1 in KVM");
+ exit(1);
+ }
+}
+
+void kvmppc_update_sdr1(target_ulong sdr1)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ run_on_cpu(cs, kvmppc_pivot_hpt_cpu, RUN_ON_CPU_TARGET_PTR(sdr1));
+ }
+}
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index eab7c8fdb3..6bc6fb3e2d 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -63,6 +63,10 @@ bool kvmppc_has_cap_mmu_hash_v3(void);
int kvmppc_enable_hwrng(void);
int kvmppc_put_books_sregs(PowerPCCPU *cpu);
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
+void kvmppc_check_papr_resize_hpt(Error **errp);
+int kvmppc_resize_hpt_prepare(PowerPCCPU *cpu, target_ulong flags, int shift);
+int kvmppc_resize_hpt_commit(PowerPCCPU *cpu, target_ulong flags, int shift);
+void kvmppc_update_sdr1(target_ulong sdr1);
bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path);
@@ -297,6 +301,28 @@ static inline PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
return NULL;
}
+static inline void kvmppc_check_papr_resize_hpt(Error **errp)
+{
+ return;
+}
+
+static inline int kvmppc_resize_hpt_prepare(PowerPCCPU *cpu,
+ target_ulong flags, int shift)
+{
+ return -ENOSYS;
+}
+
+static inline int kvmppc_resize_hpt_commit(PowerPCCPU *cpu,
+ target_ulong flags, int shift)
+{
+ return -ENOSYS;
+}
+
+static inline void kvmppc_update_sdr1(target_ulong sdr1)
+{
+ abort();
+}
+
#endif
#ifndef CONFIG_KVM
diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
index 54f1e37655..d297b97d37 100644
--- a/target/ppc/mmu-hash64.h
+++ b/target/ppc/mmu-hash64.h
@@ -63,11 +63,15 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
#define HASH_PTE_SIZE_64 16
#define HASH_PTEG_SIZE_64 (HASH_PTE_SIZE_64 * HPTES_PER_GROUP)
+#define HPTE64_V_SSIZE SLB_VSID_B
+#define HPTE64_V_SSIZE_256M SLB_VSID_B_256M
+#define HPTE64_V_SSIZE_1T SLB_VSID_B_1T
#define HPTE64_V_SSIZE_SHIFT 62
#define HPTE64_V_AVPN_SHIFT 7
#define HPTE64_V_AVPN 0x3fffffffffffff80ULL
#define HPTE64_V_AVPN_VAL(x) (((x) & HPTE64_V_AVPN) >> HPTE64_V_AVPN_SHIFT)
#define HPTE64_V_COMPARE(x, y) (!(((x) ^ (y)) & 0xffffffffffffff83ULL))
+#define HPTE64_V_BOLTED 0x0000000000000010ULL
#define HPTE64_V_LARGE 0x0000000000000004ULL
#define HPTE64_V_SECONDARY 0x0000000000000002ULL
#define HPTE64_V_VALID 0x0000000000000001ULL
diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c
index 783bf98217..b325c2cce6 100644
--- a/target/ppc/translate_init.c
+++ b/target/ppc/translate_init.c
@@ -8435,7 +8435,7 @@ static void getset_compat_deprecated(Object *obj, Visitor *v, const char *name,
visit_type_null(v, name, NULL);
}
-static PropertyInfo ppc_compat_deprecated_propinfo = {
+static const PropertyInfo ppc_compat_deprecated_propinfo = {
.name = "str",
.description = "compatibility mode (deprecated)",
.get = getset_compat_deprecated,
@@ -9011,8 +9011,16 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp)
/* By default we choose legacy mode and switch to new hash or radix
* when a register process table hcall is made. So disable process
* tables and guest translation shootdown by default
+ *
+ * Hot-plugged CPUs inherit from the guest radix setting under
+ * KVM but not under TCG. Update the default LPCR to keep new
+ * CPUs in sync when radix is enabled.
*/
- lpcr->default_value &= ~(LPCR_UPRT | LPCR_GTSE);
+ if (ppc64_radix_guest(cpu)) {
+ lpcr->default_value |= LPCR_UPRT | LPCR_GTSE;
+ } else {
+ lpcr->default_value &= ~(LPCR_UPRT | LPCR_GTSE);
+ }
lpcr->default_value |= LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE |
LPCR_OEE;
break;
diff --git a/target/s390x/arch_dump.c b/target/s390x/arch_dump.c
index 105ae9a5d8..96c9fb97cb 100644
--- a/target/s390x/arch_dump.c
+++ b/target/s390x/arch_dump.c
@@ -57,6 +57,12 @@ struct S390xElfVregsHiStruct {
typedef struct S390xElfVregsHiStruct S390xElfVregsHi;
+struct S390xElfGSCBStruct {
+ uint64_t gsregs[4];
+} QEMU_PACKED;
+
+typedef struct S390xElfGSCBStruct S390xElfGSCB;
+
typedef struct noteStruct {
Elf64_Nhdr hdr;
char name[8];
@@ -65,6 +71,7 @@ typedef struct noteStruct {
S390xElfFpregset fpregset;
S390xElfVregsLo vregslo;
S390xElfVregsHi vregshi;
+ S390xElfGSCB gscb;
uint32_t prefix;
uint64_t timer;
uint64_t todcmp;
@@ -126,6 +133,16 @@ static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu, int id)
}
}
+static void s390x_write_elf64_gscb(Note *note, S390CPU *cpu, int id)
+{
+ int i;
+
+ note->hdr.n_type = cpu_to_be32(NT_S390_GS_CB);
+ for (i = 0; i < 4; i++) {
+ note->contents.gscb.gsregs[i] = cpu_to_be64(cpu->env.gscb[i]);
+ }
+}
+
static void s390x_write_elf64_timer(Note *note, S390CPU *cpu, int id)
{
note->hdr.n_type = cpu_to_be32(NT_S390_TIMER);
@@ -181,6 +198,7 @@ static const NoteFuncDesc note_linux[] = {
{sizeof(((Note *)0)->contents.todpreg), s390x_write_elf64_todpreg},
{sizeof(((Note *)0)->contents.vregslo), s390x_write_elf64_vregslo},
{sizeof(((Note *)0)->contents.vregshi), s390x_write_elf64_vregshi},
+ {sizeof(((Note *)0)->contents.gscb), s390x_write_elf64_gscb},
{ 0, NULL}
};
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index bdb9bdbc9d..7732d01784 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -89,6 +89,7 @@ typedef struct CPUS390XState {
CPU_DoubleU vregs[32][2]; /* vector registers */
uint32_t aregs[16]; /* access registers */
uint8_t riccb[64]; /* runtime instrumentation control */
+ uint64_t gscb[4]; /* guarded storage control */
/* Fields up to this point are not cleared by initial CPU reset */
struct {} start_initial_reset_fields;
@@ -1158,6 +1159,7 @@ int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
int vq, bool assign);
int kvm_s390_cpu_restart(S390CPU *cpu);
int kvm_s390_get_memslot_count(KVMState *s);
+int kvm_s390_cmma_active(void);
void kvm_s390_cmma_reset(void);
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state);
void kvm_s390_reset_vcpu(S390CPU *cpu);
@@ -1165,6 +1167,7 @@ int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit);
void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
int kvm_s390_get_ri(void);
+int kvm_s390_get_gs(void);
void kvm_s390_crypto_reset(void);
#else
static inline void kvm_s390_io_interrupt(uint16_t subchannel_id,
@@ -1219,6 +1222,10 @@ static inline int kvm_s390_get_ri(void)
{
return 0;
}
+static inline int kvm_s390_get_gs(void)
+{
+ return 0;
+}
static inline void kvm_s390_crypto_reset(void)
{
}
@@ -1327,6 +1334,7 @@ static inline bool s390_get_squash_mcss(void)
#define MCIC_VB_CR 0x0000000400000000ULL
#define MCIC_VB_ST 0x0000000100000000ULL
#define MCIC_VB_AR 0x0000000040000000ULL
+#define MCIC_VB_GS 0x0000000008000000ULL
#define MCIC_VB_PR 0x0000000000200000ULL
#define MCIC_VB_FC 0x0000000000100000ULL
#define MCIC_VB_CT 0x0000000000020000ULL
diff --git a/target/s390x/cpu_features.c b/target/s390x/cpu_features.c
index 42fd9d792b..fa887d9b6f 100644
--- a/target/s390x/cpu_features.c
+++ b/target/s390x/cpu_features.c
@@ -59,6 +59,7 @@ static const S390FeatDef s390_features[] = {
FEAT_INIT("exrl", S390_FEAT_TYPE_STFL, 35, "Execute-extensions facility"),
FEAT_INIT("emon", S390_FEAT_TYPE_STFL, 36, "Enhanced-monitor facility"),
FEAT_INIT("fpe", S390_FEAT_TYPE_STFL, 37, "Floating-point extension facility"),
+ FEAT_INIT("opc", S390_FEAT_TYPE_STFL, 38, "Order Preserving Compression facility"),
FEAT_INIT("sprogp", S390_FEAT_TYPE_STFL, 40, "Set-program-parameters facility"),
FEAT_INIT("fpseh", S390_FEAT_TYPE_STFL, 41, "Floating-point-support-enhancement facilities"),
FEAT_INIT("dfp", S390_FEAT_TYPE_STFL, 42, "DFP (decimal-floating-point) facility"),
@@ -72,8 +73,15 @@ static const S390FeatDef s390_features[] = {
FEAT_INIT("ltlbc", S390_FEAT_TYPE_STFL, 51, "Local-TLB-clearing facility"),
FEAT_INIT("iacc2", S390_FEAT_TYPE_STFL, 52, "Interlocked-access facility 2"),
FEAT_INIT("stfle53", S390_FEAT_TYPE_STFL, 53, "Various facilities introduced with z13"),
+ FEAT_INIT("eec", S390_FEAT_TYPE_STFL, 54, "Entropy encoding compression facility"),
FEAT_INIT("msa5-base", S390_FEAT_TYPE_STFL, 57, "Message-security-assist-extension-5 facility (excluding subfunctions)"),
+ FEAT_INIT("minste2", S390_FEAT_TYPE_STFL, 58, "Miscellaneous-instruction-extensions facility 2"),
+ FEAT_INIT("sema", S390_FEAT_TYPE_STFL, 59, "Semaphore-assist facility"),
+ FEAT_INIT("tsi", S390_FEAT_TYPE_STFL, 60, "Time-slice Instrumentation facility"),
FEAT_INIT("ri", S390_FEAT_TYPE_STFL, 64, "CPU runtime-instrumentation facility"),
+ FEAT_INIT("zpci", S390_FEAT_TYPE_STFL, 69, "z/PCI facility"),
+ FEAT_INIT("aen", S390_FEAT_TYPE_STFL, 71, "General-purpose-adapter-event-notification facility"),
+ FEAT_INIT("ais", S390_FEAT_TYPE_STFL, 72, "General-purpose-adapter-interruption-suppression facility"),
FEAT_INIT("te", S390_FEAT_TYPE_STFL, 73, "Transactional-execution facility"),
FEAT_INIT("sthyi", S390_FEAT_TYPE_STFL, 74, "Store-hypervisor-information facility"),
FEAT_INIT("aefsi", S390_FEAT_TYPE_STFL, 75, "Access-exception-fetch/store-indication facility"),
@@ -82,10 +90,24 @@ static const S390FeatDef s390_features[] = {
FEAT_INIT("edat2", S390_FEAT_TYPE_STFL, 78, "Enhanced-DAT facility 2"),
FEAT_INIT("dfppc", S390_FEAT_TYPE_STFL, 80, "Decimal-floating-point packed-conversion facility"),
FEAT_INIT("vx", S390_FEAT_TYPE_STFL, 129, "Vector facility"),
-
+ FEAT_INIT("iep", S390_FEAT_TYPE_STFL, 130, "Instruction-execution-protection facility"),
+ FEAT_INIT("sea_esop2", S390_FEAT_TYPE_STFL, 131, "Side-effect-access facility and Enhanced-suppression-on-protection facility 2"),
+ FEAT_INIT("gs", S390_FEAT_TYPE_STFL, 133, "Guarded-storage facility"),
+ FEAT_INIT("vxpd", S390_FEAT_TYPE_STFL, 134, "Vector packed decimal facility"),
+ FEAT_INIT("vxeh", S390_FEAT_TYPE_STFL, 135, "Vector enhancements facility"),
+ FEAT_INIT("mepoch", S390_FEAT_TYPE_STFL, 139, "Multiple-epoch facility"),
+ FEAT_INIT("tpei", S390_FEAT_TYPE_STFL, 144, "Test-pending-external-interruption facility"),
+ FEAT_INIT("irbm", S390_FEAT_TYPE_STFL, 145, "Insert-reference-bits-multiple facility"),
+ FEAT_INIT("msa8-base", S390_FEAT_TYPE_STFL, 146, "Message-security-assist-extension-8 facility (excluding subfunctions)"),
+ FEAT_INIT("cmmnt", S390_FEAT_TYPE_STFL, 147, "CMM: ESSA-enhancement (no translate) facility"),
+
+ /* SCLP SCCB Byte 80 - 98 (bit numbers relative to byte-80) */
FEAT_INIT("gsls", S390_FEAT_TYPE_SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility"),
FEAT_INIT("esop", S390_FEAT_TYPE_SCLP_CONF_CHAR, 46, "Enhanced-suppression-on-protection facility"),
+ FEAT_INIT("hpma2", S390_FEAT_TYPE_SCLP_CONF_CHAR, 90, "Host page management assist 2 Facility"), /* 91-2 */
+ FEAT_INIT("kss", S390_FEAT_TYPE_SCLP_CONF_CHAR, 151, "SIE: Keyless-subset facility"), /* 98-7 */
+ /* SCLP SCCB Byte 116 - 119 (bit numbers relative to byte-116) */
FEAT_INIT("64bscao", S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, 0, "SIE: 64-bit-SCAO facility"),
FEAT_INIT("cmma", S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, 1, "SIE: Collaborative-memory-management assist"),
FEAT_INIT("pfmfi", S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, 9, "SIE: PFMF interpretation facility"),
@@ -182,10 +204,23 @@ static const S390FeatDef s390_features[] = {
FEAT_INIT("kimd-sha-1", S390_FEAT_TYPE_KIMD, 1, "KIMD SHA-1"),
FEAT_INIT("kimd-sha-256", S390_FEAT_TYPE_KIMD, 2, "KIMD SHA-256"),
FEAT_INIT("kimd-sha-512", S390_FEAT_TYPE_KIMD, 3, "KIMD SHA-512"),
+ FEAT_INIT("kimd-sha3-224", S390_FEAT_TYPE_KIMD, 32, "KIMD SHA3-224"),
+ FEAT_INIT("kimd-sha3-256", S390_FEAT_TYPE_KIMD, 33, "KIMD SHA3-256"),
+ FEAT_INIT("kimd-sha3-384", S390_FEAT_TYPE_KIMD, 34, "KIMD SHA3-384"),
+ FEAT_INIT("kimd-sha3-512", S390_FEAT_TYPE_KIMD, 35, "KIMD SHA3-512"),
+ FEAT_INIT("kimd-shake-128", S390_FEAT_TYPE_KIMD, 36, "KIMD SHAKE-128"),
+ FEAT_INIT("kimd-shake-256", S390_FEAT_TYPE_KIMD, 37, "KIMD SHAKE-256"),
FEAT_INIT("kimd-ghash", S390_FEAT_TYPE_KIMD, 65, "KIMD GHASH"),
+
FEAT_INIT("klmd-sha-1", S390_FEAT_TYPE_KLMD, 1, "KLMD SHA-1"),
FEAT_INIT("klmd-sha-256", S390_FEAT_TYPE_KLMD, 2, "KLMD SHA-256"),
FEAT_INIT("klmd-sha-512", S390_FEAT_TYPE_KLMD, 3, "KLMD SHA-512"),
+ FEAT_INIT("klmd-sha3-224", S390_FEAT_TYPE_KLMD, 32, "KLMD SHA3-224"),
+ FEAT_INIT("klmd-sha3-256", S390_FEAT_TYPE_KLMD, 33, "KLMD SHA3-256"),
+ FEAT_INIT("klmd-sha3-384", S390_FEAT_TYPE_KLMD, 34, "KLMD SHA3-384"),
+ FEAT_INIT("klmd-sha3-512", S390_FEAT_TYPE_KLMD, 35, "KLMD SHA3-512"),
+ FEAT_INIT("klmd-shake-128", S390_FEAT_TYPE_KLMD, 36, "KLMD SHAKE-128"),
+ FEAT_INIT("klmd-shake-256", S390_FEAT_TYPE_KLMD, 37, "KLMD SHAKE-256"),
FEAT_INIT("pckmo-edea", S390_FEAT_TYPE_PCKMO, 1, "PCKMO Encrypted-DEA-Key"),
FEAT_INIT("pckmo-etdea-128", S390_FEAT_TYPE_PCKMO, 2, "PCKMO Encrypted-TDEA-128-Key"),
@@ -251,6 +286,15 @@ static const S390FeatDef s390_features[] = {
FEAT_INIT("pcc-xts-eaes-256", S390_FEAT_TYPE_PCC, 60, "PCC Compute-XTS-Parameter-Using-Encrypted-AES-256"),
FEAT_INIT("ppno-sha-512-drng", S390_FEAT_TYPE_PPNO, 3, "PPNO SHA-512-DRNG"),
+ FEAT_INIT("prno-trng-qrtcr", S390_FEAT_TYPE_PPNO, 112, "PRNO TRNG-Query-Raw-to-Conditioned-Ratio"),
+ FEAT_INIT("prno-trng", S390_FEAT_TYPE_PPNO, 114, "PRNO TRNG"),
+
+ FEAT_INIT("kma-gcm-aes-128", S390_FEAT_TYPE_KMA, 18, "KMA GCM-AES-128"),
+ FEAT_INIT("kma-gcm-aes-192", S390_FEAT_TYPE_KMA, 19, "KMA GCM-AES-192"),
+ FEAT_INIT("kma-gcm-aes-256", S390_FEAT_TYPE_KMA, 20, "KMA GCM-AES-256"),
+ FEAT_INIT("kma-gcm-eaes-128", S390_FEAT_TYPE_KMA, 26, "KMA GCM-Encrypted-AES-128"),
+ FEAT_INIT("kma-gcm-eaes-192", S390_FEAT_TYPE_KMA, 27, "KMA GCM-Encrypted-AES-192"),
+ FEAT_INIT("kma-gcm-eaes-256", S390_FEAT_TYPE_KMA, 28, "KMA GCM-Encrypted-AES-256"),
};
const S390FeatDef *s390_feat_def(S390Feat feat)
@@ -293,8 +337,9 @@ void s390_fill_feat_block(const S390FeatBitmap features, S390FeatType type,
int bit_nr;
if (type == S390_FEAT_TYPE_STFL && test_bit(S390_FEAT_ZARCH, features)) {
- /* z/Architecture is always active if around */
- data[0] |= 0x20;
+ /* Features that are always active */
+ data[0] |= 0x20; /* z/Architecture */
+ data[17] |= 0x20; /* Configuration-z-architectural-mode */
}
feat = find_first_bit(features, S390_FEAT_MAX);
@@ -383,6 +428,9 @@ static S390FeatGroupDef s390_feature_groups[] = {
FEAT_GROUP_INIT("msa3", MSA_EXT_3, "Message-security-assist-extension 3 facility"),
FEAT_GROUP_INIT("msa4", MSA_EXT_4, "Message-security-assist-extension 4 facility"),
FEAT_GROUP_INIT("msa5", MSA_EXT_5, "Message-security-assist-extension 5 facility"),
+ FEAT_GROUP_INIT("msa6", MSA_EXT_6, "Message-security-assist-extension 6 facility"),
+ FEAT_GROUP_INIT("msa7", MSA_EXT_7, "Message-security-assist-extension 7 facility"),
+ FEAT_GROUP_INIT("msa8", MSA_EXT_8, "Message-security-assist-extension 8 facility"),
};
const S390FeatGroupDef *s390_feat_group_def(S390FeatGroup group)
diff --git a/target/s390x/cpu_features.h b/target/s390x/cpu_features.h
index d669121786..14bc311dbe 100644
--- a/target/s390x/cpu_features.h
+++ b/target/s390x/cpu_features.h
@@ -37,6 +37,7 @@ typedef enum {
S390_FEAT_TYPE_KMO,
S390_FEAT_TYPE_PCC,
S390_FEAT_TYPE_PPNO,
+ S390_FEAT_TYPE_KMA,
} S390FeatType;
/* Definition of a CPU feature */
@@ -74,6 +75,9 @@ typedef enum {
S390_FEAT_GROUP_MSA_EXT_3,
S390_FEAT_GROUP_MSA_EXT_4,
S390_FEAT_GROUP_MSA_EXT_5,
+ S390_FEAT_GROUP_MSA_EXT_6,
+ S390_FEAT_GROUP_MSA_EXT_7,
+ S390_FEAT_GROUP_MSA_EXT_8,
S390_FEAT_GROUP_MAX,
} S390FeatGroup;
diff --git a/target/s390x/cpu_features_def.h b/target/s390x/cpu_features_def.h
index aa5ab8d371..4b6d4e9cc0 100644
--- a/target/s390x/cpu_features_def.h
+++ b/target/s390x/cpu_features_def.h
@@ -15,6 +15,7 @@
#define TARGET_S390X_CPU_FEATURES_DEF_H
typedef enum {
+ /* Stfle */
S390_FEAT_ESAN3 = 0,
S390_FEAT_ZARCH,
S390_FEAT_DAT_ENH,
@@ -49,6 +50,7 @@ typedef enum {
S390_FEAT_EXECUTE_EXT,
S390_FEAT_ENHANCED_MONITOR,
S390_FEAT_FLOATING_POINT_EXT,
+ S390_FEAT_ORDER_PRESERVING_COMPRESSION,
S390_FEAT_SET_PROGRAM_PARAMETERS,
S390_FEAT_FLOATING_POINT_SUPPPORT_ENH,
S390_FEAT_DFP,
@@ -62,8 +64,15 @@ typedef enum {
S390_FEAT_LOCAL_TLB_CLEARING,
S390_FEAT_INTERLOCKED_ACCESS_2,
S390_FEAT_STFLE_53,
+ S390_FEAT_ENTROPY_ENC_COMP,
S390_FEAT_MSA_EXT_5,
+ S390_FEAT_MISC_INSTRUCTION_EXT,
+ S390_FEAT_SEMAPHORE_ASSIST,
+ S390_FEAT_TIME_SLICE_INSTRUMENTATION,
S390_FEAT_RUNTIME_INSTRUMENTATION,
+ S390_FEAT_ZPCI,
+ S390_FEAT_ADAPTER_EVENT_NOTIFICATION,
+ S390_FEAT_ADAPTER_INT_SUPPRESSION,
S390_FEAT_TRANSACTIONAL_EXE,
S390_FEAT_STORE_HYPERVISOR_INFO,
S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION,
@@ -72,12 +81,30 @@ typedef enum {
S390_FEAT_EDAT_2,
S390_FEAT_DFP_PACKED_CONVERSION,
S390_FEAT_VECTOR,
+ S390_FEAT_INSTRUCTION_EXEC_PROT,
+ S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2,
+ S390_FEAT_GUARDED_STORAGE,
+ S390_FEAT_VECTOR_PACKED_DECIMAL,
+ S390_FEAT_VECTOR_ENH,
+ S390_FEAT_MULTIPLE_EPOCH,
+ S390_FEAT_TEST_PENDING_EXT_INTERRUPTION,
+ S390_FEAT_INSERT_REFERENCE_BITS_MULT,
+ S390_FEAT_MSA_EXT_8,
+ S390_FEAT_CMM_NT,
+
+ /* Sclp Conf Char */
S390_FEAT_SIE_GSLS,
S390_FEAT_ESOP,
+ S390_FEAT_HPMA2,
+ S390_FEAT_SIE_KSS,
+
+ /* Sclp Conf Char Ext */
S390_FEAT_SIE_64BSCAO,
S390_FEAT_SIE_CMMA,
S390_FEAT_SIE_PFMFI,
S390_FEAT_SIE_IBS,
+
+ /* Sclp Cpu */
S390_FEAT_SIE_F2,
S390_FEAT_SIE_SKEY,
S390_FEAT_SIE_GPERE,
@@ -85,8 +112,12 @@ typedef enum {
S390_FEAT_SIE_SIGPIF,
S390_FEAT_SIE_IB,
S390_FEAT_SIE_CEI,
+
+ /* Misc */
S390_FEAT_DAT_ENH_2,
S390_FEAT_CMM,
+
+ /* PLO */
S390_FEAT_PLO_CL,
S390_FEAT_PLO_CLG,
S390_FEAT_PLO_CLGR,
@@ -111,6 +142,8 @@ typedef enum {
S390_FEAT_PLO_CSTSTG,
S390_FEAT_PLO_CSTSTGR,
S390_FEAT_PLO_CSTSTX,
+
+ /* PTFF */
S390_FEAT_PTFF_QTO,
S390_FEAT_PTFF_QSI,
S390_FEAT_PTFF_QPT,
@@ -118,6 +151,8 @@ typedef enum {
S390_FEAT_PTFF_QTOU,
S390_FEAT_PTFF_STO,
S390_FEAT_PTFF_STOU,
+
+ /* KMAC */
S390_FEAT_KMAC_DEA,
S390_FEAT_KMAC_TDEA_128,
S390_FEAT_KMAC_TDEA_192,
@@ -130,6 +165,8 @@ typedef enum {
S390_FEAT_KMAC_EAES_128,
S390_FEAT_KMAC_EAES_192,
S390_FEAT_KMAC_EAES_256,
+
+ /* KMC */
S390_FEAT_KMC_DEA,
S390_FEAT_KMC_TDEA_128,
S390_FEAT_KMC_TDEA_192,
@@ -143,6 +180,8 @@ typedef enum {
S390_FEAT_KMC_EAES_192,
S390_FEAT_KMC_EAES_256,
S390_FEAT_KMC_PRNG,
+
+ /* KM */
S390_FEAT_KM_DEA,
S390_FEAT_KM_TDEA_128,
S390_FEAT_KM_TDEA_192,
@@ -159,19 +198,39 @@ typedef enum {
S390_FEAT_KM_XTS_AES_256,
S390_FEAT_KM_XTS_EAES_128,
S390_FEAT_KM_XTS_EAES_256,
+
+ /* KIMD */
S390_FEAT_KIMD_SHA_1,
S390_FEAT_KIMD_SHA_256,
S390_FEAT_KIMD_SHA_512,
+ S390_FEAT_KIMD_SHA3_224,
+ S390_FEAT_KIMD_SHA3_256,
+ S390_FEAT_KIMD_SHA3_384,
+ S390_FEAT_KIMD_SHA3_512,
+ S390_FEAT_KIMD_SHAKE_128,
+ S390_FEAT_KIMD_SHAKE_256,
S390_FEAT_KIMD_GHASH,
+
+ /* KLMD */
S390_FEAT_KLMD_SHA_1,
S390_FEAT_KLMD_SHA_256,
S390_FEAT_KLMD_SHA_512,
+ S390_FEAT_KLMD_SHA3_224,
+ S390_FEAT_KLMD_SHA3_256,
+ S390_FEAT_KLMD_SHA3_384,
+ S390_FEAT_KLMD_SHA3_512,
+ S390_FEAT_KLMD_SHAKE_128,
+ S390_FEAT_KLMD_SHAKE_256,
+
+ /* PCKMO */
S390_FEAT_PCKMO_EDEA,
S390_FEAT_PCKMO_ETDEA_128,
S390_FEAT_PCKMO_ETDEA_256,
S390_FEAT_PCKMO_AES_128,
S390_FEAT_PCKMO_AES_192,
S390_FEAT_PCKMO_AES_256,
+
+ /* KMCTR */
S390_FEAT_KMCTR_DEA,
S390_FEAT_KMCTR_TDEA_128,
S390_FEAT_KMCTR_TDEA_192,
@@ -184,6 +243,8 @@ typedef enum {
S390_FEAT_KMCTR_EAES_128,
S390_FEAT_KMCTR_EAES_192,
S390_FEAT_KMCTR_EAES_256,
+
+ /* KMF */
S390_FEAT_KMF_DEA,
S390_FEAT_KMF_TDEA_128,
S390_FEAT_KMF_TDEA_192,
@@ -196,6 +257,8 @@ typedef enum {
S390_FEAT_KMF_EAES_128,
S390_FEAT_KMF_EAES_192,
S390_FEAT_KMF_EAES_256,
+
+ /* KMO */
S390_FEAT_KMO_DEA,
S390_FEAT_KMO_TDEA_128,
S390_FEAT_KMO_TDEA_192,
@@ -208,6 +271,8 @@ typedef enum {
S390_FEAT_KMO_EAES_128,
S390_FEAT_KMO_EAES_192,
S390_FEAT_KMO_EAES_256,
+
+ /* PCC */
S390_FEAT_PCC_CMAC_DEA,
S390_FEAT_PCC_CMAC_TDEA_128,
S390_FEAT_PCC_CMAC_TDEA_192,
@@ -224,7 +289,19 @@ typedef enum {
S390_FEAT_PCC_XTS_AES_256,
S390_FEAT_PCC_XTS_EAES_128,
S390_FEAT_PCC_XTS_EAES_256,
+
+ /* PPNO/PRNO */
S390_FEAT_PPNO_SHA_512_DRNG,
+ S390_FEAT_PRNO_TRNG_QRTCR,
+ S390_FEAT_PRNO_TRNG,
+
+ /* KMA */
+ S390_FEAT_KMA_GCM_AES_128,
+ S390_FEAT_KMA_GCM_AES_192,
+ S390_FEAT_KMA_GCM_AES_256 ,
+ S390_FEAT_KMA_GCM_EAES_128,
+ S390_FEAT_KMA_GCM_EAES_192,
+ S390_FEAT_KMA_GCM_EAES_256,
S390_FEAT_MAX,
} S390Feat;
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 7cb55dc7e3..c654279a6c 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -77,6 +77,32 @@ static S390CPUDef s390_cpu_defs[] = {
CPUDEF_INIT(0x2965, 13, 2, 47, 0x08000000U, "z13s", "IBM z13s GA1"),
};
+void s390_cpudef_featoff(uint8_t gen, uint8_t ec_ga, S390Feat feat)
+{
+ const S390CPUDef *def;
+
+ def = s390_find_cpu_def(0, gen, ec_ga, NULL);
+ clear_bit(feat, (unsigned long *)&def->default_feat);
+}
+
+void s390_cpudef_featoff_greater(uint8_t gen, uint8_t ec_ga, S390Feat feat)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) {
+ const S390CPUDef *def = &s390_cpu_defs[i];
+
+ if (def->gen < gen) {
+ continue;
+ }
+ if (def->gen == gen && def->ec_ga < ec_ga) {
+ continue;
+ }
+
+ clear_bit(feat, (unsigned long *)&def->default_feat);
+ }
+}
+
uint32_t s390_get_hmfai(void)
{
static S390CPU *cpu;
@@ -671,15 +697,40 @@ static void check_consistency(const S390CPUModel *model)
{ S390_FEAT_SIE_CMMA, S390_FEAT_CMM },
{ S390_FEAT_SIE_CMMA, S390_FEAT_SIE_GSLS },
{ S390_FEAT_SIE_PFMFI, S390_FEAT_EDAT },
+ { S390_FEAT_MSA_EXT_8, S390_FEAT_MSA_EXT_3 },
+ { S390_FEAT_MULTIPLE_EPOCH, S390_FEAT_TOD_CLOCK_STEERING },
+ { S390_FEAT_VECTOR_PACKED_DECIMAL, S390_FEAT_VECTOR },
+ { S390_FEAT_VECTOR_ENH, S390_FEAT_VECTOR },
+ { S390_FEAT_INSTRUCTION_EXEC_PROT, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2 },
+ { S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2, S390_FEAT_ESOP },
+ { S390_FEAT_CMM_NT, S390_FEAT_CMM },
+ { S390_FEAT_GUARDED_STORAGE, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2 },
+ { S390_FEAT_MULTIPLE_EPOCH, S390_FEAT_STORE_CLOCK_FAST },
+ { S390_FEAT_MULTIPLE_EPOCH, S390_FEAT_TOD_CLOCK_STEERING },
+ { S390_FEAT_SEMAPHORE_ASSIST, S390_FEAT_STFLE_49 },
+ { S390_FEAT_KIMD_SHA3_224, S390_FEAT_MSA },
+ { S390_FEAT_KIMD_SHA3_256, S390_FEAT_MSA },
+ { S390_FEAT_KIMD_SHA3_384, S390_FEAT_MSA },
+ { S390_FEAT_KIMD_SHA3_512, S390_FEAT_MSA },
+ { S390_FEAT_KIMD_SHAKE_128, S390_FEAT_MSA },
+ { S390_FEAT_KIMD_SHAKE_256, S390_FEAT_MSA },
+ { S390_FEAT_KLMD_SHA3_224, S390_FEAT_MSA },
+ { S390_FEAT_KLMD_SHA3_256, S390_FEAT_MSA },
+ { S390_FEAT_KLMD_SHA3_384, S390_FEAT_MSA },
+ { S390_FEAT_KLMD_SHA3_512, S390_FEAT_MSA },
+ { S390_FEAT_KLMD_SHAKE_128, S390_FEAT_MSA },
+ { S390_FEAT_KLMD_SHAKE_256, S390_FEAT_MSA },
+ { S390_FEAT_PRNO_TRNG_QRTCR, S390_FEAT_MSA_EXT_5 },
+ { S390_FEAT_PRNO_TRNG, S390_FEAT_MSA_EXT_5 },
};
int i;
for (i = 0; i < ARRAY_SIZE(dep); i++) {
if (test_bit(dep[i][0], model->features) &&
!test_bit(dep[i][1], model->features)) {
- error_report("Warning: \'%s\' requires \'%s\'.",
- s390_feat_def(dep[i][0])->name,
- s390_feat_def(dep[i][1])->name);
+ warn_report("\'%s\' requires \'%s\'.",
+ s390_feat_def(dep[i][0])->name,
+ s390_feat_def(dep[i][1])->name);
}
}
}
diff --git a/target/s390x/cpu_models.h b/target/s390x/cpu_models.h
index d41f8d6e38..c0bee15d7a 100644
--- a/target/s390x/cpu_models.h
+++ b/target/s390x/cpu_models.h
@@ -72,6 +72,8 @@ typedef struct S390CPUModel {
#define ibc_gen(x) (x == 0 ? 0 : ((x >> 4) + S390_GEN_Z10))
#define ibc_ec_ga(x) (x & 0xf)
+void s390_cpudef_featoff(uint8_t gen, uint8_t ec_ga, S390Feat feat);
+void s390_cpudef_featoff_greater(uint8_t gen, uint8_t ec_ga, S390Feat feat);
uint32_t s390_get_hmfai(void);
uint8_t s390_get_mha_pow(void);
uint32_t s390_get_ibc_val(void);
diff --git a/target/s390x/gdbstub.c b/target/s390x/gdbstub.c
index 94ab74d58f..a7efafee9f 100644
--- a/target/s390x/gdbstub.c
+++ b/target/s390x/gdbstub.c
@@ -286,6 +286,26 @@ static int cpu_write_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
}
#endif
+/* the values represent the positions in s390-gs.xml */
+#define S390_GS_RESERVED_REGNUM 0
+#define S390_GS_GSD_REGNUM 1
+#define S390_GS_GSSM_REGNUM 2
+#define S390_GS_GSEPLA_REGNUM 3
+/* total number of registers in s390-gs.xml */
+#define S390_NUM_GS_REGS 4
+
+static int cpu_read_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+{
+ return gdb_get_regl(mem_buf, env->gscb[n]);
+}
+
+static int cpu_write_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+{
+ env->gscb[n] = ldtul_p(mem_buf);
+ cpu_synchronize_post_init(ENV_GET_CPU(env));
+ return 8;
+}
+
void s390_cpu_gdb_init(CPUState *cs)
{
gdb_register_coprocessor(cs, cpu_read_ac_reg,
@@ -300,6 +320,10 @@ void s390_cpu_gdb_init(CPUState *cs)
cpu_write_vreg,
S390_NUM_VREGS, "s390-vx.xml", 0);
+ gdb_register_coprocessor(cs, cpu_read_gs_reg,
+ cpu_write_gs_reg,
+ S390_NUM_GS_REGS, "s390-gs.xml", 0);
+
#ifndef CONFIG_USER_ONLY
gdb_register_coprocessor(cs, cpu_read_c_reg,
cpu_write_c_reg,
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index e674738ae3..af14b11199 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -182,6 +182,33 @@
S390_FEAT_MSA_EXT_5, \
S390_FEAT_PPNO_SHA_512_DRNG
+#define S390_FEAT_GROUP_MSA_EXT_6 \
+ S390_FEAT_KIMD_SHA3_224, \
+ S390_FEAT_KIMD_SHA3_256, \
+ S390_FEAT_KIMD_SHA3_384, \
+ S390_FEAT_KIMD_SHA3_512, \
+ S390_FEAT_KIMD_SHAKE_128, \
+ S390_FEAT_KIMD_SHAKE_256, \
+ S390_FEAT_KLMD_SHA3_224, \
+ S390_FEAT_KLMD_SHA3_256, \
+ S390_FEAT_KLMD_SHA3_384, \
+ S390_FEAT_KLMD_SHA3_512, \
+ S390_FEAT_KLMD_SHAKE_128, \
+ S390_FEAT_KLMD_SHAKE_256
+
+#define S390_FEAT_GROUP_MSA_EXT_7 \
+ S390_FEAT_PRNO_TRNG_QRTCR, \
+ S390_FEAT_PRNO_TRNG
+
+#define S390_FEAT_GROUP_MSA_EXT_8 \
+ S390_FEAT_MSA_EXT_8, \
+ S390_FEAT_KMA_GCM_AES_128, \
+ S390_FEAT_KMA_GCM_AES_192, \
+ S390_FEAT_KMA_GCM_AES_256 , \
+ S390_FEAT_KMA_GCM_EAES_128, \
+ S390_FEAT_KMA_GCM_EAES_192, \
+ S390_FEAT_KMA_GCM_EAES_256
+
/* cpu feature groups */
static uint16_t group_PLO[] = {
S390_FEAT_GROUP_PLO,
@@ -210,15 +237,30 @@ static uint16_t group_MSA_EXT_4[] = {
static uint16_t group_MSA_EXT_5[] = {
S390_FEAT_GROUP_MSA_EXT_5,
};
+static uint16_t group_MSA_EXT_6[] = {
+ S390_FEAT_GROUP_MSA_EXT_6,
+};
+static uint16_t group_MSA_EXT_7[] = {
+ S390_FEAT_GROUP_MSA_EXT_7,
+};
+static uint16_t group_MSA_EXT_8[] = {
+ S390_FEAT_GROUP_MSA_EXT_8,
+};
-/* base features in order of release */
+/* Base features (in order of release)
+ * Only non-hypervisor managed features belong here.
+ * Base feature sets are static meaning they do not change in future QEMU
+ * releases.
+ */
static uint16_t base_GEN7_GA1[] = {
S390_FEAT_GROUP_PLO,
S390_FEAT_ESAN3,
S390_FEAT_ZARCH,
};
+
#define base_GEN7_GA2 EmptyFeat
#define base_GEN7_GA3 EmptyFeat
+
static uint16_t base_GEN8_GA1[] = {
S390_FEAT_DAT_ENH,
S390_FEAT_EXTENDED_TRANSLATION_2,
@@ -227,10 +269,12 @@ static uint16_t base_GEN8_GA1[] = {
S390_FEAT_LONG_DISPLACEMENT_FAST,
S390_FEAT_HFP_MADDSUB,
};
+
#define base_GEN8_GA2 EmptyFeat
#define base_GEN8_GA3 EmptyFeat
#define base_GEN8_GA4 EmptyFeat
#define base_GEN8_GA5 EmptyFeat
+
static uint16_t base_GEN9_GA1[] = {
S390_FEAT_IDTE_SEGMENT,
S390_FEAT_ASN_LX_REUSE,
@@ -245,8 +289,10 @@ static uint16_t base_GEN9_GA1[] = {
S390_FEAT_ETF3_ENH,
S390_FEAT_DAT_ENH_2,
};
+
#define base_GEN9_GA2 EmptyFeat
#define base_GEN9_GA3 EmptyFeat
+
static uint16_t base_GEN10_GA1[] = {
S390_FEAT_CONDITIONAL_SSKE,
S390_FEAT_PARSING_ENH,
@@ -263,6 +309,7 @@ static uint16_t base_GEN10_GA1[] = {
};
#define base_GEN10_GA2 EmptyFeat
#define base_GEN10_GA3 EmptyFeat
+
static uint16_t base_GEN11_GA1[] = {
S390_FEAT_NONQ_KEY_SETTING,
S390_FEAT_ENHANCED_MONITOR,
@@ -272,21 +319,30 @@ static uint16_t base_GEN11_GA1[] = {
S390_FEAT_CMPSC_ENH,
S390_FEAT_INTERLOCKED_ACCESS_2,
};
+
#define base_GEN11_GA2 EmptyFeat
+
static uint16_t base_GEN12_GA1[] = {
S390_FEAT_DFP_ZONED_CONVERSION,
S390_FEAT_STFLE_49,
S390_FEAT_LOCAL_TLB_CLEARING,
};
+
#define base_GEN12_GA2 EmptyFeat
+
static uint16_t base_GEN13_GA1[] = {
S390_FEAT_STFLE_53,
S390_FEAT_DFP_PACKED_CONVERSION,
S390_FEAT_GROUP_GEN13_PTFF,
};
+
#define base_GEN13_GA2 EmptyFeat
-/* full features differing to the base in order of release */
+/* Full features (in order of release)
+ * Automatically includes corresponding base features.
+ * Full features are all features this hardware supports even if kvm/QEMU do not
+ * support these features yet.
+ */
static uint16_t full_GEN7_GA1[] = {
S390_FEAT_SIE_F2,
S390_FEAT_SIE_SKEY,
@@ -294,30 +350,38 @@ static uint16_t full_GEN7_GA1[] = {
S390_FEAT_SIE_IB,
S390_FEAT_SIE_CEI,
};
+
static uint16_t full_GEN7_GA2[] = {
S390_FEAT_EXTENDED_TRANSLATION_2,
};
+
static uint16_t full_GEN7_GA3[] = {
S390_FEAT_LONG_DISPLACEMENT,
S390_FEAT_SIE_SIIF,
};
+
static uint16_t full_GEN8_GA1[] = {
S390_FEAT_SIE_GSLS,
S390_FEAT_SIE_64BSCAO,
};
+
#define full_GEN8_GA2 EmptyFeat
+
static uint16_t full_GEN8_GA3[] = {
S390_FEAT_ASN_LX_REUSE,
S390_FEAT_EXTENDED_TRANSLATION_3,
};
+
#define full_GEN8_GA4 EmptyFeat
#define full_GEN8_GA5 EmptyFeat
+
static uint16_t full_GEN9_GA1[] = {
S390_FEAT_STORE_HYPERVISOR_INFO,
S390_FEAT_GROUP_MSA_EXT_1,
S390_FEAT_CMM,
S390_FEAT_SIE_CMMA,
};
+
static uint16_t full_GEN9_GA2[] = {
S390_FEAT_MOVE_WITH_OPTIONAL_SPEC,
S390_FEAT_EXTRACT_CPU_TIME,
@@ -325,10 +389,12 @@ static uint16_t full_GEN9_GA2[] = {
S390_FEAT_FLOATING_POINT_SUPPPORT_ENH,
S390_FEAT_DFP,
};
+
static uint16_t full_GEN9_GA3[] = {
S390_FEAT_CONDITIONAL_SSKE,
S390_FEAT_PFPO,
};
+
static uint16_t full_GEN10_GA1[] = {
S390_FEAT_EDAT,
S390_FEAT_CONFIGURATION_TOPOLOGY,
@@ -337,34 +403,50 @@ static uint16_t full_GEN10_GA1[] = {
S390_FEAT_SIE_PFMFI,
S390_FEAT_SIE_SIGPIF,
};
+
static uint16_t full_GEN10_GA2[] = {
S390_FEAT_SET_PROGRAM_PARAMETERS,
S390_FEAT_SIE_IBS,
};
+
static uint16_t full_GEN10_GA3[] = {
S390_FEAT_GROUP_MSA_EXT_3,
};
+
static uint16_t full_GEN11_GA1[] = {
S390_FEAT_IPTE_RANGE,
S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION,
S390_FEAT_GROUP_MSA_EXT_4,
};
+
#define full_GEN11_GA2 EmptyFeat
+
static uint16_t full_GEN12_GA1[] = {
S390_FEAT_CONSTRAINT_TRANSACTIONAL_EXE,
S390_FEAT_TRANSACTIONAL_EXE,
S390_FEAT_RUNTIME_INSTRUMENTATION,
+ S390_FEAT_ZPCI,
+ S390_FEAT_ADAPTER_EVENT_NOTIFICATION,
+ S390_FEAT_ADAPTER_INT_SUPPRESSION,
S390_FEAT_EDAT_2,
+ S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2,
};
+
static uint16_t full_GEN12_GA2[] = {
S390_FEAT_GROUP_MSA_EXT_5,
};
+
static uint16_t full_GEN13_GA1[] = {
S390_FEAT_VECTOR,
};
+
#define full_GEN13_GA2 EmptyFeat
-/* default features differing to the base in order of release */
+/* Default features (in order of release)
+ * Automatically includes corresponding base features.
+ * Default features are all features this version of QEMU supports for this
+ * hardware model. Default feature sets can grow with new QEMU releases.
+ */
#define default_GEN7_GA1 EmptyFeat
#define default_GEN7_GA2 EmptyFeat
#define default_GEN7_GA3 EmptyFeat
@@ -373,37 +455,51 @@ static uint16_t full_GEN13_GA1[] = {
#define default_GEN8_GA3 EmptyFeat
#define default_GEN8_GA4 EmptyFeat
#define default_GEN8_GA5 EmptyFeat
+
static uint16_t default_GEN9_GA1[] = {
S390_FEAT_STORE_HYPERVISOR_INFO,
S390_FEAT_GROUP_MSA_EXT_1,
S390_FEAT_CMM,
};
+
#define default_GEN9_GA2 EmptyFeat
#define default_GEN9_GA3 EmptyFeat
+
static uint16_t default_GEN10_GA1[] = {
S390_FEAT_EDAT,
S390_FEAT_GROUP_MSA_EXT_2,
};
+
#define default_GEN10_GA2 EmptyFeat
#define default_GEN10_GA3 EmptyFeat
+
static uint16_t default_GEN11_GA1[] = {
S390_FEAT_GROUP_MSA_EXT_3,
S390_FEAT_IPTE_RANGE,
S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION,
S390_FEAT_GROUP_MSA_EXT_4,
};
+
#define default_GEN11_GA2 EmptyFeat
+
static uint16_t default_GEN12_GA1[] = {
S390_FEAT_CONSTRAINT_TRANSACTIONAL_EXE,
S390_FEAT_TRANSACTIONAL_EXE,
S390_FEAT_RUNTIME_INSTRUMENTATION,
+ S390_FEAT_ZPCI,
+ S390_FEAT_ADAPTER_EVENT_NOTIFICATION,
S390_FEAT_EDAT_2,
+ S390_FEAT_ESOP,
+ S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2,
};
+
#define default_GEN12_GA2 EmptyFeat
+
static uint16_t default_GEN13_GA1[] = {
S390_FEAT_GROUP_MSA_EXT_5,
S390_FEAT_VECTOR,
};
+
#define default_GEN13_GA2 EmptyFeat
/****** END FEATURE DEFS ******/
@@ -491,6 +587,9 @@ static FeatGroupDefSpec FeatGroupDef[] = {
FEAT_GROUP_INITIALIZER(MSA_EXT_3),
FEAT_GROUP_INITIALIZER(MSA_EXT_4),
FEAT_GROUP_INITIALIZER(MSA_EXT_5),
+ FEAT_GROUP_INITIALIZER(MSA_EXT_6),
+ FEAT_GROUP_INITIALIZER(MSA_EXT_7),
+ FEAT_GROUP_INITIALIZER(MSA_EXT_8),
};
static void set_bits(uint64_t list[], BitSpec bits)
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index a3d00196f4..831492f9a2 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -139,6 +139,9 @@ static int cap_async_pf;
static int cap_mem_op;
static int cap_s390_irq;
static int cap_ri;
+static int cap_gs;
+
+static int active_cmma;
static void *legacy_s390_alloc(size_t size, uint64_t *align);
@@ -177,6 +180,11 @@ int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit)
return kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr);
}
+int kvm_s390_cmma_active(void)
+{
+ return active_cmma;
+}
+
static bool kvm_s390_cmma_available(void)
{
static bool initialized, value;
@@ -197,7 +205,7 @@ void kvm_s390_cmma_reset(void)
.attr = KVM_S390_VM_MEM_CLR_CMMA,
};
- if (mem_path || !kvm_s390_cmma_available()) {
+ if (!kvm_s390_cmma_active()) {
return;
}
@@ -213,7 +221,13 @@ static void kvm_s390_enable_cmma(void)
.attr = KVM_S390_VM_MEM_ENABLE_CMMA,
};
+ if (mem_path) {
+ error_report("Warning: CMM will not be enabled because it is not "
+ "compatible to hugetlbfs.");
+ return;
+ }
rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+ active_cmma = !rc;
trace_kvm_enable_cmma(rc);
}
@@ -288,6 +302,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_ri = 1;
}
}
+ if (gs_allowed()) {
+ if (kvm_vm_enable_cap(s, KVM_CAP_S390_GS, 0) == 0) {
+ cap_gs = 1;
+ }
+ }
+
+ /* Try to enable AIS facility */
+ kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0);
qemu_mutex_init(&qemu_sigp_mutex);
@@ -456,6 +478,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
}
}
+ if (can_sync_regs(cs, KVM_SYNC_GSCB)) {
+ memcpy(cs->kvm_run->s.regs.gscb, env->gscb, 32);
+ cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GSCB;
+ }
+
/* Finally the prefix */
if (can_sync_regs(cs, KVM_SYNC_PREFIX)) {
cs->kvm_run->s.regs.prefix = env->psa;
@@ -562,6 +589,10 @@ int kvm_arch_get_registers(CPUState *cs)
memcpy(env->riccb, cs->kvm_run->s.regs.riccb, 64);
}
+ if (can_sync_regs(cs, KVM_SYNC_GSCB)) {
+ memcpy(env->gscb, cs->kvm_run->s.regs.gscb, 32);
+ }
+
/* pfault parameters */
if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
env->pfault_token = cs->kvm_run->s.regs.pft;
@@ -1193,7 +1224,21 @@ static int kvm_stpcifc_service_call(S390CPU *cpu, struct kvm_run *run)
static int kvm_sic_service_call(S390CPU *cpu, struct kvm_run *run)
{
- /* NOOP */
+ CPUS390XState *env = &cpu->env;
+ uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
+ uint8_t r3 = run->s390_sieic.ipa & 0x000f;
+ uint8_t isc;
+ uint16_t mode;
+ int r;
+
+ cpu_synchronize_state(CPU(cpu));
+ mode = env->regs[r1] & 0xffff;
+ isc = (env->regs[r3] >> 27) & 0x7;
+ r = css_do_sic(env, isc, mode);
+ if (r) {
+ enter_pgmcheck(cpu, -r);
+ }
+
return 0;
}
@@ -1444,22 +1489,28 @@ static void sigp_stop(CPUState *cs, run_on_cpu_data arg)
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
-#define ADTL_SAVE_AREA_SIZE 1024
-static int kvm_s390_store_adtl_status(S390CPU *cpu, hwaddr addr)
+#define ADTL_GS_OFFSET 1024 /* offset of GS data in adtl save area */
+#define ADTL_GS_MIN_SIZE 2048 /* minimal size of adtl save area for GS */
+static int do_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len)
{
+ hwaddr save = len;
void *mem;
- hwaddr len = ADTL_SAVE_AREA_SIZE;
- mem = cpu_physical_memory_map(addr, &len, 1);
+ mem = cpu_physical_memory_map(addr, &save, 1);
if (!mem) {
return -EFAULT;
}
- if (len != ADTL_SAVE_AREA_SIZE) {
+ if (save != len) {
cpu_physical_memory_unmap(mem, len, 1, 0);
return -EFAULT;
}
- memcpy(mem, &cpu->env.vregs, 512);
+ if (s390_has_feat(S390_FEAT_VECTOR)) {
+ memcpy(mem, &cpu->env.vregs, 512);
+ }
+ if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) && len >= ADTL_GS_MIN_SIZE) {
+ memcpy(mem + ADTL_GS_OFFSET, &cpu->env.gscb, 32);
+ }
cpu_physical_memory_unmap(mem, len, 1, len);
@@ -1555,12 +1606,17 @@ static void sigp_store_status_at_address(CPUState *cs, run_on_cpu_data arg)
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
+#define ADTL_SAVE_LC_MASK 0xfUL
static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
{
S390CPU *cpu = S390_CPU(cs);
SigpInfo *si = arg.host_ptr;
+ uint8_t lc = si->param & ADTL_SAVE_LC_MASK;
+ hwaddr addr = si->param & ~ADTL_SAVE_LC_MASK;
+ hwaddr len = 1UL << (lc ? lc : 10);
- if (!s390_has_feat(S390_FEAT_VECTOR)) {
+ if (!s390_has_feat(S390_FEAT_VECTOR) &&
+ !s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
return;
}
@@ -1571,15 +1627,32 @@ static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
return;
}
- /* parameter must be aligned to 1024-byte boundary */
- if (si->param & 0x3ff) {
+ /* address must be aligned to length */
+ if (addr & (len - 1)) {
+ set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
+ return;
+ }
+
+ /* no GS: only lc == 0 is valid */
+ if (!s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
+ lc != 0) {
+ set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
+ return;
+ }
+
+ /* GS: 0, 10, 11, 12 are valid */
+ if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
+ lc != 0 &&
+ lc != 10 &&
+ lc != 11 &&
+ lc != 12) {
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
return;
}
cpu_synchronize_state(cs);
- if (kvm_s390_store_adtl_status(cpu, si->param)) {
+ if (do_store_adtl_status(cpu, addr, len)) {
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
return;
}
@@ -1727,41 +1800,25 @@ static int sigp_set_architecture(S390CPU *cpu, uint32_t param,
{
CPUState *cur_cs;
S390CPU *cur_cpu;
+ bool all_stopped = true;
- /* due to the BQL, we are the only active cpu */
CPU_FOREACH(cur_cs) {
cur_cpu = S390_CPU(cur_cs);
- if (cur_cpu->env.sigp_order != 0) {
- return SIGP_CC_BUSY;
+
+ if (cur_cpu == cpu) {
+ continue;
}
- cpu_synchronize_state(cur_cs);
- /* all but the current one have to be stopped */
- if (cur_cpu != cpu &&
- s390_cpu_get_state(cur_cpu) != CPU_STATE_STOPPED) {
- *status_reg &= 0xffffffff00000000ULL;
- *status_reg |= SIGP_STAT_INCORRECT_STATE;
- return SIGP_CC_STATUS_STORED;
+ if (s390_cpu_get_state(cur_cpu) != CPU_STATE_STOPPED) {
+ all_stopped = false;
}
}
- switch (param & 0xff) {
- case SIGP_MODE_ESA_S390:
- /* not supported */
- return SIGP_CC_NOT_OPERATIONAL;
- case SIGP_MODE_Z_ARCH_TRANS_ALL_PSW:
- case SIGP_MODE_Z_ARCH_TRANS_CUR_PSW:
- CPU_FOREACH(cur_cs) {
- cur_cpu = S390_CPU(cur_cs);
- cur_cpu->env.pfault_token = -1UL;
- }
- break;
- default:
- *status_reg &= 0xffffffff00000000ULL;
- *status_reg |= SIGP_STAT_INVALID_PARAMETER;
- return SIGP_CC_STATUS_STORED;
- }
+ *status_reg &= 0xffffffff00000000ULL;
- return SIGP_CC_ORDER_CODE_ACCEPTED;
+ /* Reject set arch order, with czam we're always in z/Arch mode. */
+ *status_reg |= (all_stopped ? SIGP_STAT_INVALID_PARAMETER :
+ SIGP_STAT_INCORRECT_STATE);
+ return SIGP_CC_STATUS_STORED;
}
static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
@@ -2174,6 +2231,9 @@ static uint64_t build_channel_report_mcic(void)
if (s390_has_feat(S390_FEAT_VECTOR)) {
mcic |= MCIC_VB_VR;
}
+ if (s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
+ mcic |= MCIC_VB_GS;
+ }
return mcic;
}
@@ -2239,6 +2299,11 @@ int kvm_s390_get_ri(void)
return cap_ri;
}
+int kvm_s390_get_gs(void)
+{
+ return cap_gs;
+}
+
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
{
struct kvm_mp_state mp_state = {};
@@ -2417,6 +2482,9 @@ static int query_cpu_subfunc(S390FeatBitmap features)
if (test_bit(S390_FEAT_MSA_EXT_5, features)) {
s390_add_from_feat_block(features, S390_FEAT_TYPE_PPNO, prop.ppno);
}
+ if (test_bit(S390_FEAT_MSA_EXT_8, features)) {
+ s390_add_from_feat_block(features, S390_FEAT_TYPE_KMA, prop.kma);
+ }
return 0;
}
@@ -2470,6 +2538,10 @@ static int configure_cpu_subfunc(const S390FeatBitmap features)
s390_fill_feat_block(features, S390_FEAT_TYPE_PPNO, prop.ppno);
prop.ppno[0] |= 0x80; /* query is always available */
}
+ if (test_bit(S390_FEAT_MSA_EXT_8, features)) {
+ s390_fill_feat_block(features, S390_FEAT_TYPE_KMA, prop.kma);
+ prop.kma[0] |= 0x80; /* query is always available */
+ }
return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
}
@@ -2487,6 +2559,7 @@ static int kvm_to_feat[][2] = {
{ KVM_S390_VM_CPU_FEAT_CMMA, S390_FEAT_SIE_CMMA },
{ KVM_S390_VM_CPU_FEAT_PFMFI, S390_FEAT_SIE_PFMFI},
{ KVM_S390_VM_CPU_FEAT_SIGPIF, S390_FEAT_SIE_SIGPIF},
+ { KVM_S390_VM_CPU_FEAT_KSS, S390_FEAT_SIE_KSS},
};
static int query_cpu_feat(S390FeatBitmap features)
@@ -2606,8 +2679,15 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
/* with cpu model support, CMM is only indicated if really available */
if (kvm_s390_cmma_available()) {
set_bit(S390_FEAT_CMM, model->features);
+ } else {
+ /* no cmm -> no cmm nt */
+ clear_bit(S390_FEAT_CMM_NT, model->features);
}
+ /* set zpci and aen facilities */
+ set_bit(S390_FEAT_ZPCI, model->features);
+ set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features);
+
if (s390_known_cpu_type(cpu_type)) {
/* we want the exact model, even if some features are missing */
model->def = s390_find_cpu_def(cpu_type, ibc_gen(unblocked_ibc),
@@ -2641,7 +2721,7 @@ void kvm_s390_apply_cpu_model(const S390CPUModel *model, Error **errp)
if (!model) {
/* compatibility handling if cpu models are disabled */
- if (kvm_s390_cmma_available() && !mem_path) {
+ if (kvm_s390_cmma_available()) {
kvm_s390_enable_cmma();
}
return;
@@ -2672,13 +2752,8 @@ void kvm_s390_apply_cpu_model(const S390CPUModel *model, Error **errp)
error_setg(errp, "KVM: Error configuring CPU subfunctions: %d", rc);
return;
}
- /* enable CMM via CMMA - disable on hugetlbfs */
+ /* enable CMM via CMMA */
if (test_bit(S390_FEAT_CMM, model->features)) {
- if (mem_path) {
- error_report("Warning: CMM will not be enabled because it is not "
- "compatible to hugetlbfs.");
- } else {
- kvm_s390_enable_cmma();
- }
+ kvm_s390_enable_cmma();
}
}
diff --git a/target/s390x/machine.c b/target/s390x/machine.c
index 8f908bbe82..2dcadfdd29 100644
--- a/target/s390x/machine.c
+++ b/target/s390x/machine.c
@@ -174,6 +174,22 @@ const VMStateDescription vmstate_exval = {
}
};
+static bool gscb_needed(void *opaque)
+{
+ return kvm_s390_get_gs();
+}
+
+const VMStateDescription vmstate_gscb = {
+ .name = "cpu/gscb",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = gscb_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64_ARRAY(env.gscb, S390CPU, 4),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
const VMStateDescription vmstate_s390_cpu = {
.name = "cpu",
.post_load = cpu_post_load,
@@ -207,6 +223,7 @@ const VMStateDescription vmstate_s390_cpu = {
&vmstate_vregs,
&vmstate_riccb,
&vmstate_exval,
+ &vmstate_gscb,
NULL
},
};
diff --git a/target/xtensa/gdbstub.c b/target/xtensa/gdbstub.c
index da131ae8cc..d78a1b437d 100644
--- a/target/xtensa/gdbstub.c
+++ b/target/xtensa/gdbstub.c
@@ -72,7 +72,6 @@ int xtensa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
__func__, n, reg->type);
memset(mem_buf, 0, reg->size);
return reg->size;
- return 0;
}
}
diff --git a/target/xtensa/xtensa-semi.c b/target/xtensa/xtensa-semi.c
index 32e2bd7f1d..7aa1d1357b 100644
--- a/target/xtensa/xtensa-semi.c
+++ b/target/xtensa/xtensa-semi.c
@@ -158,7 +158,7 @@ void xtensa_sim_open_console(Chardev *chr)
static CharBackend console;
qemu_chr_fe_init(&console, chr, &error_abort);
- qemu_chr_fe_set_handlers(&console, NULL, NULL, NULL, NULL, NULL, true);
+ qemu_chr_fe_set_handlers(&console, NULL, NULL, NULL, NULL, NULL, NULL, true);
xtensa_sim_console = &console;
}
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 18cd06a6b3..cfbb689e0e 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -554,7 +554,7 @@ tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-u
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y)
-tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y)
+tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y)
tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o
tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o migration/xbzrle.o migration/page_cache.o $(test-util-obj-y)
tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o
@@ -761,7 +761,7 @@ tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y)
tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o
tests/test-qapi-util$(EXESUF): tests/test-qapi-util.o $(test-util-obj-y)
tests/numa-test$(EXESUF): tests/numa-test.o
-tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/acpi-utils.o
+tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/boot-sector.o tests/acpi-utils.o
tests/migration/stress$(EXESUF): tests/migration/stress.o
$(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@")
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
index 037cb9e9e7..012a2fc1af 100644
--- a/tests/docker/Makefile.include
+++ b/tests/docker/Makefile.include
@@ -106,6 +106,8 @@ docker:
@echo ' (default is 1)'
@echo ' DEBUG=1 Stop and drop to shell in the created container'
@echo ' before running the command.'
+ @echo ' NETWORK=1 Enable virtual network interface with default backend.'
+ @echo ' NETWORK=$BACKEND Enable virtual network interface with $BACKEND.'
@echo ' NOUSER Define to disable adding current user to containers passwd.'
@echo ' NOCACHE=1 Ignore cache when build images.'
@echo ' EXECUTABLE=<path> Include executable in image.'
@@ -132,7 +134,8 @@ docker-run: docker-qemu-src
$(SRC_PATH)/tests/docker/docker.py run \
$(if $(NOUSER),,-u $(shell id -u)) -t \
$(if $V,,--rm) \
- $(if $(DEBUG),-i,--net=none) \
+ $(if $(DEBUG),-i,) \
+ $(if $(NETWORK),$(if $(subst $(NETWORK),,1),--net=$(NETWORK)),--net=none) \
-e TARGET_LIST=$(TARGET_LIST) \
-e EXTRA_CONFIGURE_OPTS="$(EXTRA_CONFIGURE_OPTS)" \
-e V=$V -e J=$J -e DEBUG=$(DEBUG) \
diff --git a/tests/docker/docker.py b/tests/docker/docker.py
index e707e5bcca..ee40ca04d9 100755
--- a/tests/docker/docker.py
+++ b/tests/docker/docker.py
@@ -112,13 +112,16 @@ class Docker(object):
signal.signal(signal.SIGTERM, self._kill_instances)
signal.signal(signal.SIGHUP, self._kill_instances)
- def _do(self, cmd, quiet=True, infile=None, **kwargs):
+ def _do(self, cmd, quiet=True, **kwargs):
if quiet:
kwargs["stdout"] = DEVNULL
- if infile:
- kwargs["stdin"] = infile
return subprocess.call(self._command + cmd, **kwargs)
+ def _do_check(self, cmd, quiet=True, **kwargs):
+ if quiet:
+ kwargs["stdout"] = DEVNULL
+ return subprocess.check_call(self._command + cmd, **kwargs)
+
def _do_kill_instances(self, only_known, only_active=True):
cmd = ["ps", "-q"]
if not only_active:
@@ -177,14 +180,14 @@ class Docker(object):
extra_files_cksum)))
tmp_df.flush()
- self._do(["build", "-t", tag, "-f", tmp_df.name] + argv + \
- [docker_dir],
- quiet=quiet)
+ self._do_check(["build", "-t", tag, "-f", tmp_df.name] + argv + \
+ [docker_dir],
+ quiet=quiet)
def update_image(self, tag, tarball, quiet=True):
"Update a tagged image using "
- self._do(["build", "-t", tag, "-"], quiet=quiet, infile=tarball)
+ self._do_check(["build", "-t", tag, "-"], quiet=quiet, stdin=tarball)
def image_matches_dockerfile(self, tag, dockerfile):
try:
@@ -197,9 +200,9 @@ class Docker(object):
label = uuid.uuid1().hex
if not keep:
self._instances.append(label)
- ret = self._do(["run", "--label",
- "com.qemu.instance.uuid=" + label] + cmd,
- quiet=quiet)
+ ret = self._do_check(["run", "--label",
+ "com.qemu.instance.uuid=" + label] + cmd,
+ quiet=quiet)
if not keep:
self._instances.remove(label)
return ret
diff --git a/tests/multiboot/run_test.sh b/tests/multiboot/run_test.sh
index 78d7edfc3b..c8f3da8f37 100755
--- a/tests/multiboot/run_test.sh
+++ b/tests/multiboot/run_test.sh
@@ -26,7 +26,7 @@ run_qemu() {
local kernel=$1
shift
- echo -e "\n\n=== Running test case: $kernel $@ ===\n" >> test.log
+ printf %b "\n\n=== Running test case: $kernel $@ ===\n\n" >> test.log
$QEMU \
-kernel $kernel \
@@ -68,21 +68,21 @@ for t in mmap modules; do
pass=1
if [ $debugexit != 1 ]; then
- echo -e "\e[31m ?? \e[0m $t (no debugexit used, exit code $ret)"
+ printf %b "\e[31m ?? \e[0m $t (no debugexit used, exit code $ret)\n"
pass=0
elif [ $ret != 0 ]; then
- echo -e "\e[31mFAIL\e[0m $t (exit code $ret)"
+ printf %b "\e[31mFAIL\e[0m $t (exit code $ret)\n"
pass=0
fi
if ! diff $t.out test.log > /dev/null 2>&1; then
- echo -e "\e[31mFAIL\e[0m $t (output difference)"
+ printf %b "\e[31mFAIL\e[0m $t (output difference)\n"
diff -u $t.out test.log
pass=0
fi
if [ $pass == 1 ]; then
- echo -e "\e[32mPASS\e[0m $t"
+ printf %b "\e[32mPASS\e[0m $t\n"
fi
done
diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033
index 16edcf2f00..2cdfd1397a 100755
--- a/tests/qemu-iotests/033
+++ b/tests/qemu-iotests/033
@@ -50,10 +50,18 @@ do_test()
local align=$1
local iocmd=$2
local img=$3
+ if [ "$IMGOPTSSYNTAX" = "true" ]
+ then
+ IO_OPEN_ARG="$img"
+ IO_EXTRA_ARGS="--image-opts"
+ else
+ IO_OPEN_ARG="-o driver=$IMGFMT,file.align=$align blkdebug::$img"
+ IO_EXTRA_ARGS=""
+ fi
{
- echo "open -o driver=$IMGFMT,file.align=$align blkdebug::$img"
+ echo "open $IO_OPEN_ARG"
echo $iocmd
- } | $QEMU_IO
+ } | $QEMU_IO $IO_EXTRA_ARGS
}
for write_zero_cmd in "write -z" "aio_write -z"; do
diff --git a/tests/qemu-iotests/042 b/tests/qemu-iotests/042
index 351b2830a2..a53e7cb757 100755
--- a/tests/qemu-iotests/042
+++ b/tests/qemu-iotests/042
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-_supported_fmt qcow2 qcow qed
+_supported_fmt qcow2 qed
_supported_proto file
_supported_os Linux
diff --git a/tests/qemu-iotests/044.out b/tests/qemu-iotests/044.out
index 4789a5310e..703cf3dee1 100644
--- a/tests/qemu-iotests/044.out
+++ b/tests/qemu-iotests/044.out
@@ -1,6 +1,6 @@
No errors were found on the image.
7292415/33554432 = 21.73% allocated, 0.00% fragmented, 0.00% compressed clusters
-Image end offset: 4296152064
+Image end offset: 4296217088
.
----------------------------------------------------------------------
Ran 1 tests
diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048
index 203c04fc7f..9ed04a068d 100755
--- a/tests/qemu-iotests/048
+++ b/tests/qemu-iotests/048
@@ -46,7 +46,7 @@ _compare()
. ./common.filter
. ./common.pattern
-_supported_fmt raw qcow qcow2 qed luks
+_supported_fmt raw qcow2 qed luks
_supported_proto file
_supported_os Linux
diff --git a/tests/qemu-iotests/049 b/tests/qemu-iotests/049
index fff07604fc..df35b6d21e 100755
--- a/tests/qemu-iotests/049
+++ b/tests/qemu-iotests/049
@@ -106,7 +106,7 @@ test_qemu_img create -f $IMGFMT -o preallocation=1234 "$TEST_IMG" 64M
echo "== Check encryption option =="
echo
test_qemu_img create -f $IMGFMT -o encryption=off "$TEST_IMG" 64M
-test_qemu_img create -f $IMGFMT -o encryption=on "$TEST_IMG" 64M
+test_qemu_img create -f $IMGFMT --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 "$TEST_IMG" 64M
echo "== Check lazy_refcounts option (only with v3) =="
echo
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
index 34e66db691..003247023e 100644
--- a/tests/qemu-iotests/049.out
+++ b/tests/qemu-iotests/049.out
@@ -4,90 +4,90 @@ QA output created by 049
== 1. Traditional size parameter ==
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024b
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1k
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1K
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1G
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1T
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0b
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5k
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5K
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5G
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5T
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16
== 2. Specifying size via -o ==
qemu-img create -f qcow2 -o size=1024 TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1024b TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1k TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1K TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1M TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1G TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1T TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1024.0 TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1024.0b TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5k TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5K TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5M TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5G TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5T TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16
== 3. Invalid sizes ==
@@ -128,84 +128,84 @@ qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'
== Check correct interpretation of suffixes for cluster size ==
qemu-img create -f qcow2 -o cluster_size=1024 TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1024b TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1k TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1K TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1M TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1048576 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1048576 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1024.0 TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1024.0b TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=0.5k TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=0.5K TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=0.5M TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=524288 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=524288 lazy_refcounts=off refcount_bits=16
== Check compat level option ==
qemu-img create -f qcow2 -o compat=0.10 TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: '0.42'
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: 'foobar'
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar cluster_size=65536 lazy_refcounts=off refcount_bits=16
== Check preallocation option ==
qemu-img create -f qcow2 -o preallocation=off TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation=off lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=off lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: invalid parameter value: 1234
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16
== Check encryption option ==
qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-qemu-img create -f qcow2 -o encryption=on TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off refcount_bits=16
+qemu-img create -f qcow2 --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on encrypt.key-secret=sec0 cluster_size=65536 lazy_refcounts=off refcount_bits=16
== Check lazy_refcounts option (only with v3) ==
qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=off TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=on TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 encryption=off cluster_size=65536 lazy_refcounts=on refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=on refcount_bits=16
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 encryption=off cluster_size=65536 lazy_refcounts=on refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=on refcount_bits=16
*** done
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 26c29deb51..c8cfc764bc 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -217,7 +217,7 @@ run_qemu -drive driver=null-co,cache=invalid_value
# Test 142 checks the direct=on cases
for cache in writeback writethrough unsafe invalid_value; do
- echo -e "info block\ninfo block file\ninfo block backing\ninfo block backing-file" | \
+ printf "info block %s\n" '' file backing backing-file | \
run_qemu -drive file="$TEST_IMG",cache=$cache,backing.file.filename="$TEST_IMG.base",backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=$device_id -nodefaults
done
@@ -325,8 +325,9 @@ echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_I
$QEMU_IO -c "read -P 0x22 0 4k" "$TEST_IMG" | _filter_qemu_io
-echo -e "qemu-io $device_id \"write -P 0x33 0 4k\"\ncommit $device_id" | run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id\
- | _filter_qemu_io
+printf %b "qemu-io $device_id \"write -P 0x33 0 4k\"\ncommit $device_id\n" |
+ run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id |
+ _filter_qemu_io
$QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
index 3801b65b9d..cfa0f2aed5 100755
--- a/tests/qemu-iotests/068
+++ b/tests/qemu-iotests/068
@@ -76,7 +76,7 @@ for extra_args in \
_make_test_img $IMG_SIZE
# Give qemu some time to boot before saving the VM state
- bash -c 'sleep 1; echo -e "savevm 0\nquit"' | _qemu $extra_args
+ { sleep 1; printf "savevm 0\nquit\n"; } | _qemu $extra_args
# Now try to continue from that VM state (this should just work)
echo quit | _qemu $extra_args -loadvm 0
done
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
index a952330ba5..dbed67f2ba 100644
--- a/tests/qemu-iotests/082.out
+++ b/tests/qemu-iotests/082.out
@@ -3,14 +3,14 @@ QA output created by 082
=== create: Options specified more than once ===
Testing: create -f foo -f qcow2 TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 128M (134217728 bytes)
cluster_size: 65536
Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=4096 lazy_refcounts=on refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=4096 lazy_refcounts=on refcount_bits=16
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 128M (134217728 bytes)
@@ -22,7 +22,7 @@ Format specific information:
corrupt: false
Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=8192 lazy_refcounts=on refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=on refcount_bits=16
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 128M (134217728 bytes)
@@ -34,7 +34,7 @@ Format specific information:
corrupt: false
Testing: create -f qcow2 -o cluster_size=4k,cluster_size=8k TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=8192 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=off refcount_bits=16
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 128M (134217728 bytes)
@@ -48,7 +48,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -61,7 +69,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -74,7 +90,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -87,7 +111,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -100,7 +132,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -113,7 +153,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -126,7 +174,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -139,7 +195,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -147,10 +211,10 @@ refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help cluster_size=65536 lazy_refcounts=off refcount_bits=16
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,? encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,? cluster_size=65536 lazy_refcounts=off refcount_bits=16
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2, -o help TEST_DIR/t.qcow2 128M
qemu-img: Invalid option list: backing_file=TEST_DIR/t.qcow2,
@@ -167,7 +231,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -180,7 +252,7 @@ size Virtual disk size
=== convert: Options specified more than once ===
Testing: create -f qcow2 TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Testing: convert -f foo -f qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
image: TEST_DIR/t.IMGFMT.base
@@ -229,7 +301,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -242,7 +322,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -255,7 +343,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -268,7 +364,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -281,7 +385,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -294,7 +406,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -307,7 +427,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -320,7 +448,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -348,7 +484,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -407,7 +551,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -420,7 +572,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -433,7 +593,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -446,7 +614,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -459,7 +635,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -472,7 +656,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -485,7 +677,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -498,7 +698,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
@@ -528,7 +736,15 @@ size Virtual disk size
compat Compatibility level (0.10 or 1.1)
backing_file File name of a base image
backing_fmt Image format of the base image
-encryption Encrypt the image
+encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
+encrypt.format Encrypt the image, format choices: 'aes', 'luks'
+encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
+encrypt.cipher-alg Name of encryption cipher algorithm
+encrypt.cipher-mode Name of encryption cipher mode
+encrypt.ivgen-alg Name of IV generator algorithm
+encrypt.ivgen-hash-alg Name of IV generator hash algorithm
+encrypt.hash-alg Name of encryption hash algorithm
+encrypt.iter-time Time to spend in PBKDF in milliseconds
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out
index a5d4cc3494..6edf107f55 100644
--- a/tests/qemu-iotests/085.out
+++ b/tests/qemu-iotests/085.out
@@ -11,7 +11,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
=== Create a single snapshot on virtio0 ===
-Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
=== Invalid command - missing device and nodename ===
@@ -25,32 +25,32 @@ Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file
=== Create several transactional group snapshots ===
-Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
=== Create a couple of snapshots using blockdev-snapshot ===
diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087
index 6d52f7d1b7..f8e4903f4f 100755
--- a/tests/qemu-iotests/087
+++ b/tests/qemu-iotests/087
@@ -119,12 +119,21 @@ run_qemu <<EOF
EOF
echo
-echo === Encrypted image ===
+echo === Encrypted image QCow ===
echo
-_make_test_img -o encryption=on $size
-run_qemu -S <<EOF
+_make_test_img --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 $size
+run_qemu <<EOF
{ "execute": "qmp_capabilities" }
+{ "execute": "object-add",
+ "arguments": {
+ "qom-type": "secret",
+ "id": "sec0",
+ "props": {
+ "data": "123456"
+ }
+ }
+}
{ "execute": "blockdev-add",
"arguments": {
"driver": "$IMGFMT",
@@ -132,14 +141,32 @@ run_qemu -S <<EOF
"file": {
"driver": "file",
"filename": "$TEST_IMG"
+ },
+ "encrypt": {
+ "format": "aes",
+ "key-secret": "sec0"
}
}
}
{ "execute": "quit" }
EOF
+echo
+echo === Encrypted image LUKS ===
+echo
+
+_make_test_img --object secret,id=sec0,data=123456 -o encrypt.format=luks,encrypt.key-secret=sec0 $size
run_qemu <<EOF
{ "execute": "qmp_capabilities" }
+{ "execute": "object-add",
+ "arguments": {
+ "qom-type": "secret",
+ "id": "sec0",
+ "props": {
+ "data": "123456"
+ }
+ }
+}
{ "execute": "blockdev-add",
"arguments": {
"driver": "$IMGFMT",
@@ -147,6 +174,10 @@ run_qemu <<EOF
"file": {
"driver": "file",
"filename": "$TEST_IMG"
+ },
+ "encrypt": {
+ "format": "luks",
+ "key-secret": "sec0"
}
}
}
@@ -157,7 +188,7 @@ echo
echo === Missing driver ===
echo
-_make_test_img -o encryption=on $size
+_make_test_img --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 $size
run_qemu -S <<EOF
{ "execute": "qmp_capabilities" }
{ "execute": "blockdev-add",
diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out
index 59c5208272..b1318c6ed6 100644
--- a/tests/qemu-iotests/087.out
+++ b/tests/qemu-iotests/087.out
@@ -32,27 +32,33 @@ QMP_VERSION
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-=== Encrypted image ===
+=== Encrypted image QCow ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
-Testing: -S
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0
+Testing:
QMP_VERSION
{"return": {}}
+{"return": {}}
{"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+=== Encrypted image LUKS ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encrypt.format=luks encrypt.key-secret=sec0
Testing:
QMP_VERSION
{"return": {}}
-{"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}}
+{"return": {}}
+{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
=== Missing driver ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0
Testing: -S
QMP_VERSION
{"return": {}}
diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106
new file mode 100755
index 0000000000..32649578fb
--- /dev/null
+++ b/tests/qemu-iotests/106
@@ -0,0 +1,92 @@
+#!/bin/bash
+#
+# Test preallocated resize of raw images
+#
+# Copyright (C) 2017 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=mreitz@redhat.com
+
+seq=$(basename $0)
+echo "QA output created by $seq"
+
+here=$PWD
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment and filters
+. ./common.rc
+. ./common.filter
+
+_supported_fmt raw
+_supported_proto file
+_supported_os Linux
+
+# in kB
+CREATION_SIZE=128
+GROWTH_SIZE=256
+
+echo '=== Testing image growth ==='
+
+for create_mode in off falloc full; do
+ for growth_mode in off falloc full; do
+ echo
+ echo "--- create_mode=$create_mode growth_mode=$growth_mode ---"
+
+ IMGOPTS="preallocation=$create_mode" _make_test_img ${CREATION_SIZE}K
+ $QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K
+
+ expected_size=0
+ if [ $create_mode != off ]; then
+ expected_size=$CREATION_SIZE
+ fi
+ if [ $growth_mode != off ]; then
+ expected_size=$((expected_size + $GROWTH_SIZE))
+ fi
+
+ actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size')
+ actual_size=$(echo "$actual_size" | sed -e 's/^[^0-9]*\([0-9]\+\).*$/\1/')
+
+ # The actual size may exceed the expected size, depending on the file
+ # system. Therefore we just test that the actual size is at least what
+ # we expect.
+ if [ $actual_size -lt $expected_size ]; then
+ echo "ERROR: Image should have at least ${expected_size}K, but has ${actual_size}K"
+ fi
+ done
+done
+
+echo
+echo '=== Testing image shrinking ==='
+
+# None of this should work except for "off", because other modes cannot be used
+# for shrinking
+for growth_mode in falloc full off; do
+ echo
+ echo "--- growth_mode=$growth_mode ---"
+ $QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" -${GROWTH_SIZE}K
+done
+
+# success, all done
+echo '*** done'
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/106.out b/tests/qemu-iotests/106.out
new file mode 100644
index 0000000000..0a42312301
--- /dev/null
+++ b/tests/qemu-iotests/106.out
@@ -0,0 +1,50 @@
+QA output created by 106
+=== Testing image growth ===
+
+--- create_mode=off growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=off
+Image resized.
+
+--- create_mode=off growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=off
+Image resized.
+
+--- create_mode=off growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=off
+Image resized.
+
+--- create_mode=falloc growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=falloc
+Image resized.
+
+--- create_mode=falloc growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=falloc
+Image resized.
+
+--- create_mode=falloc growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=falloc
+Image resized.
+
+--- create_mode=full growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=full
+Image resized.
+
+--- create_mode=full growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=full
+Image resized.
+
+--- create_mode=full growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 preallocation=full
+Image resized.
+
+=== Testing image shrinking ===
+
+--- growth_mode=falloc ---
+qemu-img: Preallocation can only be used for growing images
+
+--- growth_mode=full ---
+qemu-img: Preallocation can only be used for growing images
+
+--- growth_mode=off ---
+Image resized.
+*** done
diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120
index 4f88a67fe1..f40b97d099 100755
--- a/tests/qemu-iotests/120
+++ b/tests/qemu-iotests/120
@@ -41,6 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto file
_supported_os Linux
+_unsupported_fmt luks
_make_test_img 64M
diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125
new file mode 100755
index 0000000000..9424313e82
--- /dev/null
+++ b/tests/qemu-iotests/125
@@ -0,0 +1,130 @@
+#!/bin/bash
+#
+# Test preallocated growth of qcow2 images
+#
+# Copyright (C) 2017 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=mreitz@redhat.com
+
+seq=$(basename $0)
+echo "QA output created by $seq"
+
+here=$PWD
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+get_image_size_on_host()
+{
+ $QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep "disk size" \
+ | sed -e 's/^[^0-9]*\([0-9]\+\).*$/\1/'
+}
+
+# get standard environment and filters
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+if [ -z "$TEST_IMG_FILE" ]; then
+ TEST_IMG_FILE=$TEST_IMG
+fi
+
+# Generally, we create some image with or without existing preallocation and
+# then resize it. Then we write some data into the image and verify that its
+# size does not change if we have used preallocation.
+
+# With a cluster size of 512 B, one L2 table covers 64 * 512 B = 32 kB.
+# One cluster of the L1 table covers 64 * 32 kB = 2 MB.
+# There are multiple cases we want to test:
+# (1) Grow an image without having to allocate a new L2 table.
+# (2) Grow an image, having to allocate a new L2 table.
+# (3) Grow an image, having to grow the L1 table.
+# Therefore, we create an image that is 48 kB below 2 MB. Then:
+# (1) We resize it to 2 MB - 32 kB. (+ 16 kB)
+# (2) We resize it to 2 MB. (+ 48 kB)
+# (3) We resize it to 2 MB + 32 kB. (+ 80 kB)
+
+# in B
+CREATION_SIZE=$((2 * 1024 * 1024 - 48 * 1024))
+
+# in kB
+for GROWTH_SIZE in 16 48 80; do
+ for create_mode in off metadata falloc full; do
+ for growth_mode in off metadata falloc full; do
+ echo "--- growth_size=$GROWTH_SIZE create_mode=$create_mode growth_mode=$growth_mode ---"
+
+ IMGOPTS="preallocation=$create_mode,cluster_size=512" _make_test_img ${CREATION_SIZE}
+ $QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K
+
+ host_size_0=$(get_image_size_on_host)
+ file_length_0=$(stat -c '%s' "$TEST_IMG_FILE")
+
+ $QEMU_IO -c "write 0 $CREATION_SIZE" "$TEST_IMG" | _filter_qemu_io
+
+ host_size_1=$(get_image_size_on_host)
+ file_length_1=$(stat -c '%s' "$TEST_IMG_FILE")
+
+ $QEMU_IO -c "write $CREATION_SIZE ${GROWTH_SIZE}K" "$TEST_IMG" | _filter_qemu_io
+
+ host_size_2=$(get_image_size_on_host)
+ file_length_2=$(stat -c '%s' "$TEST_IMG_FILE")
+
+ # Test creation preallocation: Compare #0 against #1
+ if [ $create_mode != off ]; then
+ # The image length should not have grown
+ if [ $file_length_1 -gt $file_length_0 ]; then
+ echo "ERROR (create): Image length has grown from $file_length_0 to $file_length_1"
+ fi
+ if [ $create_mode != metadata ]; then
+ # The host size should not have grown either
+ if [ $host_size_1 -gt $host_size_0 ]; then
+ echo "ERROR (create): Host size has grown from $host_size_0 to $host_size_1"
+ fi
+ fi
+ fi
+
+ # Test resize preallocation: Compare #2 against #1
+ if [ $growth_mode != off ]; then
+ # The image length should not have grown
+ if [ $file_length_2 -gt $file_length_1 ]; then
+ echo "ERROR (grow): Image length has grown from $file_length_1 to $file_length_2"
+ fi
+ if [ $create_mode != metadata ]; then
+ # The host size should not have grown either
+ if [ $host_size_2 -gt $host_size_1 ]; then
+ echo "ERROR (grow): Host size has grown from $host_size_1 to $host_size_2"
+ fi
+ fi
+ fi
+
+ echo
+ done
+ done
+done
+
+# success, all done
+echo '*** done'
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/125.out b/tests/qemu-iotests/125.out
new file mode 100644
index 0000000000..3f4d6e31a6
--- /dev/null
+++ b/tests/qemu-iotests/125.out
@@ -0,0 +1,386 @@
+QA output created by 125
+--- growth_size=16 create_mode=off growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=off growth_mode=metadata ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=off growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=off growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=metadata growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=metadata growth_mode=metadata ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=metadata growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=metadata growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=falloc growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=falloc growth_mode=metadata ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=falloc growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=falloc growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=full growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=full growth_mode=metadata ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=full growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=16 create_mode=full growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 16384/16384 bytes at offset 2048000
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=off growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=off growth_mode=metadata ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=off growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=off growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=metadata growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=metadata growth_mode=metadata ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=metadata growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=metadata growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=falloc growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=falloc growth_mode=metadata ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=falloc growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=falloc growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=full growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=full growth_mode=metadata ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=full growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=48 create_mode=full growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 49152/49152 bytes at offset 2048000
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=off growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=off growth_mode=metadata ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=off growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=off growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=metadata growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=metadata growth_mode=metadata ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=metadata growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=metadata growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=falloc growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=falloc growth_mode=metadata ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=falloc growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=falloc growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=full growth_mode=off ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=full growth_mode=metadata ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=full growth_mode=falloc ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+--- growth_size=80 create_mode=full growth_mode=full ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
+Image resized.
+wrote 2048000/2048000 bytes at offset 0
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset 2048000
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+*** done
diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126
new file mode 100755
index 0000000000..a2d4d6c73d
--- /dev/null
+++ b/tests/qemu-iotests/126
@@ -0,0 +1,105 @@
+#!/bin/bash
+#
+# Tests handling of colons in filenames (which may be confused with protocol
+# prefixes)
+#
+# Copyright (C) 2017 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=mreitz@redhat.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+here="$PWD"
+status=1 # failure is the default!
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+# Needs backing file support
+_supported_fmt qcow qcow2 qed vmdk
+# This is the default protocol (and we want to test the difference between
+# colons which separate a protocol prefix from the rest and colons which are
+# just part of the filename, so we cannot test protocols which require a prefix)
+_supported_proto file
+_supported_os Linux
+
+echo
+echo '=== Testing plain files ==='
+echo
+
+# A colon after a slash is not a protocol prefix separator
+TEST_IMG="$TEST_DIR/a:b.$IMGFMT" _make_test_img 64M
+_rm_test_img "$TEST_DIR/a:b.$IMGFMT"
+
+# But if you want to be really sure, you can do this
+TEST_IMG="file:$TEST_DIR/a:b.$IMGFMT" _make_test_img 64M
+_rm_test_img "$TEST_DIR/a:b.$IMGFMT"
+
+
+echo
+echo '=== Testing relative backing filename resolution ==='
+echo
+
+BASE_IMG="$TEST_DIR/image:base.$IMGFMT"
+TOP_IMG="$TEST_DIR/image:top.$IMGFMT"
+
+TEST_IMG=$BASE_IMG _make_test_img 64M
+TEST_IMG=$TOP_IMG _make_test_img -b ./image:base.$IMGFMT
+
+# The default cluster size depends on the image format
+TEST_IMG=$TOP_IMG _img_info | grep -v 'cluster_size'
+
+_rm_test_img "$BASE_IMG"
+_rm_test_img "$TOP_IMG"
+
+
+# Do another test where we access both top and base without any slash in them
+echo
+pushd "$TEST_DIR" >/dev/null
+
+BASE_IMG="base.$IMGFMT"
+TOP_IMG="file:image:top.$IMGFMT"
+
+TEST_IMG=$BASE_IMG _make_test_img 64M
+TEST_IMG=$TOP_IMG _make_test_img -b "$BASE_IMG"
+
+TEST_IMG=$TOP_IMG _img_info | grep -v 'cluster_size'
+
+_rm_test_img "$BASE_IMG"
+_rm_test_img "image:top.$IMGFMT"
+
+popd >/dev/null
+
+# Note that we could also do the same test with BASE_IMG=file:image:base.$IMGFMT
+# -- but behavior for that case is a bit strange. Protocol-prefixed paths are
+# in a sense always absolute paths, so such paths will never be combined with
+# the path of the overlay. But since "image:base.$IMGFMT" is actually a
+# relative path, it will always be evaluated relative to qemu's CWD (but not
+# relative to the overlay!). While this is more or less intended, it is still
+# pretty strange and thus not something that is tested here.
+# (The root of the issue is the use of a relative path with a protocol prefix.
+# This may always give you weird results because in one sense, qemu considers
+# such paths absolute, whereas in another, they are still relative.)
+
+
+# success, all done
+echo '*** done'
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/126.out b/tests/qemu-iotests/126.out
new file mode 100644
index 0000000000..50d73080fa
--- /dev/null
+++ b/tests/qemu-iotests/126.out
@@ -0,0 +1,23 @@
+QA output created by 126
+
+=== Testing plain files ===
+
+Formatting 'TEST_DIR/a:b.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/a:b.IMGFMT', fmt=IMGFMT size=67108864
+
+=== Testing relative backing filename resolution ===
+
+Formatting 'TEST_DIR/image:base.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/image:top.IMGFMT', fmt=IMGFMT size=67108864 backing_file=./image:base.IMGFMT
+image: TEST_DIR/image:top.IMGFMT
+file format: IMGFMT
+virtual size: 64M (67108864 bytes)
+backing file: ./image:base.IMGFMT (actual path: TEST_DIR/./image:base.IMGFMT)
+
+Formatting 'base.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'file:image:top.IMGFMT', fmt=IMGFMT size=67108864 backing_file=base.IMGFMT
+image: ./image:top.IMGFMT
+file format: IMGFMT
+virtual size: 64M (67108864 bytes)
+backing file: base.IMGFMT (actual path: ./base.IMGFMT)
+*** done
diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134
index acce946e75..99144151b8 100755
--- a/tests/qemu-iotests/134
+++ b/tests/qemu-iotests/134
@@ -37,30 +37,38 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-_supported_fmt qcow2
+_supported_fmt qcow qcow2
_supported_proto generic
_unsupported_proto vxhs
_supported_os Linux
size=128M
-IMGOPTS="encryption=on" _make_test_img $size
+
+SECRET="secret,id=sec0,data=astrochicken"
+SECRETALT="secret,id=sec0,data=platypus"
+
+_make_test_img --object $SECRET -o "encryption=on,encrypt.key-secret=sec0" $size
+
+IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0"
+
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
echo
echo "== reading whole image =="
-echo "astrochicken" | $QEMU_IO -c "read 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
+$QEMU_IO --object $SECRET -c "read 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
echo
echo "== rewriting whole image =="
-echo "astrochicken" | $QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
+$QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
echo
echo "== verify pattern =="
-echo "astrochicken" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
+$QEMU_IO --object $SECRET -c "read -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
echo
echo "== verify pattern failure with wrong password =="
-echo "platypus" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
+$QEMU_IO --object $SECRETALT -c "read -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
# success, all done
diff --git a/tests/qemu-iotests/134.out b/tests/qemu-iotests/134.out
index 6493704ecf..972be49d91 100644
--- a/tests/qemu-iotests/134.out
+++ b/tests/qemu-iotests/134.out
@@ -1,27 +1,19 @@
QA output created by 134
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0
== reading whole image ==
-Disk image 'TEST_DIR/t.qcow2' is encrypted.
-password:
read 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== rewriting whole image ==
-Disk image 'TEST_DIR/t.qcow2' is encrypted.
-password:
wrote 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== verify pattern ==
-Disk image 'TEST_DIR/t.qcow2' is encrypted.
-password:
read 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== verify pattern failure with wrong password ==
-Disk image 'TEST_DIR/t.qcow2' is encrypted.
-password:
Pattern verification failed at offset 0, 134217728 bytes
read 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140
index 8c80a5a866..f89d0d6789 100755
--- a/tests/qemu-iotests/140
+++ b/tests/qemu-iotests/140
@@ -52,8 +52,15 @@ _make_test_img 64k
$QEMU_IO -c 'write -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io
+if test "$IMGOPTSSYNTAX" = "true"
+then
+ SYSEMU_DRIVE_ARG=if=none,media=cdrom,id=drv,"$TEST_IMG"
+else
+ SYSEMU_DRIVE_ARG=if=none,media=cdrom,id=drv,file="$TEST_IMG",driver=$IMGFMT
+fi
+
keep_stderr=y \
-_launch_qemu -drive if=none,media=cdrom,id=drv,file="$TEST_IMG",format=$IMGFMT \
+_launch_qemu -drive $SYSEMU_DRIVE_ARG \
2> >(_filter_nbd)
_send_qemu_cmd $QEMU_HANDLE \
diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142
index 9a5b713256..1639c83985 100755
--- a/tests/qemu-iotests/142
+++ b/tests/qemu-iotests/142
@@ -94,36 +94,36 @@ function check_cache_all()
# cache.direct is supposed to be inherited by both bs->file and
# bs->backing
- echo -e "cache.direct=on on none0"
+ printf "cache.direct=on on none0\n"
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't"
- echo -e "\ncache.direct=on on file"
+ printf "\ncache.direct=on on file\n"
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't"
- echo -e "\ncache.direct=on on backing"
+ printf "\ncache.direct=on on backing\n"
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't"
- echo -e "\ncache.direct=on on backing-file"
+ printf "\ncache.direct=on on backing-file\n"
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't"
# cache.writeback is supposed to be inherited by bs->backing; bs->file
# always gets cache.writeback=on
- echo -e "\n\ncache.writeback=off on none0"
+ printf "\n\ncache.writeback=off on none0\n"
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.writeback=off | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
- echo -e "\ncache.writeback=off on file"
+ printf "\ncache.writeback=off on file\n"
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.writeback=off | grep -e "doesn't" -e "does not"
- echo -e "\ncache.writeback=off on backing"
+ printf "\ncache.writeback=off on backing\n"
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.writeback=off | grep -e "doesn't" -e "does not"
- echo -e "\ncache.writeback=off on backing-file"
+ printf "\ncache.writeback=off on backing-file\n"
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.writeback=off | grep -e "doesn't" -e "does not"
# cache.no-flush is supposed to be inherited by both bs->file and bs->backing
- echo -e "\n\ncache.no-flush=on on none0"
+ printf "\n\ncache.no-flush=on on none0\n"
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
- echo -e "\ncache.no-flush=on on file"
+ printf "\ncache.no-flush=on on file\n"
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
- echo -e "\ncache.no-flush=on on backing"
+ printf "\ncache.no-flush=on on backing\n"
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
- echo -e "\ncache.no-flush=on on backing-file"
+ printf "\ncache.no-flush=on on backing-file\n"
echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
}
@@ -236,35 +236,35 @@ function check_cache_all_separate()
{
# Check cache.direct
- echo -e "cache.direct=on on blk"
+ printf "cache.direct=on on blk\n"
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.direct=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
- echo -e "\ncache.direct=on on file"
+ printf "\ncache.direct=on on file\n"
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.direct=on -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
- echo -e "\ncache.direct=on on backing"
+ printf "\ncache.direct=on on backing\n"
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.direct=on -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
- echo -e "\ncache.direct=on on backing-file"
+ printf "\ncache.direct=on on backing-file\n"
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.direct=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
# Check cache.writeback
- echo -e "\n\ncache.writeback=off on blk"
+ printf "\n\ncache.writeback=off on blk\n"
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.writeback=off | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
- echo -e "\ncache.writeback=off on file"
+ printf "\ncache.writeback=off on file\n"
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.writeback=off -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
- echo -e "\ncache.writeback=off on backing"
+ printf "\ncache.writeback=off on backing\n"
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.writeback=off -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
- echo -e "\ncache.writeback=off on backing-file"
+ printf "\ncache.writeback=off on backing-file\n"
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.writeback=off -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
# Check cache.no-flush
- echo -e "\n\ncache.no-flush=on on blk"
+ printf "\n\ncache.no-flush=on on blk\n"
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
- echo -e "\ncache.no-flush=on on file"
+ printf "\ncache.no-flush=on on file\n"
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.no-flush=on -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
- echo -e "\ncache.no-flush=on on backing"
+ printf "\ncache.no-flush=on on backing\n"
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.no-flush=on -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
- echo -e "\ncache.no-flush=on on backing-file"
+ printf "\ncache.no-flush=on on backing-file\n"
echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.no-flush=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't"
}
diff --git a/tests/qemu-iotests/144.out b/tests/qemu-iotests/144.out
index 387855c378..014b2817ee 100644
--- a/tests/qemu-iotests/144.out
+++ b/tests/qemu-iotests/144.out
@@ -7,7 +7,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=536870912
=== Performing Live Snapshot 1 ===
{"return": {}}
-Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
=== Performing block-commit on active layer ===
@@ -19,6 +19,6 @@ Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/
=== Performing Live Snapshot 2 ===
-Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
*** done
diff --git a/tests/qemu-iotests/145 b/tests/qemu-iotests/145
index e6c6bc4a4f..c371b3c46a 100755
--- a/tests/qemu-iotests/145
+++ b/tests/qemu-iotests/145
@@ -43,8 +43,23 @@ _supported_proto generic
_supported_os Linux
_make_test_img 1M
-echo quit | $QEMU -nographic -hda "$TEST_IMG" -incoming 'exec:true' -snapshot -serial none -monitor stdio |
- _filter_qemu | _filter_hmp
+
+if test "$IMGOPTSSYNTAX" = "true"
+then
+ SYSEMU_DRIVE_ARG=if=none,$TEST_IMG
+ SYSEMU_EXTRA_ARGS=""
+ if [ -n "$IMGKEYSECRET" ]; then
+ SECRET_ARG="secret,id=keysec0,data=$IMGKEYSECRET"
+ SYSEMU_EXTRA_ARGS="-object $SECRET_ARG"
+ fi
+else
+ SYSEMU_DRIVE_ARG=if=none,file="$TEST_IMG",driver=$IMGFMT
+ SYSEMU_EXTRA_ARGS=""
+fi
+
+echo quit | $QEMU -nographic $SYSEMU_EXTRA_ARGS -drive $SYSEMU_DRIVE_ARG \
+ -incoming 'exec:true' -snapshot -serial none -monitor stdio \
+ | _filter_qemu | _filter_hmp
# success, all done
echo "*** done"
diff --git a/tests/qemu-iotests/149 b/tests/qemu-iotests/149
index 84072513db..223cd68ad5 100755
--- a/tests/qemu-iotests/149
+++ b/tests/qemu-iotests/149
@@ -136,6 +136,7 @@ def cryptsetup_add_password(config, slot):
args = ["luksAddKey", config.image_path(),
"--key-slot", slot,
"--key-file", "-",
+ "--iter-time", "10",
pwfile]
cryptsetup(args, password)
@@ -164,6 +165,7 @@ def cryptsetup_format(config):
args.extend(["--hash", config.hash])
args.extend(["--key-slot", slot])
args.extend(["--key-file", "-"])
+ args.extend(["--iter-time", "10"])
args.append(config.image_path())
cryptsetup(args, password)
@@ -184,7 +186,7 @@ def chown(config):
msg = proc.communicate()[0]
if proc.returncode != 0:
- raise Exception("Cannot change owner on %s" % path)
+ raise Exception(msg)
def cryptsetup_open(config):
@@ -230,6 +232,7 @@ def qemu_img_create(config, size_mb):
opts = [
"key-secret=sec0",
+ "iter-time=10",
"cipher-alg=%s-%d" % (config.cipher, config.keylen),
"cipher-mode=%s" % config.mode,
"ivgen-alg=%s" % config.ivgen,
@@ -268,6 +271,8 @@ def qemu_io_image_args(config, dev=False):
def qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False):
"""Write a pattern of data to a LUKS image or device"""
+ if dev:
+ chown(config)
args = ["-c", "write -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)]
args.extend(qemu_io_image_args(config, dev))
iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir])
@@ -278,6 +283,8 @@ def qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False):
def qemu_io_read_pattern(config, pattern, offset_mb, size_mb, dev=False):
"""Read a pattern of data to a LUKS image or device"""
+ if dev:
+ chown(config)
args = ["-c", "read -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)]
args.extend(qemu_io_image_args(config, dev))
iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir])
@@ -328,9 +335,6 @@ def test_once(config, qemu_img=False):
cryptsetup_open(config)
try:
- iotests.log("# Set dev owner")
- chown(config)
-
iotests.log("# Write test pattern 0xa7")
qemu_io_write_pattern(config, 0xa7, lowOffsetMB, 10, dev=True)
iotests.log("# Write test pattern 0x13")
@@ -362,9 +366,6 @@ def test_once(config, qemu_img=False):
cryptsetup_open(config)
try:
- iotests.log("# Set dev owner")
- chown(config)
-
iotests.log("# Read test pattern 0x91")
qemu_io_read_pattern(config, 0x91, lowOffsetMB, 10, dev=True)
iotests.log("# Read test pattern 0x5e")
@@ -454,8 +455,12 @@ configs = [
# LUKS default but diff hash
+ LUKSConfig("aes-256-xts-plain64-sha224",
+ "aes", 256, "xts", "plain64", None, "sha224"),
LUKSConfig("aes-256-xts-plain64-sha256",
"aes", 256, "xts", "plain64", None, "sha256"),
+ LUKSConfig("aes-256-xts-plain64-sha384",
+ "aes", 256, "xts", "plain64", None, "sha384"),
LUKSConfig("aes-256-xts-plain64-sha512",
"aes", 256, "xts", "plain64", None, "sha512"),
LUKSConfig("aes-256-xts-plain64-ripemd160",
@@ -501,12 +506,6 @@ blacklist = [
# GCrypt doesn't support Twofish with 192 bit key
"twofish-192-xts-plain64-sha1",
-
- # We don't have sha512 hash wired up yet
- "aes-256-xts-plain64-sha512",
-
- # We don't have ripemd160 hash wired up yet
- "aes-256-xts-plain64-ripemd160",
]
whitelist = []
diff --git a/tests/qemu-iotests/149.out b/tests/qemu-iotests/149.out
index 90b5b55efb..5dea00bfa8 100644
--- a/tests/qemu-iotests/149.out
+++ b/tests/qemu-iotests/149.out
@@ -2,17 +2,17 @@
# Create image
truncate TEST_DIR/luks-aes-256-xts-plain64-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-plain64-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -41,14 +41,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -60,19 +60,19 @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha1.img
# ================= qemu-img aes-256-xts-plain64-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain64-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -101,14 +101,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -122,17 +122,17 @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha1.img
# Create image
truncate TEST_DIR/luks-twofish-256-xts-plain64-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-twofish-256-xts-plain64-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -161,14 +161,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -180,19 +180,19 @@ unlink TEST_DIR/luks-twofish-256-xts-plain64-sha1.img
# ================= qemu-img twofish-256-xts-plain64-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=twofish-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-twofish-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=twofish-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-twofish-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -221,14 +221,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -242,17 +242,17 @@ unlink TEST_DIR/luks-twofish-256-xts-plain64-sha1.img
# Create image
truncate TEST_DIR/luks-serpent-256-xts-plain64-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-serpent-256-xts-plain64-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -281,14 +281,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -300,19 +300,19 @@ unlink TEST_DIR/luks-serpent-256-xts-plain64-sha1.img
# ================= qemu-img serpent-256-xts-plain64-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=serpent-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-serpent-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-serpent-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -341,14 +341,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -362,17 +362,17 @@ unlink TEST_DIR/luks-serpent-256-xts-plain64-sha1.img
# Create image
truncate TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher cast5-cbc-plain64 --key-size 128 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher cast5-cbc-plain64 --key-size 128 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -401,14 +401,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -420,19 +420,19 @@ unlink TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img
# ================= qemu-img cast5-128-cbc-plain64-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=cast5-128,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=cast5-128 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=cast5-128,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=cast5-128 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -461,14 +461,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -483,17 +483,17 @@ Skipping cast6-256-xts-plain64-sha1 in blacklist
# Create image
truncate TEST_DIR/luks-aes-256-cbc-plain-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-plain-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -522,14 +522,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -541,19 +541,19 @@ unlink TEST_DIR/luks-aes-256-cbc-plain-sha1.img
# ================= qemu-img aes-256-cbc-plain-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-cbc-plain-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-aes-256-cbc-plain-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -582,14 +582,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -603,17 +603,17 @@ unlink TEST_DIR/luks-aes-256-cbc-plain-sha1.img
# Create image
truncate TEST_DIR/luks-aes-256-cbc-plain64-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-plain64-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -642,14 +642,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -661,19 +661,19 @@ unlink TEST_DIR/luks-aes-256-cbc-plain64-sha1.img
# ================= qemu-img aes-256-cbc-plain64-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -702,14 +702,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -723,17 +723,17 @@ unlink TEST_DIR/luks-aes-256-cbc-plain64-sha1.img
# Create image
truncate TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -762,14 +762,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -781,19 +781,19 @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img
# ================= qemu-img aes-256-cbc-essiv-sha256-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -822,14 +822,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -843,17 +843,17 @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img
# Create image
truncate TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher aes-xts-essiv:sha256 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher aes-xts-essiv:sha256 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -882,14 +882,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -901,19 +901,19 @@ unlink TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img
# ================= qemu-img aes-256-xts-essiv-sha256-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -942,14 +942,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -963,17 +963,17 @@ unlink TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img
# Create image
truncate TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1002,14 +1002,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1021,19 +1021,19 @@ unlink TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img
# ================= qemu-img aes-128-xts-plain64-sha256-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1062,14 +1062,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1083,17 +1083,17 @@ unlink TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img
# Create image
truncate TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1122,14 +1122,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1141,19 +1141,19 @@ unlink TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img
# ================= qemu-img aes-192-xts-plain64-sha256-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1182,14 +1182,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1203,17 +1203,17 @@ unlink TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img
# Create image
truncate TEST_DIR/luks-twofish-128-xts-plain64-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-twofish-128-xts-plain64-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1242,14 +1242,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1261,19 +1261,19 @@ unlink TEST_DIR/luks-twofish-128-xts-plain64-sha1.img
# ================= qemu-img twofish-128-xts-plain64-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=twofish-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-twofish-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=twofish-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-twofish-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1302,14 +1302,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1324,17 +1324,17 @@ Skipping twofish-192-xts-plain64-sha1 in blacklist
# Create image
truncate TEST_DIR/luks-serpent-128-xts-plain64-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-serpent-128-xts-plain64-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1363,14 +1363,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1382,19 +1382,19 @@ unlink TEST_DIR/luks-serpent-128-xts-plain64-sha1.img
# ================= qemu-img serpent-128-xts-plain64-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=serpent-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-serpent-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-serpent-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1423,14 +1423,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1444,17 +1444,17 @@ unlink TEST_DIR/luks-serpent-128-xts-plain64-sha1.img
# Create image
truncate TEST_DIR/luks-serpent-192-xts-plain64-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-serpent-192-xts-plain64-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1483,14 +1483,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1502,19 +1502,19 @@ unlink TEST_DIR/luks-serpent-192-xts-plain64-sha1.img
# ================= qemu-img serpent-192-xts-plain64-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=serpent-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-serpent-192-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-serpent-192-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1543,14 +1543,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1562,21 +1562,141 @@ unlink TEST_DIR/luks-serpent-192-xts-plain64-sha1.img
Skipping cast6-128-xts-plain64-sha1 in blacklist
Skipping cast6-192-xts-plain64-sha1 in blacklist
+# ================= dm-crypt aes-256-xts-plain64-sha224 =================
+# Create image
+truncate TEST_DIR/luks-aes-256-xts-plain64-sha224.img --size 4194304MB
+# Format image
+sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha224 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha224.img
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224
+# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha224
+# Read test pattern 0xa7
+qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x13
+qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x91
+qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x5e
+qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224
+# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha224
+# Delete image
+unlink TEST_DIR/luks-aes-256-xts-plain64-sha224.img
+
+# ================= qemu-img aes-256-xts-plain64-sha224 =================
+# Create image
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha224 TEST_DIR/luks-aes-256-xts-plain64-sha224.img 4194304M
+Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha224.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha224 iter-time=10
+
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224
+# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha224
+# Read test pattern 0xa7
+qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x13
+qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x91
+qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x5e
+qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224
+# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha224
+# Delete image
+unlink TEST_DIR/luks-aes-256-xts-plain64-sha224.img
+
# ================= dm-crypt aes-256-xts-plain64-sha256 =================
# Create image
truncate TEST_DIR/luks-aes-256-xts-plain64-sha256.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha256 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-plain64-sha256.img
+sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha256 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha256.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1605,14 +1725,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1624,19 +1744,19 @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha256.img
# ================= qemu-img aes-256-xts-plain64-sha256 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha256 TEST_DIR/luks-aes-256-xts-plain64-sha256.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha256.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha256
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha256 TEST_DIR/luks-aes-256-xts-plain64-sha256.img 4194304M
+Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha256.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha256 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1665,14 +1785,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1682,23 +1802,381 @@ sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha256
# Delete image
unlink TEST_DIR/luks-aes-256-xts-plain64-sha256.img
-Skipping aes-256-xts-plain64-sha512 in blacklist
-Skipping aes-256-xts-plain64-ripemd160 in blacklist
+# ================= dm-crypt aes-256-xts-plain64-sha384 =================
+# Create image
+truncate TEST_DIR/luks-aes-256-xts-plain64-sha384.img --size 4194304MB
+# Format image
+sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha384 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha384.img
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384
+# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha384
+# Read test pattern 0xa7
+qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x13
+qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x91
+qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x5e
+qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384
+# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha384
+# Delete image
+unlink TEST_DIR/luks-aes-256-xts-plain64-sha384.img
+
+# ================= qemu-img aes-256-xts-plain64-sha384 =================
+# Create image
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha384 TEST_DIR/luks-aes-256-xts-plain64-sha384.img 4194304M
+Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha384.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha384 iter-time=10
+
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384
+# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha384
+# Read test pattern 0xa7
+qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x13
+qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x91
+qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x5e
+qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384
+# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha384
+# Delete image
+unlink TEST_DIR/luks-aes-256-xts-plain64-sha384.img
+
+# ================= dm-crypt aes-256-xts-plain64-sha512 =================
+# Create image
+truncate TEST_DIR/luks-aes-256-xts-plain64-sha512.img --size 4194304MB
+# Format image
+sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha512 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha512.img
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512
+# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha512
+# Read test pattern 0xa7
+qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x13
+qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x91
+qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x5e
+qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512
+# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha512
+# Delete image
+unlink TEST_DIR/luks-aes-256-xts-plain64-sha512.img
+
+# ================= qemu-img aes-256-xts-plain64-sha512 =================
+# Create image
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha512 TEST_DIR/luks-aes-256-xts-plain64-sha512.img 4194304M
+Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha512.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha512 iter-time=10
+
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512
+# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha512
+# Read test pattern 0xa7
+qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x13
+qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x91
+qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x5e
+qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512
+# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha512
+# Delete image
+unlink TEST_DIR/luks-aes-256-xts-plain64-sha512.img
+
+# ================= dm-crypt aes-256-xts-plain64-ripemd160 =================
+# Create image
+truncate TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img --size 4194304MB
+# Format image
+sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash ripemd160 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160
+# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-ripemd160
+# Read test pattern 0xa7
+qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x13
+qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x91
+qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x5e
+qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160
+# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-ripemd160
+# Delete image
+unlink TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img
+
+# ================= qemu-img aes-256-xts-plain64-ripemd160 =================
+# Create image
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=ripemd160 TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img 4194304M
+Formatting 'TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=ripemd160 iter-time=10
+
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160
+# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-ripemd160
+# Read test pattern 0xa7
+qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x13
+qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x91
+qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img
+wrote 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Write test pattern 0x5e
+qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img
+wrote 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Open dev
+sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160
+# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+read 10485760/10485760 bytes at offset 104857600
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160
+read 10485760/10485760 bytes at offset 3298534883328
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+# Close dev
+sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-ripemd160
+# Delete image
+unlink TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img
+
# ================= dm-crypt aes-256-xts-plain-sha1-pwslot3 =================
# Create image
truncate TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 3 --key-file - TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img
+sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 3 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img qiotest-145-aes-256-xts-plain-sha1-pwslot3
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1727,14 +2205,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img qiotest-145-aes-256-xts-plain-sha1-pwslot3
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1748,31 +2226,31 @@ unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img
# Create image
truncate TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img
+sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img
# Add password slot 1
-sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 1 --key-file - TEST_DIR/passwd.txt
+sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 1 --key-file - --iter-time 10 TEST_DIR/passwd.txt
# Add password slot 2
-sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 2 --key-file - TEST_DIR/passwd.txt
+sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 2 --key-file - --iter-time 10 TEST_DIR/passwd.txt
# Add password slot 3
-sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 3 --key-file - TEST_DIR/passwd.txt
+sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 3 --key-file - --iter-time 10 TEST_DIR/passwd.txt
# Add password slot 4
-sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 4 --key-file - TEST_DIR/passwd.txt
+sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 4 --key-file - --iter-time 10 TEST_DIR/passwd.txt
# Add password slot 5
-sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 5 --key-file - TEST_DIR/passwd.txt
+sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 5 --key-file - --iter-time 10 TEST_DIR/passwd.txt
# Add password slot 6
-sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 6 --key-file - TEST_DIR/passwd.txt
+sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 6 --key-file - --iter-time 10 TEST_DIR/passwd.txt
# Add password slot 7
-sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 7 --key-file - TEST_DIR/passwd.txt
+sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 7 --key-file - --iter-time 10 TEST_DIR/passwd.txt
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1801,14 +2279,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1820,19 +2298,19 @@ unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img
# ================= qemu-img aes-256-xts-plain-sha1-pwallslots =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=c2xvdDE=,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=c2xvdDE=,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img 4194304M
+Formatting 'TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1861,14 +2339,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1882,17 +2360,17 @@ unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img
# Create image
truncate TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1921,14 +2399,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1940,19 +2418,19 @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img
# ================= qemu-img aes-256-cbc-essiv-auto-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -1981,14 +2459,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -2002,17 +2480,17 @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img
# Create image
truncate TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img --size 4194304MB
# Format image
-sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img
+sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -2041,14 +2519,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -2060,19 +2538,19 @@ unlink TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img
# ================= qemu-img aes-256-cbc-plain64-sha256-sha1 =================
# Create image
-qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img 4194304M
-Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 ivgen-hash-alg=sha256 hash-alg=sha1
+qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img 4194304M
+Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
# Write test pattern 0xa7
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
wrote 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Write test pattern 0x13
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
wrote 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -2101,14 +2579,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328
# Open dev
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1
-# Set dev owner
-sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
# Read test pattern 0x91
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
read 10485760/10485760 bytes at offset 104857600
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
# Read test pattern 0x5e
+sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1
read 10485760/10485760 bytes at offset 3298534883328
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/157 b/tests/qemu-iotests/157
index 8d939cb747..2bf02be465 100755
--- a/tests/qemu-iotests/157
+++ b/tests/qemu-iotests/157
@@ -43,7 +43,6 @@ _supported_os Linux
function do_run_qemu()
{
- echo Testing: "$@"
(
if ! test -t 0; then
while read cmd; do
@@ -63,7 +62,18 @@ function run_qemu()
size=128M
-drive="if=none,file=$TEST_IMG,driver=$IMGFMT"
+if test "$IMGOPTSSYNTAX" = "true"
+then
+ SYSEMU_DRIVE_ARG=if=none,$TEST_IMG
+ SYSEMU_EXTRA_ARGS=""
+ if [ -n "$IMGKEYSECRET" ]; then
+ SECRET_ARG="secret,id=keysec0,data=$IMGKEYSECRET"
+ SYSEMU_EXTRA_ARGS="-object $SECRET_ARG"
+ fi
+else
+ SYSEMU_DRIVE_ARG=if=none,file="$TEST_IMG",driver=$IMGFMT
+ SYSEMU_EXTRA_ARGS=""
+fi
_make_test_img $size
@@ -76,8 +86,9 @@ echo
for cache in "writeback" "writethrough"; do
for wce in "" ",write-cache=auto" ",write-cache=on" ",write-cache=off"; do
+ echo "Testing: cache='$cache' wce='$wce'"
echo "info block" \
- | run_qemu -drive "$drive,cache=$cache" \
+ | run_qemu $SYSEMU_EXTRA_ARGS -drive "$SYSEMU_DRIVE_ARG,cache=$cache" \
-device "virtio-blk,drive=none0$wce" \
| grep -e "Testing" -e "Cache mode"
done
diff --git a/tests/qemu-iotests/157.out b/tests/qemu-iotests/157.out
index 77a9c03d2c..fdc807f541 100644
--- a/tests/qemu-iotests/157.out
+++ b/tests/qemu-iotests/157.out
@@ -3,20 +3,20 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
=== Setting WCE with qdev and with manually created BB ===
-Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writeback -device virtio-blk,drive=none0
+Testing: cache='writeback' wce=''
Cache mode: writeback
-Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writeback -device virtio-blk,drive=none0,write-cache=auto
+Testing: cache='writeback' wce=',write-cache=auto'
Cache mode: writeback
-Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writeback -device virtio-blk,drive=none0,write-cache=on
+Testing: cache='writeback' wce=',write-cache=on'
Cache mode: writeback
-Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writeback -device virtio-blk,drive=none0,write-cache=off
+Testing: cache='writeback' wce=',write-cache=off'
Cache mode: writethrough
-Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writethrough -device virtio-blk,drive=none0
+Testing: cache='writethrough' wce=''
Cache mode: writethrough
-Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writethrough -device virtio-blk,drive=none0,write-cache=auto
+Testing: cache='writethrough' wce=',write-cache=auto'
Cache mode: writethrough
-Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writethrough -device virtio-blk,drive=none0,write-cache=on
+Testing: cache='writethrough' wce=',write-cache=on'
Cache mode: writeback
-Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,driver=IMGFMT,cache=writethrough -device virtio-blk,drive=none0,write-cache=off
+Testing: cache='writethrough' wce=',write-cache=off'
Cache mode: writethrough
*** done
diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158
index ef8d70f109..823c12002e 100755
--- a/tests/qemu-iotests/158
+++ b/tests/qemu-iotests/158
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-_supported_fmt qcow2
+_supported_fmt qcow qcow2
_supported_proto generic
_unsupported_proto vxhs
_supported_os Linux
@@ -45,34 +45,39 @@ _supported_os Linux
size=128M
TEST_IMG_BASE=$TEST_IMG.base
+SECRET="secret,id=sec0,data=astrochicken"
TEST_IMG_SAVE=$TEST_IMG
TEST_IMG=$TEST_IMG_BASE
echo "== create base =="
-IMGOPTS="encryption=on" _make_test_img $size
+_make_test_img --object $SECRET -o "encryption=on,encrypt.key-secret=sec0" $size
TEST_IMG=$TEST_IMG_SAVE
+IMGSPECBASE="driver=$IMGFMT,file.filename=$TEST_IMG_BASE,encrypt.key-secret=sec0"
+IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,backing.driver=$IMGFMT,backing.file.filename=$TEST_IMG_BASE,backing.encrypt.key-secret=sec0,encrypt.key-secret=sec0"
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
+
echo
echo "== writing whole image =="
-echo "astrochicken" | $QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG_BASE" | _filter_qemu_io | _filter_testdir
+$QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir
echo
echo "== verify pattern =="
-echo "astrochicken" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG_BASE" | _filter_qemu_io | _filter_testdir
+$QEMU_IO --object $SECRET -c "read -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir
echo "== create overlay =="
-IMGOPTS="encryption=on" _make_test_img -b "$TEST_IMG_BASE" $size
+_make_test_img --object $SECRET -o "encryption=on,encrypt.key-secret=sec0" -b "$TEST_IMG_BASE" $size
echo
echo "== writing part of a cluster =="
-echo "astrochicken" | $QEMU_IO -c "write -P 0xe 0 1024" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
+$QEMU_IO --object $SECRET -c "write -P 0xe 0 1024" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
echo
echo "== verify pattern =="
-echo "astrochicken" | $QEMU_IO -c "read -P 0xe 0 1024" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
+$QEMU_IO --object $SECRET -c "read -P 0xe 0 1024" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
echo
echo "== verify pattern =="
-echo "astrochicken" | $QEMU_IO -c "read -P 0xa 1024 64512" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
+$QEMU_IO --object $SECRET -c "read -P 0xa 1024 64512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
# success, all done
diff --git a/tests/qemu-iotests/158.out b/tests/qemu-iotests/158.out
index b3f37e28ef..6def216e55 100644
--- a/tests/qemu-iotests/158.out
+++ b/tests/qemu-iotests/158.out
@@ -1,36 +1,26 @@
QA output created by 158
== create base ==
-Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 encryption=on
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0
== writing whole image ==
-Disk image 'TEST_DIR/t.qcow2.base' is encrypted.
-password:
wrote 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== verify pattern ==
-Disk image 'TEST_DIR/t.qcow2.base' is encrypted.
-password:
read 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== create overlay ==
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on encrypt.key-secret=sec0
== writing part of a cluster ==
-Disk image 'TEST_DIR/t.qcow2' is encrypted.
-password:
wrote 1024/1024 bytes at offset 0
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== verify pattern ==
-Disk image 'TEST_DIR/t.qcow2' is encrypted.
-password:
read 1024/1024 bytes at offset 0
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== verify pattern ==
-Disk image 'TEST_DIR/t.qcow2' is encrypted.
-password:
read 64512/64512 bytes at offset 1024
63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
*** done
diff --git a/tests/qemu-iotests/159 b/tests/qemu-iotests/159
index 825f05fab8..9b0e1ecc90 100755
--- a/tests/qemu-iotests/159
+++ b/tests/qemu-iotests/159
@@ -40,6 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto file
_supported_os Linux
+_unsupported_fmt luks
TEST_SIZES="5 512 1024 1999 1K 64K 1M"
diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165
new file mode 100755
index 0000000000..74d7b79a0b
--- /dev/null
+++ b/tests/qemu-iotests/165
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+#
+# Tests for persistent dirty bitmaps.
+#
+# Copyright: Vladimir Sementsov-Ogievskiy 2015-2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import re
+import iotests
+from iotests import qemu_img
+
+disk = os.path.join(iotests.test_dir, 'disk')
+disk_size = 0x40000000 # 1G
+
+# regions for qemu_io: (start, count) in bytes
+regions1 = ((0, 0x100000),
+ (0x200000, 0x100000))
+
+regions2 = ((0x10000000, 0x20000),
+ (0x3fff0000, 0x10000))
+
+class TestPersistentDirtyBitmap(iotests.QMPTestCase):
+
+ def setUp(self):
+ qemu_img('create', '-f', iotests.imgfmt, disk, str(disk_size))
+
+ def tearDown(self):
+ os.remove(disk)
+
+ def mkVm(self):
+ return iotests.VM().add_drive(disk)
+
+ def mkVmRo(self):
+ return iotests.VM().add_drive(disk, opts='readonly=on')
+
+ def getSha256(self):
+ result = self.vm.qmp('x-debug-block-dirty-bitmap-sha256',
+ node='drive0', name='bitmap0')
+ return result['return']['sha256']
+
+ def checkBitmap(self, sha256):
+ result = self.vm.qmp('x-debug-block-dirty-bitmap-sha256',
+ node='drive0', name='bitmap0')
+ self.assert_qmp(result, 'return/sha256', sha256);
+
+ def writeRegions(self, regions):
+ for r in regions:
+ self.vm.hmp_qemu_io('drive0',
+ 'write %d %d' % r)
+
+ def qmpAddBitmap(self):
+ self.vm.qmp('block-dirty-bitmap-add', node='drive0',
+ name='bitmap0', persistent=True, autoload=True)
+
+ def test_persistent(self):
+ self.vm = self.mkVm()
+ self.vm.launch()
+ self.qmpAddBitmap()
+
+ self.writeRegions(regions1)
+ sha256 = self.getSha256()
+
+ self.vm.shutdown()
+
+ self.vm = self.mkVmRo()
+ self.vm.launch()
+ self.vm.shutdown()
+
+ #catch 'Persistent bitmaps are lost' possible error
+ log = self.vm.get_log()
+ log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log)
+ log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log)
+ if log:
+ print log
+
+ self.vm = self.mkVm()
+ self.vm.launch()
+
+ self.checkBitmap(sha256)
+ self.writeRegions(regions2)
+ sha256 = self.getSha256()
+
+ self.vm.shutdown()
+ self.vm.launch()
+
+ self.checkBitmap(sha256)
+
+ self.vm.shutdown()
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=['qcow2'])
diff --git a/tests/qemu-iotests/165.out b/tests/qemu-iotests/165.out
new file mode 100644
index 0000000000..ae1213e6f8
--- /dev/null
+++ b/tests/qemu-iotests/165.out
@@ -0,0 +1,5 @@
+.
+----------------------------------------------------------------------
+Ran 1 tests
+
+OK
diff --git a/tests/qemu-iotests/170 b/tests/qemu-iotests/170
index 5b335dbc3e..b79359fc4e 100755
--- a/tests/qemu-iotests/170
+++ b/tests/qemu-iotests/170
@@ -40,6 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto file
_supported_os Linux
+_unsupported_fmt luks
echo
echo "== Creating image =="
diff --git a/tests/qemu-iotests/171 b/tests/qemu-iotests/171
index 257be10a0e..bcfaaf1be2 100755
--- a/tests/qemu-iotests/171
+++ b/tests/qemu-iotests/171
@@ -45,15 +45,15 @@ _supported_os Linux
# Create JSON with options
img_json() {
- echo -n 'json:{"driver":"raw", '
- echo -n "\"offset\":\"$img_offset\", "
+ printf %s 'json:{"driver":"raw", '
+ printf %s "\"offset\":\"$img_offset\", "
if [ "$img_size" -ne -1 ] ; then
- echo -n "\"size\":\"$img_size\", "
+ printf %s "\"size\":\"$img_size\", "
fi
- echo -n '"file": {'
- echo -n '"driver":"file", '
- echo -n "\"filename\":\"$TEST_IMG\" "
- echo -n "} }"
+ printf %s '"file": {'
+ printf %s '"driver":"file", '
+ printf %s "\"filename\":\"$TEST_IMG\" "
+ printf %s "} }"
}
do_general_test() {
diff --git a/tests/qemu-iotests/174 b/tests/qemu-iotests/174
index c1c20a1a57..552879db32 100755
--- a/tests/qemu-iotests/174
+++ b/tests/qemu-iotests/174
@@ -41,7 +41,7 @@ _unsupported_fmt raw
size=256K
-IMGFMT=raw IMGOPTS= _make_test_img $size | _filter_imgfmt
+IMGFMT=raw IMGKEYSECRET= IMGOPTS= _make_test_img $size | _filter_imgfmt
echo
echo "== reading wrong format should fail =="
diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178
new file mode 100755
index 0000000000..6af52c653a
--- /dev/null
+++ b/tests/qemu-iotests/178
@@ -0,0 +1,170 @@
+#!/bin/bash
+#
+# qemu-img measure sub-command tests
+#
+# Copyright (C) 2017 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=stefanha@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+ rm -f "$TEST_IMG.converted"
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.pattern
+
+_supported_fmt raw qcow2
+_supported_proto file
+_supported_os Linux
+
+echo "== Input validation =="
+echo
+
+_make_test_img 1G
+
+$QEMU_IMG measure # missing arguments
+$QEMU_IMG measure --size 2G "$TEST_IMG" # only one allowed
+$QEMU_IMG measure "$TEST_IMG" a # only one filename allowed
+$QEMU_IMG measure --object secret,id=sec0,data=MTIzNDU2,format=base64 # missing filename
+$QEMU_IMG measure --image-opts # missing filename
+$QEMU_IMG measure -f qcow2 # missing filename
+$QEMU_IMG measure -l snap1 # missing filename
+$QEMU_IMG measure -o , # invalid option list
+$QEMU_IMG measure -l snapshot.foo # invalid snapshot option
+$QEMU_IMG measure --output foo # invalid output format
+$QEMU_IMG measure --size -1 # invalid image size
+$QEMU_IMG measure -O foo "$TEST_IMG" # unknown image file format
+
+make_test_img_with_fmt() {
+ # Shadow global variables within this function
+ local IMGFMT="$1" IMGOPTS=""
+ _make_test_img "$2"
+}
+
+qemu_io_with_fmt() {
+ # Shadow global variables within this function
+ local QEMU_IO_OPTIONS=$(echo "$QEMU_IO_OPTIONS" | sed "s/-f $IMGFMT/-f $1/")
+ shift
+ $QEMU_IO "$@"
+}
+
+# The proof is in the pudding: converted image size cannot be larger than the
+# required size.
+#
+# Note: if a change to the image format code causes the file size to change,
+# then this test fails! This is good because it's a reminder to check that the
+# required size is still at least as big as the actual converted file size.
+convert_and_show_size() {
+ local fmt="$1"
+ shift
+ $QEMU_IMG convert -f "$fmt" -O "$IMGFMT" "$TEST_IMG" "$@" "$TEST_IMG.converted"
+ stat -c "converted image file size in bytes: %s" "$TEST_IMG.converted"
+}
+
+for ofmt in human json; do
+ echo
+ echo "== Size calculation for a new file ($ofmt) =="
+ echo
+
+ # Try a few interesting sizes
+ $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 0
+ $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 2G
+ $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 64G
+ $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 256G
+ $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 1T
+ $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 2P
+ $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 7E
+
+ # Always test the raw input files but also IMGFMT
+ for fmt in $(echo -e "raw\n$IMGFMT\n" | sort -u); do
+ echo
+ echo "== Empty $fmt input image ($ofmt) =="
+ echo
+ make_test_img_with_fmt "$fmt" 0
+ $QEMU_IMG measure --output=$ofmt -f "$fmt" -O "$IMGFMT" "$TEST_IMG"
+ echo
+ convert_and_show_size "$fmt"
+
+ echo
+ echo "== $fmt input image with data ($ofmt) =="
+ echo
+ make_test_img_with_fmt "$fmt" 1G
+ $QEMU_IMG measure --output=$ofmt -f "$fmt" -O "$IMGFMT" "$TEST_IMG"
+ qemu_io_with_fmt "$fmt" -c "write 512 512" "$TEST_IMG" | _filter_qemu_io
+ qemu_io_with_fmt "$fmt" -c "write 64K 64K" "$TEST_IMG" | _filter_qemu_io
+ if [ "$fmt" = "qcow2" ]; then
+ $QEMU_IMG snapshot -c snapshot1 "$TEST_IMG"
+ fi
+ qemu_io_with_fmt "$fmt" -c "write 128M 63K" "$TEST_IMG" | _filter_qemu_io
+ $QEMU_IMG measure --output=$ofmt -f "$fmt" -O "$IMGFMT" "$TEST_IMG"
+ echo
+ convert_and_show_size "$fmt"
+
+ if [ "$fmt" = "qcow2" ]; then
+ echo
+ echo "== $fmt input image with internal snapshot ($ofmt) =="
+ echo
+ $QEMU_IMG measure --output=$ofmt -f "$fmt" -l snapshot1 \
+ -O "$IMGFMT" "$TEST_IMG"
+ echo
+ convert_and_show_size "$fmt" -l snapshot1
+ fi
+
+ if [ "$IMGFMT" = "qcow2" ]; then
+ echo
+ echo "== $fmt input image and a backing file ($ofmt) =="
+ echo
+ # The backing file doesn't need to exist :)
+ $QEMU_IMG measure --output=$ofmt -o backing_file=x \
+ -f "$fmt" -O "$IMGFMT" "$TEST_IMG"
+ fi
+
+ echo
+ echo "== $fmt input image and preallocation ($ofmt) =="
+ echo
+ $QEMU_IMG measure --output=$ofmt -o preallocation=full \
+ -f "$fmt" -O "$IMGFMT" "$TEST_IMG"
+ echo
+ convert_and_show_size "$fmt" -o preallocation=full
+
+ echo
+ echo "== Fully-allocated $fmt input image ($ofmt) =="
+ echo
+ make_test_img_with_fmt "$fmt" 8M
+ qemu_io_with_fmt "$fmt" -c "write 0 8M" "$TEST_IMG" | _filter_qemu_io
+ $QEMU_IMG measure --output=$ofmt -f "$fmt" -O "$IMGFMT" "$TEST_IMG"
+ echo
+ convert_and_show_size "$fmt"
+ done
+done
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2
new file mode 100644
index 0000000000..d42d4a4597
--- /dev/null
+++ b/tests/qemu-iotests/178.out.qcow2
@@ -0,0 +1,286 @@
+QA output created by 178
+== Input validation ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+qemu-img: Either --size N or one filename must be specified.
+qemu-img: --size N cannot be used together with a filename.
+qemu-img: At most one filename argument is allowed.
+qemu-img: --object, --image-opts, -f, and -l require a filename argument.
+qemu-img: --object, --image-opts, -f, and -l require a filename argument.
+qemu-img: --object, --image-opts, -f, and -l require a filename argument.
+qemu-img: --object, --image-opts, -f, and -l require a filename argument.
+qemu-img: Invalid option list: ,
+qemu-img: Invalid parameter 'snapshot.foo'
+qemu-img: Failed in parsing snapshot param 'snapshot.foo'
+qemu-img: --output must be used with human or json as argument.
+qemu-img: Image size must be less than 8 EiB!
+qemu-img: Unknown file format 'foo'
+
+== Size calculation for a new file (human) ==
+
+required size: 196608
+fully allocated size: 196608
+required size: 589824
+fully allocated size: 2148073472
+required size: 10747904
+fully allocated size: 68730224640
+required size: 42205184
+fully allocated size: 274920112128
+required size: 168034304
+fully allocated size: 1099679662080
+required size: 343650009088
+fully allocated size: 2252143463694336
+qemu-img: The image size is too large (try using a larger cluster size)
+
+== Empty qcow2 input image (human) ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
+required size: 196608
+fully allocated size: 196608
+
+converted image file size in bytes: 196608
+
+== qcow2 input image with data (human) ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+required size: 393216
+fully allocated size: 1074135040
+wrote 512/512 bytes at offset 512
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 64512/64512 bytes at offset 134217728
+63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+required size: 589824
+fully allocated size: 1074135040
+
+converted image file size in bytes: 524288
+
+== qcow2 input image with internal snapshot (human) ==
+
+required size: 524288
+fully allocated size: 1074135040
+
+converted image file size in bytes: 458752
+
+== qcow2 input image and a backing file (human) ==
+
+required size: 1074135040
+fully allocated size: 1074135040
+
+== qcow2 input image and preallocation (human) ==
+
+required size: 1074135040
+fully allocated size: 1074135040
+
+converted image file size in bytes: 1074135040
+
+== Fully-allocated qcow2 input image (human) ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608
+wrote 8388608/8388608 bytes at offset 0
+8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+required size: 8716288
+fully allocated size: 8716288
+
+converted image file size in bytes: 8716288
+
+== Empty raw input image (human) ==
+
+Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=0
+required size: 196608
+fully allocated size: 196608
+
+converted image file size in bytes: 196608
+
+== raw input image with data (human) ==
+
+Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824
+required size: 393216
+fully allocated size: 1074135040
+wrote 512/512 bytes at offset 512
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 64512/64512 bytes at offset 134217728
+63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+required size: 589824
+fully allocated size: 1074135040
+
+converted image file size in bytes: 524288
+
+== raw input image and a backing file (human) ==
+
+required size: 1074135040
+fully allocated size: 1074135040
+
+== raw input image and preallocation (human) ==
+
+required size: 1074135040
+fully allocated size: 1074135040
+
+converted image file size in bytes: 1074135040
+
+== Fully-allocated raw input image (human) ==
+
+Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=8388608
+wrote 8388608/8388608 bytes at offset 0
+8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+required size: 8716288
+fully allocated size: 8716288
+
+converted image file size in bytes: 8716288
+
+== Size calculation for a new file (json) ==
+
+{
+ "required": 196608,
+ "fully-allocated": 196608
+}
+{
+ "required": 589824,
+ "fully-allocated": 2148073472
+}
+{
+ "required": 10747904,
+ "fully-allocated": 68730224640
+}
+{
+ "required": 42205184,
+ "fully-allocated": 274920112128
+}
+{
+ "required": 168034304,
+ "fully-allocated": 1099679662080
+}
+{
+ "required": 343650009088,
+ "fully-allocated": 2252143463694336
+}
+qemu-img: The image size is too large (try using a larger cluster size)
+
+== Empty qcow2 input image (json) ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
+{
+ "required": 196608,
+ "fully-allocated": 196608
+}
+
+converted image file size in bytes: 196608
+
+== qcow2 input image with data (json) ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+{
+ "required": 393216,
+ "fully-allocated": 1074135040
+}
+wrote 512/512 bytes at offset 512
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 64512/64512 bytes at offset 134217728
+63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+{
+ "required": 589824,
+ "fully-allocated": 1074135040
+}
+
+converted image file size in bytes: 524288
+
+== qcow2 input image with internal snapshot (json) ==
+
+{
+ "required": 524288,
+ "fully-allocated": 1074135040
+}
+
+converted image file size in bytes: 458752
+
+== qcow2 input image and a backing file (json) ==
+
+{
+ "required": 1074135040,
+ "fully-allocated": 1074135040
+}
+
+== qcow2 input image and preallocation (json) ==
+
+{
+ "required": 1074135040,
+ "fully-allocated": 1074135040
+}
+
+converted image file size in bytes: 1074135040
+
+== Fully-allocated qcow2 input image (json) ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608
+wrote 8388608/8388608 bytes at offset 0
+8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+{
+ "required": 8716288,
+ "fully-allocated": 8716288
+}
+
+converted image file size in bytes: 8716288
+
+== Empty raw input image (json) ==
+
+Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=0
+{
+ "required": 196608,
+ "fully-allocated": 196608
+}
+
+converted image file size in bytes: 196608
+
+== raw input image with data (json) ==
+
+Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824
+{
+ "required": 393216,
+ "fully-allocated": 1074135040
+}
+wrote 512/512 bytes at offset 512
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 64512/64512 bytes at offset 134217728
+63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+{
+ "required": 589824,
+ "fully-allocated": 1074135040
+}
+
+converted image file size in bytes: 524288
+
+== raw input image and a backing file (json) ==
+
+{
+ "required": 1074135040,
+ "fully-allocated": 1074135040
+}
+
+== raw input image and preallocation (json) ==
+
+{
+ "required": 1074135040,
+ "fully-allocated": 1074135040
+}
+
+converted image file size in bytes: 1074135040
+
+== Fully-allocated raw input image (json) ==
+
+Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=8388608
+wrote 8388608/8388608 bytes at offset 0
+8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+{
+ "required": 8716288,
+ "fully-allocated": 8716288
+}
+
+converted image file size in bytes: 8716288
+*** done
diff --git a/tests/qemu-iotests/178.out.raw b/tests/qemu-iotests/178.out.raw
new file mode 100644
index 0000000000..6478365905
--- /dev/null
+++ b/tests/qemu-iotests/178.out.raw
@@ -0,0 +1,158 @@
+QA output created by 178
+== Input validation ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+qemu-img: Either --size N or one filename must be specified.
+qemu-img: --size N cannot be used together with a filename.
+qemu-img: At most one filename argument is allowed.
+qemu-img: --object, --image-opts, -f, and -l require a filename argument.
+qemu-img: --object, --image-opts, -f, and -l require a filename argument.
+qemu-img: --object, --image-opts, -f, and -l require a filename argument.
+qemu-img: --object, --image-opts, -f, and -l require a filename argument.
+qemu-img: Invalid option list: ,
+qemu-img: Invalid parameter 'snapshot.foo'
+qemu-img: Failed in parsing snapshot param 'snapshot.foo'
+qemu-img: --output must be used with human or json as argument.
+qemu-img: Image size must be less than 8 EiB!
+qemu-img: Unknown file format 'foo'
+
+== Size calculation for a new file (human) ==
+
+required size: 0
+fully allocated size: 0
+required size: 2147483648
+fully allocated size: 2147483648
+required size: 68719476736
+fully allocated size: 68719476736
+required size: 274877906944
+fully allocated size: 274877906944
+required size: 1099511627776
+fully allocated size: 1099511627776
+required size: 2251799813685248
+fully allocated size: 2251799813685248
+required size: 8070450532247928832
+fully allocated size: 8070450532247928832
+
+== Empty raw input image (human) ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
+required size: 0
+fully allocated size: 0
+
+converted image file size in bytes: 0
+
+== raw input image with data (human) ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+required size: 1073741824
+fully allocated size: 1073741824
+wrote 512/512 bytes at offset 512
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 64512/64512 bytes at offset 134217728
+63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+required size: 1073741824
+fully allocated size: 1073741824
+
+converted image file size in bytes: 1073741824
+
+== raw input image and preallocation (human) ==
+
+required size: 1073741824
+fully allocated size: 1073741824
+
+converted image file size in bytes: 1073741824
+
+== Fully-allocated raw input image (human) ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608
+wrote 8388608/8388608 bytes at offset 0
+8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+required size: 8388608
+fully allocated size: 8388608
+
+converted image file size in bytes: 8388608
+
+== Size calculation for a new file (json) ==
+
+{
+ "required": 0,
+ "fully-allocated": 0
+}
+{
+ "required": 2147483648,
+ "fully-allocated": 2147483648
+}
+{
+ "required": 68719476736,
+ "fully-allocated": 68719476736
+}
+{
+ "required": 274877906944,
+ "fully-allocated": 274877906944
+}
+{
+ "required": 1099511627776,
+ "fully-allocated": 1099511627776
+}
+{
+ "required": 2251799813685248,
+ "fully-allocated": 2251799813685248
+}
+{
+ "required": 8070450532247928832,
+ "fully-allocated": 8070450532247928832
+}
+
+== Empty raw input image (json) ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
+{
+ "required": 0,
+ "fully-allocated": 0
+}
+
+converted image file size in bytes: 0
+
+== raw input image with data (json) ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+{
+ "required": 1073741824,
+ "fully-allocated": 1073741824
+}
+wrote 512/512 bytes at offset 512
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 64512/64512 bytes at offset 134217728
+63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+{
+ "required": 1073741824,
+ "fully-allocated": 1073741824
+}
+
+converted image file size in bytes: 1073741824
+
+== raw input image and preallocation (json) ==
+
+{
+ "required": 1073741824,
+ "fully-allocated": 1073741824
+}
+
+converted image file size in bytes: 1073741824
+
+== Fully-allocated raw input image (json) ==
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608
+wrote 8388608/8388608 bytes at offset 0
+8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+{
+ "required": 8388608,
+ "fully-allocated": 8388608
+}
+
+converted image file size in bytes: 8388608
+*** done
diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181
index e969a2a94f..0333dda0e3 100755
--- a/tests/qemu-iotests/181
+++ b/tests/qemu-iotests/181
@@ -43,6 +43,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.qemu
_supported_fmt generic
+# Formats that do not support live migration
+_unsupported_fmt qcow vdi vhdx vmdk vpc vvfat
_supported_proto generic
_supported_os Linux
@@ -55,13 +57,24 @@ echo
qemu_comm_method="monitor"
-_launch_qemu \
- -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk
+if [ "$IMGOPTSSYNTAX" = "true" ]; then
+ _launch_qemu \
+ -drive "${TEST_IMG}",cache=${CACHEMODE},id=disk
+else
+ _launch_qemu \
+ -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk
+fi
src=$QEMU_HANDLE
-_launch_qemu \
- -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk \
- -incoming "unix:${MIG_SOCKET}"
+if [ "$IMGOPTSSYNTAX" = "true" ]; then
+ _launch_qemu \
+ -drive "${TEST_IMG}",cache=${CACHEMODE},id=disk \
+ -incoming "unix:${MIG_SOCKET}"
+else
+ _launch_qemu \
+ -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk \
+ -incoming "unix:${MIG_SOCKET}"
+fi
dest=$QEMU_HANDLE
echo
diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out
index 45bc7cb1a5..57eaf8d699 100644
--- a/tests/qemu-iotests/185.out
+++ b/tests/qemu-iotests/185.out
@@ -7,12 +7,12 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
=== Creating backing chain ===
-Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
wrote 4194304/4194304 bytes at offset 0
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": ""}
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
=== Start commit job and exit qemu ===
@@ -33,7 +33,7 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q
=== Start mirror job and exit qemu ===
{"return": {}}
-Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
@@ -42,7 +42,7 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 encryption=off clust
=== Start backup job and exit qemu ===
{"return": {}}
-Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
diff --git a/tests/qemu-iotests/188 b/tests/qemu-iotests/188
new file mode 100755
index 0000000000..83ed03e33e
--- /dev/null
+++ b/tests/qemu-iotests/188
@@ -0,0 +1,76 @@
+#!/bin/bash
+#
+# Test encrypted read/write using plain bdrv_read/bdrv_write
+#
+# Copyright (C) 2017 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=berrange@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto generic
+_supported_os Linux
+
+
+size=16M
+
+SECRET="secret,id=sec0,data=astrochicken"
+SECRETALT="secret,id=sec0,data=platypus"
+
+_make_test_img --object $SECRET -o "encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10" $size
+
+IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0"
+
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
+
+echo
+echo "== reading whole image =="
+$QEMU_IO --object $SECRET -c "read -P 0 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== rewriting whole image =="
+$QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== verify pattern =="
+$QEMU_IO --object $SECRET -c "read -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== verify open failure with wrong password =="
+$QEMU_IO --object $SECRETALT -c "read -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
+
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/188.out b/tests/qemu-iotests/188.out
new file mode 100644
index 0000000000..8af24e5d8b
--- /dev/null
+++ b/tests/qemu-iotests/188.out
@@ -0,0 +1,18 @@
+QA output created by 188
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10
+
+== reading whole image ==
+read 16777216/16777216 bytes at offset 0
+16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== rewriting whole image ==
+wrote 16777216/16777216 bytes at offset 0
+16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== verify pattern ==
+read 16777216/16777216 bytes at offset 0
+16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== verify open failure with wrong password ==
+can't open: Invalid password, cannot unlock any keyslot
+*** done
diff --git a/tests/qemu-iotests/189 b/tests/qemu-iotests/189
new file mode 100755
index 0000000000..54ad980a4e
--- /dev/null
+++ b/tests/qemu-iotests/189
@@ -0,0 +1,86 @@
+#!/bin/bash
+#
+# Test encrypted read/write using backing files
+#
+# Copyright (C) 2017 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=berrange@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto generic
+_supported_os Linux
+
+
+size=16M
+TEST_IMG_BASE=$TEST_IMG.base
+SECRET0="secret,id=sec0,data=astrochicken"
+SECRET1="secret,id=sec1,data=furby"
+
+TEST_IMG_SAVE=$TEST_IMG
+TEST_IMG=$TEST_IMG_BASE
+echo "== create base =="
+_make_test_img --object $SECRET0 -o "encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10" $size
+TEST_IMG=$TEST_IMG_SAVE
+
+IMGSPECBASE="driver=$IMGFMT,file.filename=$TEST_IMG_BASE,encrypt.key-secret=sec0"
+IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,backing.driver=$IMGFMT,backing.file.filename=$TEST_IMG_BASE,backing.encrypt.key-secret=sec0,encrypt.key-secret=sec1"
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
+
+echo
+echo "== writing whole image =="
+$QEMU_IO --object $SECRET0 -c "write -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== verify pattern =="
+$QEMU_IO --object $SECRET0 -c "read -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir
+
+echo "== create overlay =="
+_make_test_img --object $SECRET1 -o "encrypt.format=luks,encrypt.key-secret=sec1,encrypt.iter-time=10" -b "$TEST_IMG_BASE" $size
+
+echo
+echo "== writing part of a cluster =="
+$QEMU_IO --object $SECRET0 --object $SECRET1 -c "write -P 0xe 0 1024" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== verify pattern =="
+$QEMU_IO --object $SECRET0 --object $SECRET1 -c "read -P 0xe 0 1024" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
+echo
+echo "== verify pattern =="
+$QEMU_IO --object $SECRET0 --object $SECRET1 -c "read -P 0xa 1024 64512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
+
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/189.out b/tests/qemu-iotests/189.out
new file mode 100644
index 0000000000..a0b7c9c24c
--- /dev/null
+++ b/tests/qemu-iotests/189.out
@@ -0,0 +1,26 @@
+QA output created by 189
+== create base ==
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=16777216 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10
+
+== writing whole image ==
+wrote 16777216/16777216 bytes at offset 0
+16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== verify pattern ==
+read 16777216/16777216 bytes at offset 0
+16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== create overlay ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base encrypt.format=luks encrypt.key-secret=sec1 encrypt.iter-time=10
+
+== writing part of a cluster ==
+wrote 1024/1024 bytes at offset 0
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== verify pattern ==
+read 1024/1024 bytes at offset 0
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== verify pattern ==
+read 64512/64512 bytes at offset 1024
+63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index 4b1c6749b7..2a55ec9ada 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -141,7 +141,7 @@ _wallclock()
_timestamp()
{
now=`date "+%T"`
- echo -n " [$now]"
+ printf %s " [$now]"
}
_wrapup()
@@ -255,7 +255,7 @@ seq="check"
for seq in $list
do
err=false
- echo -n "$seq"
+ printf %s "$seq"
if [ -n "$TESTS_REMAINING_LOG" ] ; then
sed -e "s/$seq//" -e 's/ / /' -e 's/^ *//' $TESTS_REMAINING_LOG > $TESTS_REMAINING_LOG.tmp
mv $TESTS_REMAINING_LOG.tmp $TESTS_REMAINING_LOG
@@ -281,9 +281,9 @@ do
rm -f $seq.out.bad
lasttime=`sed -n -e "/^$seq /s/.* //p" <$TIMESTAMP_FILE`
if [ "X$lasttime" != X ]; then
- echo -n " ${lasttime}s ..."
+ printf %s " ${lasttime}s ..."
else
- echo -n " " # prettier output with timestamps.
+ printf " " # prettier output with timestamps.
fi
rm -f core $seq.notrun
@@ -291,7 +291,7 @@ do
echo "$seq" > "${TEST_DIR}"/check.sts
start=`_wallclock`
- $timestamp && echo -n " ["`date "+%T"`"]"
+ $timestamp && printf %s " [$(date "+%T")]"
if [ "$(head -n 1 "$source_iotests/$seq")" == "#!/usr/bin/env python" ]; then
run_command="$PYTHON $seq"
@@ -314,21 +314,21 @@ do
if [ -f core ]
then
- echo -n " [dumped core]"
+ printf " [dumped core]"
mv core $seq.core
err=true
fi
if [ -f $seq.notrun ]
then
- $timestamp || echo -n " [not run] "
- $timestamp && echo " [not run]" && echo -n " $seq -- "
+ $timestamp || printf " [not run] "
+ $timestamp && echo " [not run]" && printf %s " $seq -- "
cat $seq.notrun
notrun="$notrun $seq"
else
if [ $sts -ne 0 ]
then
- echo -n " [failed, exit status $sts]"
+ printf %s " [failed, exit status $sts]"
err=true
fi
@@ -338,6 +338,11 @@ do
reference="$reference_machine"
fi
+ reference_format="$source_iotests/$seq.out.$IMGFMT"
+ if [ -f "$reference_format" ]; then
+ reference="$reference_format"
+ fi
+
if [ "$CACHEMODE" = "none" ]; then
[ -f "$source_iotests/$seq.out.nocache" ] && reference="$source_iotests/$seq.out.nocache"
fi
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
index f2a7199c4b..d34c11c056 100644
--- a/tests/qemu-iotests/common
+++ b/tests/qemu-iotests/common
@@ -50,6 +50,7 @@ export IMGPROTO=file
export IMGOPTS=""
export CACHEMODE="writeback"
export QEMU_IO_OPTIONS=""
+export QEMU_IO_OPTIONS_NO_FMT=""
export CACHEMODE_IS_DEFAULT=true
export QEMU_OPTIONS="-nodefaults -machine accel=qtest"
export VALGRIND_QEMU=
@@ -413,10 +414,11 @@ BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
done
# Set qemu-io cache mode with $CACHEMODE we have
-if [ "$IMGOPTSSYNTAX" = "true" ]; then
- QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE"
-else
- QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT --cache $CACHEMODE"
+QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE"
+
+QEMU_IO_OPTIONS_NO_FMT="$QEMU_IO_OPTIONS"
+if [ "$IMGOPTSSYNTAX" != "true" ]; then
+ QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT"
fi
# Set default options for qemu-img create -o if they were not specified
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
index d1b45f5447..e0883a0c65 100644
--- a/tests/qemu-iotests/common.config
+++ b/tests/qemu-iotests/common.config
@@ -103,6 +103,17 @@ if [ -z "$QEMU_VXHS_PROG" ]; then
export QEMU_VXHS_PROG="`set_prog_path qnio_server`"
fi
+export QEMU_PROG=$(realpath -- "$(type -p "$QEMU_PROG")")
+export QEMU_IMG_PROG=$(realpath -- "$(type -p "$QEMU_IMG_PROG")")
+export QEMU_IO_PROG=$(realpath -- "$(type -p "$QEMU_IO_PROG")")
+export QEMU_NBD_PROG=$(realpath -- "$(type -p "$QEMU_NBD_PROG")")
+
+# This program is not built as part of qemu but (possibly) provided by the
+# system, so it may not be present at all
+if [ -n "$QEMU_VXHS_PROG" ]; then
+ export QEMU_VXHS_PROG=$(realpath -- "$(type -p "$QEMU_VXHS_PROG")")
+fi
+
_qemu_wrapper()
{
(
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 2f595b2ce2..7a58e57317 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -126,7 +126,8 @@ _filter_img_create()
-e "s# block_state_zero=\\(on\\|off\\)##g" \
-e "s# log_size=[0-9]\\+##g" \
-e "s# refcount_bits=[0-9]\\+##g" \
- -e "s# key-secret=[a-zA-Z0-9]\\+##g"
+ -e "s# key-secret=[a-zA-Z0-9]\\+##g" \
+ -e "s# iter-time=[0-9]\\+##g"
}
_filter_img_info()
diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu
index 76ef298d3f..7645f1dc72 100644
--- a/tests/qemu-iotests/common.qemu
+++ b/tests/qemu-iotests/common.qemu
@@ -153,14 +153,19 @@ function _launch_qemu()
mkfifo "${fifo_out}"
mkfifo "${fifo_in}"
+ object_options=
+ if [ -n "$IMGKEYSECRET" ]; then
+ object_options="--object secret,id=keysec0,data=$IMGKEYSECRET"
+ fi
+
if [ -z "$keep_stderr" ]; then
QEMU_NEED_PID='y'\
- ${QEMU} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \
+ ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \
2>&1 \
<"${fifo_in}" &
elif [ "$keep_stderr" = "y" ]; then
QEMU_NEED_PID='y'\
- ${QEMU} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \
+ ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \
<"${fifo_in}" &
else
exit 1
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 9fd3130bde..2548e58b99 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -107,6 +107,9 @@ _set_default_imgopts()
if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then
IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1")
fi
+ if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null); then
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10")
+ fi
}
_use_sample_img()
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 318ae74b10..2aba585287 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -112,6 +112,7 @@
103 rw auto quick
104 rw auto
105 rw auto quick
+106 rw auto quick
107 rw auto quick
108 rw auto quick
109 rw auto
@@ -130,6 +131,8 @@
122 rw auto
123 rw auto quick
124 rw auto backing
+125 rw auto
+126 rw auto backing
128 rw auto quick
129 rw auto quick
130 rw auto quick
@@ -163,6 +166,7 @@
159 rw auto quick
160 rw auto quick
162 auto quick
+165 rw auto quick
170 rw auto quick
171 rw auto quick
172 auto
@@ -171,8 +175,11 @@
175 auto quick
176 rw auto backing
177 rw auto quick
+178 auto quick
179 rw auto quick
181 rw auto migration
182 rw auto quick
183 rw auto migration
185 rw auto
+188 rw auto quick
+189 rw auto quick
diff --git a/tests/rocker/all b/tests/rocker/all
index d5ae9632a2..3f9b786daf 100755
--- a/tests/rocker/all
+++ b/tests/rocker/all
@@ -1,19 +1,19 @@
-echo -n "Running port test... "
+printf "Running port test... "
./port
if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi
-echo -n "Running bridge test... "
+printf "Running bridge test... "
./bridge
if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi
-echo -n "Running bridge STP test... "
+printf "Running bridge STP test... "
./bridge-stp
if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi
-echo -n "Running bridge VLAN test... "
+printf "Running bridge VLAN test... "
./bridge-vlan
if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi
-echo -n "Running bridge VLAN STP test... "
+printf "Running bridge VLAN STP test... "
./bridge-vlan-stp
if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi
diff --git a/tests/tcg/cris/Makefile b/tests/tcg/cris/Makefile
index 6b3dba446c..664b30ce81 100644
--- a/tests/tcg/cris/Makefile
+++ b/tests/tcg/cris/Makefile
@@ -150,17 +150,17 @@ check_addcv17.tst: crtv10.o sysv10.o
build: $(CRT) $(SYS) $(TESTCASES)
check: $(CRT) $(SYS) $(TESTCASES)
- @echo -e "\nQEMU simulator."
+ @printf "\nQEMU simulator.\n"
for case in $(TESTCASES); do \
- echo -n "$$case "; \
+ printf %s "$$case "; \
SIMARGS=; \
case $$case in *v17*) SIMARGS="-cpu crisv17";; esac; \
$(SIM) $$SIMARGS ./$$case; \
done
check-g: $(CRT) $(SYS) $(TESTCASES)
- @echo -e "\nGDB simulator."
+ @printf "\nGDB simulator.\n"
@for case in $(TESTCASES); do \
- echo -n "$$case "; \
+ printf %s "$$case "; \
$(SIMG) $$case; \
done
diff --git a/tests/test-char.c b/tests/test-char.c
index b962063e56..7ac25ff73f 100644
--- a/tests/test-char.c
+++ b/tests/test-char.c
@@ -178,6 +178,7 @@ static void char_mux_test(void)
fe_can_read,
fe_read,
fe_event,
+ NULL,
&h1,
NULL, true);
@@ -186,6 +187,7 @@ static void char_mux_test(void)
fe_can_read,
fe_read,
fe_event,
+ NULL,
&h2,
NULL, true);
qemu_chr_fe_take_focus(&chr_be2);
@@ -209,7 +211,8 @@ static void char_mux_test(void)
h1.read_count = 0;
/* remove first handler */
- qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, NULL, true);
+ qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
+ NULL, NULL, true);
qemu_chr_be_write(base, (void *)"hello", 6);
g_assert_cmpint(h1.read_count, ==, 0);
g_assert_cmpint(h2.read_count, ==, 0);
@@ -307,13 +310,13 @@ static void char_socket_test(void)
qemu_chr_fe_init(&be, chr, &error_abort);
qemu_chr_fe_set_handlers(&be, socket_can_read, socket_read,
- NULL, &d, NULL, true);
+ NULL, NULL, &d, NULL, true);
chr_client = qemu_chr_new("client", tmp);
qemu_chr_fe_init(&client_be, chr_client, &error_abort);
qemu_chr_fe_set_handlers(&client_be, socket_can_read_hello,
socket_read_hello,
- NULL, &d, NULL, true);
+ NULL, NULL, &d, NULL, true);
g_free(tmp);
d.conn_expected = true;
@@ -383,6 +386,7 @@ static void char_pipe_test(void)
fe_can_read,
fe_read,
fe_event,
+ NULL,
&fe,
NULL, true);
@@ -403,16 +407,11 @@ static void char_pipe_test(void)
}
#endif
-static void char_udp_test(void)
+static int make_udp_socket(int *port)
{
- struct sockaddr_in addr = { 0, }, other;
- SocketIdleData d = { 0, };
- Chardev *chr;
- CharBackend be;
+ struct sockaddr_in addr = { 0, };
socklen_t alen = sizeof(addr);
int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0);
- char buf[10];
- char *tmp;
g_assert_cmpint(sock, >, 0);
addr.sin_family = AF_INET ;
@@ -423,19 +422,41 @@ static void char_udp_test(void)
ret = getsockname(sock, (struct sockaddr *)&addr, &alen);
g_assert_cmpint(ret, ==, 0);
- tmp = g_strdup_printf("udp:127.0.0.1:%d",
- ntohs(addr.sin_port));
- chr = qemu_chr_new("client", tmp);
- g_assert_nonnull(chr);
+ *port = ntohs(addr.sin_port);
+ return sock;
+}
+
+static void char_udp_test_internal(Chardev *reuse_chr, int sock)
+{
+ struct sockaddr_in other;
+ SocketIdleData d = { 0, };
+ Chardev *chr;
+ CharBackend *be;
+ socklen_t alen = sizeof(other);
+ int ret;
+ char buf[10];
+ char *tmp = NULL;
+
+ if (reuse_chr) {
+ chr = reuse_chr;
+ be = chr->be;
+ } else {
+ int port;
+ sock = make_udp_socket(&port);
+ tmp = g_strdup_printf("udp:127.0.0.1:%d", port);
+ chr = qemu_chr_new("client", tmp);
+ g_assert_nonnull(chr);
+
+ be = g_alloca(sizeof(CharBackend));
+ qemu_chr_fe_init(be, chr, &error_abort);
+ }
d.chr = chr;
- qemu_chr_fe_init(&be, chr, &error_abort);
- qemu_chr_fe_set_handlers(&be, socket_can_read_hello, socket_read_hello,
- NULL, &d, NULL, true);
+ qemu_chr_fe_set_handlers(be, socket_can_read_hello, socket_read_hello,
+ NULL, NULL, &d, NULL, true);
ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5);
g_assert_cmpint(ret, ==, 5);
- alen = sizeof(addr);
ret = recvfrom(sock, buf, sizeof(buf), 0,
(struct sockaddr *)&other, &alen);
g_assert_cmpint(ret, ==, 5);
@@ -444,10 +465,18 @@ static void char_udp_test(void)
main_loop();
- close(sock);
+ if (!reuse_chr) {
+ close(sock);
+ qemu_chr_fe_deinit(be, true);
+ }
g_free(tmp);
}
+static void char_udp_test(void)
+{
+ char_udp_test_internal(NULL, 0);
+}
+
#ifdef HAVE_CHARDEV_SERIAL
static void char_serial_test(void)
{
@@ -474,81 +503,110 @@ static void char_serial_test(void)
}
#endif
-static void char_file_test(void)
+#ifndef _WIN32
+static void char_file_fifo_test(void)
{
+ Chardev *chr;
+ CharBackend be;
char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
+ char *fifo = g_build_filename(tmp_path, "fifo", NULL);
char *out = g_build_filename(tmp_path, "out", NULL);
- char *contents = NULL;
- ChardevFile file = { .out = out };
+ ChardevFile file = { .in = fifo,
+ .has_in = true,
+ .out = out };
ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
.u.file.data = &file };
+ FeHandler fe = { 0, };
+ int fd, ret;
+
+ if (mkfifo(fifo, 0600) < 0) {
+ abort();
+ }
+
+ fd = open(fifo, O_RDWR);
+ ret = write(fd, "fifo-in", 8);
+ g_assert_cmpint(ret, ==, 8);
+
+ chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend,
+ &error_abort);
+
+ qemu_chr_fe_init(&be, chr, &error_abort);
+ qemu_chr_fe_set_handlers(&be,
+ fe_can_read,
+ fe_read,
+ fe_event,
+ NULL,
+ &fe, NULL, true);
+
+ g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
+ qmp_chardev_send_break("label-foo", NULL);
+ g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
+ qmp_chardev_send_break("label-file", NULL);
+ g_assert_cmpint(fe.last_event, ==, CHR_EVENT_BREAK);
+
+ main_loop();
+
+ close(fd);
+
+ g_assert_cmpint(fe.read_count, ==, 8);
+ g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
+
+ qemu_chr_fe_deinit(&be, true);
+
+ g_unlink(fifo);
+ g_free(fifo);
+ g_unlink(out);
+ g_free(out);
+ g_rmdir(tmp_path);
+ g_free(tmp_path);
+}
+#endif
+
+static void char_file_test_internal(Chardev *ext_chr, const char *filepath)
+{
+ char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
+ char *out;
Chardev *chr;
+ char *contents = NULL;
+ ChardevFile file = {};
+ ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
+ .u.file.data = &file };
gsize length;
int ret;
- chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
- &error_abort);
+ if (ext_chr) {
+ chr = ext_chr;
+ out = g_strdup(filepath);
+ file.out = out;
+ } else {
+ out = g_build_filename(tmp_path, "out", NULL);
+ file.out = out;
+ chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
+ &error_abort);
+ }
ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6);
g_assert_cmpint(ret, ==, 6);
- object_unref(OBJECT(chr));
ret = g_file_get_contents(out, &contents, &length, NULL);
g_assert(ret == TRUE);
g_assert_cmpint(length, ==, 6);
g_assert(strncmp(contents, "hello!", 6) == 0);
- g_free(contents);
-
-#ifndef _WIN32
- {
- CharBackend be;
- FeHandler fe = { 0, };
- char *fifo = g_build_filename(tmp_path, "fifo", NULL);
- int fd;
-
- if (mkfifo(fifo, 0600) < 0) {
- abort();
- }
-
- fd = open(fifo, O_RDWR);
- ret = write(fd, "fifo-in", 8);
- g_assert_cmpint(ret, ==, 8);
-
- file.in = fifo;
- file.has_in = true;
- chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend,
- &error_abort);
-
- qemu_chr_fe_init(&be, chr, &error_abort);
- qemu_chr_fe_set_handlers(&be,
- fe_can_read,
- fe_read,
- fe_event,
- &fe, NULL, true);
-
- g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
- qmp_chardev_send_break("label-foo", NULL);
- g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
- qmp_chardev_send_break("label-file", NULL);
- g_assert_cmpint(fe.last_event, ==, CHR_EVENT_BREAK);
-
- main_loop();
- close(fd);
-
- g_assert_cmpint(fe.read_count, ==, 8);
- g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
- qemu_chr_fe_deinit(&be, true);
- g_unlink(fifo);
- g_free(fifo);
+ if (!ext_chr) {
+ object_unref(OBJECT(chr));
+ g_unlink(out);
}
-#endif
-
- g_unlink(out);
+ g_free(contents);
g_rmdir(tmp_path);
g_free(tmp_path);
g_free(out);
}
+static void char_file_test(void)
+{
+ char_file_test_internal(NULL, NULL);
+}
+
static void char_null_test(void)
{
Error *err = NULL;
@@ -583,6 +641,7 @@ static void char_null_test(void)
fe_can_read,
fe_read,
fe_event,
+ NULL,
NULL, NULL, true);
ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
@@ -599,6 +658,76 @@ static void char_invalid_test(void)
g_assert_null(chr);
}
+static int chardev_change(void *opaque)
+{
+ return 0;
+}
+
+static int chardev_change_denied(void *opaque)
+{
+ return -1;
+}
+
+static void char_hotswap_test(void)
+{
+ char *chr_args;
+ Chardev *chr;
+ CharBackend be;
+
+ gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
+ char *filename = g_build_filename(tmp_path, "file", NULL);
+ ChardevFile file = { .out = filename };
+ ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
+ .u.file.data = &file };
+ ChardevReturn *ret;
+
+ int port;
+ int sock = make_udp_socket(&port);
+ g_assert_cmpint(sock, >, 0);
+
+ chr_args = g_strdup_printf("udp:127.0.0.1:%d", port);
+
+ chr = qemu_chr_new("chardev", chr_args);
+ qemu_chr_fe_init(&be, chr, &error_abort);
+
+ /* check that chardev operates correctly */
+ char_udp_test_internal(chr, sock);
+
+ /* set the handler that denies the hotswap */
+ qemu_chr_fe_set_handlers(&be, NULL, NULL,
+ NULL, chardev_change_denied, NULL, NULL, true);
+
+ /* now, change is denied and has to keep the old backend operating */
+ ret = qmp_chardev_change("chardev", &backend, NULL);
+ g_assert(!ret);
+ g_assert(be.chr == chr);
+
+ char_udp_test_internal(chr, sock);
+
+ /* now allow the change */
+ qemu_chr_fe_set_handlers(&be, NULL, NULL,
+ NULL, chardev_change, NULL, NULL, true);
+
+ /* has to succeed now */
+ ret = qmp_chardev_change("chardev", &backend, &error_abort);
+ g_assert(be.chr != chr);
+
+ close(sock);
+ chr = be.chr;
+
+ /* run the file chardev test */
+ char_file_test_internal(chr, filename);
+
+ object_unparent(OBJECT(chr));
+
+ qapi_free_ChardevReturn(ret);
+ g_unlink(filename);
+ g_free(filename);
+ g_rmdir(tmp_path);
+ g_free(tmp_path);
+ g_free(chr_args);
+}
+
int main(int argc, char **argv)
{
qemu_init_main_loop(&error_abort);
@@ -625,11 +754,15 @@ int main(int argc, char **argv)
g_test_add_func("/char/pipe", char_pipe_test);
#endif
g_test_add_func("/char/file", char_file_test);
+#ifndef _WIN32
+ g_test_add_func("/char/file-fifo", char_file_fifo_test);
+#endif
g_test_add_func("/char/socket", char_socket_test);
g_test_add_func("/char/udp", char_udp_test);
#ifdef HAVE_CHARDEV_SERIAL
g_test_add_func("/char/serial", char_serial_test);
#endif
+ g_test_add_func("/char/hotswap", char_hotswap_test);
return g_test_run();
}
diff --git a/tests/test-crypto-block.c b/tests/test-crypto-block.c
index 95c4bd5da3..bd7fe593e3 100644
--- a/tests/test-crypto-block.c
+++ b/tests/test-crypto-block.c
@@ -281,7 +281,7 @@ static void test_block(gconstpointer opaque)
memset(&header, 0, sizeof(header));
buffer_init(&header, "header");
- blk = qcrypto_block_create(data->create_opts,
+ blk = qcrypto_block_create(data->create_opts, NULL,
test_block_init_func,
test_block_write_func,
&header,
@@ -300,7 +300,7 @@ static void test_block(gconstpointer opaque)
object_unparent(sec);
/* Ensure we can't open without the secret */
- blk = qcrypto_block_open(data->open_opts,
+ blk = qcrypto_block_open(data->open_opts, NULL,
test_block_read_func,
&header,
0,
@@ -308,7 +308,7 @@ static void test_block(gconstpointer opaque)
g_assert(blk == NULL);
/* Ensure we can't open without the secret, unless NO_IO */
- blk = qcrypto_block_open(data->open_opts,
+ blk = qcrypto_block_open(data->open_opts, NULL,
test_block_read_func,
&header,
QCRYPTO_BLOCK_OPEN_NO_IO,
@@ -322,7 +322,7 @@ static void test_block(gconstpointer opaque)
/* Now open for real with secret */
sec = test_block_secret();
- blk = qcrypto_block_open(data->open_opts,
+ blk = qcrypto_block_open(data->open_opts, NULL,
test_block_read_func,
&header,
0,
diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c
index 23773d2051..1acb353889 100644
--- a/tests/test-hbitmap.c
+++ b/tests/test-hbitmap.c
@@ -909,6 +909,22 @@ static void hbitmap_test_add(const char *testpath,
hbitmap_test_teardown);
}
+static void test_hbitmap_iter_and_reset(TestHBitmapData *data,
+ const void *unused)
+{
+ HBitmapIter hbi;
+
+ hbitmap_test_init(data, L1 * 2, 0);
+ hbitmap_set(data->hb, 0, data->size);
+
+ hbitmap_iter_init(&hbi, data->hb, BITS_PER_LONG - 1);
+
+ hbitmap_iter_next(&hbi);
+
+ hbitmap_reset_all(data->hb);
+ hbitmap_iter_next(&hbi);
+}
+
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
@@ -966,6 +982,9 @@ int main(int argc, char **argv)
test_hbitmap_serialize_part);
hbitmap_test_add("/hbitmap/serialize/zeroes",
test_hbitmap_serialize_zeroes);
+
+ hbitmap_test_add("/hbitmap/iter/iter_and_reset",
+ test_hbitmap_iter_and_reset);
g_test_run();
return 0;
diff --git a/tests/test-hmp.c b/tests/test-hmp.c
index 6dfa0c36e2..d77b3c8710 100644
--- a/tests/test-hmp.c
+++ b/tests/test-hmp.c
@@ -23,6 +23,7 @@ static const char *hmp_cmds[] = {
"boot_set ndc",
"chardev-add null,id=testchardev1",
"chardev-send-break testchardev2",
+ "chardev-change testchardev1 ringbuf",
"chardev-remove testchardev1",
"commit all",
"cpu-add 1",
diff --git a/tests/test-qdev-global-props.c b/tests/test-qdev-global-props.c
index 48e5b7315f..b25fe892ed 100644
--- a/tests/test-qdev-global-props.c
+++ b/tests/test-qdev-global-props.c
@@ -232,10 +232,10 @@ static void test_dynamic_globalprop(void)
g_test_trap_assert_passed();
g_test_trap_assert_stderr_unmatched("*prop1*");
g_test_trap_assert_stderr_unmatched("*prop2*");
- g_test_trap_assert_stderr("*Warning: global dynamic-prop-type-bad.prop3 has invalid class name\n*");
+ g_test_trap_assert_stderr("*warning: global dynamic-prop-type-bad.prop3 has invalid class name\n*");
g_test_trap_assert_stderr_unmatched("*prop4*");
- g_test_trap_assert_stderr("*Warning: global nohotplug-type.prop5=105 not used\n*");
- g_test_trap_assert_stderr("*Warning: global nondevice-type.prop6 has invalid class name\n*");
+ g_test_trap_assert_stderr("*warning: global nohotplug-type.prop5=105 not used\n*");
+ g_test_trap_assert_stderr("*warning: global nondevice-type.prop6 has invalid class name\n*");
g_test_trap_assert_stdout("");
}
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index b3cc045765..d4da09f147 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -464,7 +464,7 @@ static void test_server_create_chr(TestServer *server, const gchar *opt)
qemu_chr_fe_init(&server->chr, chr, &error_abort);
qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read,
- chr_event, server, NULL, true);
+ chr_event, NULL, server, NULL, true);
}
static void test_server_listen(TestServer *server)
diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c
index e7ba38c9d1..a49de9233b 100644
--- a/tests/vmgenid-test.c
+++ b/tests/vmgenid-test.c
@@ -15,6 +15,7 @@
#include "qemu/bitmap.h"
#include "qemu/uuid.h"
#include "hw/acpi/acpi-defs.h"
+#include "boot-sector.h"
#include "acpi-utils.h"
#include "libqtest.h"
@@ -23,8 +24,6 @@
* OVMF SDT Header Probe Supressor
*/
#define RSDP_ADDR_INVALID 0x100000 /* RSDP must be below this address */
-#define RSDP_SLEEP_US 100000 /* Sleep for 100ms between tries */
-#define RSDP_TRIES_MAX 100 /* Max total time is 10 seconds */
typedef struct {
AcpiTableHeader header;
@@ -47,14 +46,12 @@ static uint32_t acpi_find_vgia(void)
VgidTable vgid_table;
int i;
- /* Tables may take a short time to be set up by the guest */
- for (i = 0; i < RSDP_TRIES_MAX; i++) {
- rsdp_offset = acpi_find_rsdp_address();
- if (rsdp_offset < RSDP_ADDR_INVALID) {
- break;
- }
- g_usleep(RSDP_SLEEP_US);
- }
+ /* Wait for guest firmware to finish and start the payload. */
+ boot_sector_test();
+
+ /* Tables should be initialized now. */
+ rsdp_offset = acpi_find_rsdp_address();
+
g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID);
acpi_parse_rsdp_table(rsdp_offset, &rsdp_table);
@@ -131,6 +128,18 @@ static void read_guid_from_monitor(QemuUUID *guid)
QDECREF(rsp);
}
+static char disk[] = "tests/vmgenid-test-disk-XXXXXX";
+
+static char *guid_cmd_strdup(const char *guid)
+{
+ return g_strdup_printf("-machine accel=tcg "
+ "-device vmgenid,id=testvgid,guid=%s "
+ "-drive id=hd0,if=none,file=%s,format=raw "
+ "-device ide-hd,drive=hd0 ",
+ guid, disk);
+}
+
+
static void vmgenid_set_guid_test(void)
{
QemuUUID expected, measured;
@@ -138,8 +147,7 @@ static void vmgenid_set_guid_test(void)
g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
- cmd = g_strdup_printf("-machine accel=tcg -device vmgenid,id=testvgid,"
- "guid=%s", VGID_GUID);
+ cmd = guid_cmd_strdup(VGID_GUID);
qtest_start(cmd);
/* Read the GUID from accessing guest memory */
@@ -152,10 +160,10 @@ static void vmgenid_set_guid_test(void)
static void vmgenid_set_guid_auto_test(void)
{
- const char *cmd;
+ char *cmd;
QemuUUID measured;
- cmd = "-machine accel=tcg -device vmgenid,id=testvgid," "guid=auto";
+ cmd = guid_cmd_strdup("auto");
qtest_start(cmd);
read_guid_from_memory(&measured);
@@ -164,6 +172,7 @@ static void vmgenid_set_guid_auto_test(void)
g_assert(!qemu_uuid_is_null(&measured));
qtest_quit(global_qtest);
+ g_free(cmd);
}
static void vmgenid_query_monitor_test(void)
@@ -173,8 +182,7 @@ static void vmgenid_query_monitor_test(void)
g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
- cmd = g_strdup_printf("-machine accel=tcg -device vmgenid,id=testvgid,"
- "guid=%s", VGID_GUID);
+ cmd = guid_cmd_strdup(VGID_GUID);
qtest_start(cmd);
/* Read the GUID via the monitor */
@@ -189,6 +197,11 @@ int main(int argc, char **argv)
{
int ret;
+ ret = boot_sector_init(disk);
+ if (ret) {
+ return ret;
+ }
+
g_test_init(&argc, &argv, NULL);
qtest_add_func("/vmgenid/vmgenid/set-guid",
@@ -198,6 +211,7 @@ int main(int argc, char **argv)
qtest_add_func("/vmgenid/vmgenid/query-monitor",
vmgenid_query_monitor_test);
ret = g_test_run();
+ boot_sector_cleanup(disk);
return ret;
}
diff --git a/trace/control.c b/trace/control.c
index 9b157b0ca7..f5fb11d280 100644
--- a/trace/control.c
+++ b/trace/control.c
@@ -171,8 +171,8 @@ static void do_trace_enable_events(const char *line_buf)
while ((ev = trace_event_iter_next(&iter)) != NULL) {
if (!trace_event_get_state_static(ev)) {
if (!is_pattern) {
- error_report("WARNING: trace event '%s' is not traceable",
- line_ptr);
+ warn_report("trace event '%s' is not traceable",
+ line_ptr);
return;
}
continue;
@@ -186,8 +186,8 @@ static void do_trace_enable_events(const char *line_buf)
}
if (!is_pattern) {
- error_report("WARNING: trace event '%s' does not exist",
- line_ptr);
+ warn_report("trace event '%s' does not exist",
+ line_ptr);
}
}
diff --git a/util/error.c b/util/error.c
index 020b86b9f0..3efdd69162 100644
--- a/util/error.c
+++ b/util/error.c
@@ -232,6 +232,15 @@ void error_report_err(Error *err)
error_free(err);
}
+void warn_report_err(Error *err)
+{
+ warn_report("%s", error_get_pretty(err));
+ if (err->hint) {
+ error_printf_unless_qmp("%s", err->hint->str);
+ }
+ error_free(err);
+}
+
void error_reportf_err(Error *err, const char *fmt, ...)
{
va_list ap;
@@ -242,6 +251,17 @@ void error_reportf_err(Error *err, const char *fmt, ...)
error_report_err(err);
}
+
+void warn_reportf_err(Error *err, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ error_vprepend(&err, fmt, ap);
+ va_end(ap);
+ warn_report_err(err);
+}
+
void error_free(Error *err)
{
if (err) {
diff --git a/util/hbitmap.c b/util/hbitmap.c
index 35088e19c4..21535cc90b 100644
--- a/util/hbitmap.c
+++ b/util/hbitmap.c
@@ -13,6 +13,7 @@
#include "qemu/hbitmap.h"
#include "qemu/host-utils.h"
#include "trace.h"
+#include "crypto/hash.h"
/* HBitmaps provides an array of bits. The bits are stored as usual in an
* array of unsigned longs, but HBitmap is also optimized to provide fast
@@ -106,8 +107,9 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi)
unsigned long cur;
do {
- cur = hbi->cur[--i];
+ i--;
pos >>= BITS_PER_LEVEL;
+ cur = hbi->cur[i] & hb->levels[i][pos];
} while (cur == 0);
/* Check for end of iteration. We always use fewer than BITS_PER_LONG
@@ -139,6 +141,26 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi)
return cur;
}
+int64_t hbitmap_iter_next(HBitmapIter *hbi)
+{
+ unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1] &
+ hbi->hb->levels[HBITMAP_LEVELS - 1][hbi->pos];
+ int64_t item;
+
+ if (cur == 0) {
+ cur = hbitmap_iter_skip_words(hbi);
+ if (cur == 0) {
+ return -1;
+ }
+ }
+
+ /* The next call will resume work from the next bit. */
+ hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1);
+ item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ctzl(cur);
+
+ return item << hbi->granularity;
+}
+
void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first)
{
unsigned i, bit;
@@ -530,6 +552,23 @@ void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
}
}
+void hbitmap_deserialize_ones(HBitmap *hb, uint64_t start, uint64_t count,
+ bool finish)
+{
+ uint64_t el_count;
+ unsigned long *first;
+
+ if (!count) {
+ return;
+ }
+ serialization_chunk(hb, start, count, &first, &el_count);
+
+ memset(first, 0xff, el_count * sizeof(unsigned long));
+ if (finish) {
+ hbitmap_deserialize_finish(hb);
+ }
+}
+
void hbitmap_deserialize_finish(HBitmap *bitmap)
{
int64_t i, size, prev_size;
@@ -689,3 +728,13 @@ void hbitmap_free_meta(HBitmap *hb)
hbitmap_free(hb->meta);
hb->meta = NULL;
}
+
+char *hbitmap_sha256(const HBitmap *bitmap, Error **errp)
+{
+ size_t size = bitmap->sizes[HBITMAP_LEVELS - 1] * sizeof(unsigned long);
+ char *data = (char *)bitmap->levels[HBITMAP_LEVELS - 1];
+ char *hash = NULL;
+ qcrypto_hash_digest(QCRYPTO_HASH_ALG_SHA256, data, size, &hash, errp);
+
+ return hash;
+}
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index 5e8b4b39ed..b2dea48f40 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -414,72 +414,6 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
}
-static struct termios oldtty;
-
-static void term_exit(void)
-{
- tcsetattr(0, TCSANOW, &oldtty);
-}
-
-static void term_init(void)
-{
- struct termios tty;
-
- tcgetattr(0, &tty);
- oldtty = tty;
-
- tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
- |INLCR|IGNCR|ICRNL|IXON);
- tty.c_oflag |= OPOST;
- tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
- tty.c_cflag &= ~(CSIZE|PARENB);
- tty.c_cflag |= CS8;
- tty.c_cc[VMIN] = 1;
- tty.c_cc[VTIME] = 0;
-
- tcsetattr(0, TCSANOW, &tty);
-
- atexit(term_exit);
-}
-
-int qemu_read_password(char *buf, int buf_size)
-{
- uint8_t ch;
- int i, ret;
-
- printf("password: ");
- fflush(stdout);
- term_init();
- i = 0;
- for (;;) {
- ret = read(0, &ch, 1);
- if (ret == -1) {
- if (errno == EAGAIN || errno == EINTR) {
- continue;
- } else {
- break;
- }
- } else if (ret == 0) {
- ret = -1;
- break;
- } else {
- if (ch == '\r' ||
- ch == '\n') {
- ret = 0;
- break;
- }
- if (i < (buf_size - 1)) {
- buf[i++] = ch;
- }
- }
- }
- term_exit();
- buf[i] = '\0';
- printf("\n");
- return ret;
-}
-
-
char *qemu_get_pid_name(pid_t pid)
{
char *name = NULL;
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index 3de9e7777e..69a6286d50 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -552,30 +552,6 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
}
-/* XXX: put correct support for win32 */
-int qemu_read_password(char *buf, int buf_size)
-{
- int c, i;
-
- printf("Password: ");
- fflush(stdout);
- i = 0;
- for (;;) {
- c = getchar();
- if (c < 0) {
- buf[i] = '\0';
- return -1;
- } else if (c == '\n') {
- break;
- } else if (i < (buf_size - 1)) {
- buf[i++] = c;
- }
- }
- buf[i] = '\0';
- return 0;
-}
-
-
char *qemu_get_pid_name(pid_t pid)
{
/* XXX Implement me */
diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c
index b44b5d55eb..846ff9167f 100644
--- a/util/qemu-coroutine-lock.c
+++ b/util/qemu-coroutine-lock.c
@@ -402,6 +402,21 @@ void qemu_co_rwlock_unlock(CoRwlock *lock)
qemu_co_mutex_unlock(&lock->mutex);
}
+void qemu_co_rwlock_downgrade(CoRwlock *lock)
+{
+ Coroutine *self = qemu_coroutine_self();
+
+ /* lock->mutex critical section started in qemu_co_rwlock_wrlock or
+ * qemu_co_rwlock_upgrade.
+ */
+ assert(lock->reader == 0);
+ lock->reader++;
+ qemu_co_mutex_unlock(&lock->mutex);
+
+ /* The rest of the read-side critical section is run without the mutex. */
+ self->locks_held++;
+}
+
void qemu_co_rwlock_wrlock(CoRwlock *lock)
{
qemu_co_mutex_lock(&lock->mutex);
@@ -416,3 +431,23 @@ void qemu_co_rwlock_wrlock(CoRwlock *lock)
* There is no need to update self->locks_held.
*/
}
+
+void qemu_co_rwlock_upgrade(CoRwlock *lock)
+{
+ Coroutine *self = qemu_coroutine_self();
+
+ qemu_co_mutex_lock(&lock->mutex);
+ assert(lock->reader > 0);
+ lock->reader--;
+ lock->pending_writer++;
+ while (lock->reader) {
+ qemu_co_queue_wait(&lock->queue, &lock->mutex);
+ }
+ lock->pending_writer--;
+
+ /* The rest of the write-side critical section is run with
+ * the mutex taken, similar to qemu_co_rwlock_wrlock. Do
+ * not account for the lock twice in self->locks_held.
+ */
+ self->locks_held--;
+}
diff --git a/util/qemu-error.c b/util/qemu-error.c
index b331f8f4a4..c557c6ae47 100644
--- a/util/qemu-error.c
+++ b/util/qemu-error.c
@@ -14,6 +14,16 @@
#include "monitor/monitor.h"
#include "qemu/error-report.h"
+/*
+ * @report_type is the type of message: error, warning or
+ * informational.
+ */
+typedef enum {
+ REPORT_TYPE_ERROR,
+ REPORT_TYPE_WARNING,
+ REPORT_TYPE_INFO,
+} report_type;
+
void error_printf(const char *fmt, ...)
{
va_list ap;
@@ -146,7 +156,7 @@ const char *error_get_progname(void)
/*
* Print current location to current monitor if we have one, else to stderr.
*/
-static void error_print_loc(void)
+static void print_loc(void)
{
const char *sep = "";
int i;
@@ -179,17 +189,29 @@ static void error_print_loc(void)
bool enable_timestamp_msg;
/*
- * Print an error message to current monitor if we have one, else to stderr.
+ * Print a message to current monitor if we have one, else to stderr.
+ * @report_type is the type of message: error, warning or informational.
* Format arguments like vsprintf(). The resulting message should be
* a single phrase, with no newline or trailing punctuation.
* Prepend the current location and append a newline.
* It's wrong to call this in a QMP monitor. Use error_setg() there.
*/
-void error_vreport(const char *fmt, va_list ap)
+static void vreport(report_type type, const char *fmt, va_list ap)
{
GTimeVal tv;
gchar *timestr;
+ switch (type) {
+ case REPORT_TYPE_ERROR:
+ break;
+ case REPORT_TYPE_WARNING:
+ error_printf("warning: ");
+ break;
+ case REPORT_TYPE_INFO:
+ error_printf("info: ");
+ break;
+ }
+
if (enable_timestamp_msg && !cur_mon) {
g_get_current_time(&tv);
timestr = g_time_val_to_iso8601(&tv);
@@ -197,15 +219,52 @@ void error_vreport(const char *fmt, va_list ap)
g_free(timestr);
}
- error_print_loc();
+ print_loc();
error_vprintf(fmt, ap);
error_printf("\n");
}
/*
* Print an error message to current monitor if we have one, else to stderr.
- * Format arguments like sprintf(). The resulting message should be a
- * single phrase, with no newline or trailing punctuation.
+ * Format arguments like vsprintf(). The resulting message should be
+ * a single phrase, with no newline or trailing punctuation.
+ * Prepend the current location and append a newline.
+ * It's wrong to call this in a QMP monitor. Use error_setg() there.
+ */
+void error_vreport(const char *fmt, va_list ap)
+{
+ vreport(REPORT_TYPE_ERROR, fmt, ap);
+}
+
+/*
+ * Print a warning message to current monitor if we have one, else to stderr.
+ * Format arguments like vsprintf(). The resulting message should be
+ * a single phrase, with no newline or trailing punctuation.
+ * Prepend the current location and append a newline.
+ * It's wrong to call this in a QMP monitor. Use error_setg() there.
+ */
+void warn_vreport(const char *fmt, va_list ap)
+{
+ vreport(REPORT_TYPE_WARNING, fmt, ap);
+}
+
+/*
+ * Print an information message to current monitor if we have one, else to
+ * stderr.
+ * Format arguments like vsprintf(). The resulting message should be
+ * a single phrase, with no newline or trailing punctuation.
+ * Prepend the current location and append a newline.
+ * It's wrong to call this in a QMP monitor. Use error_setg() there.
+ */
+void info_vreport(const char *fmt, va_list ap)
+{
+ vreport(REPORT_TYPE_INFO, fmt, ap);
+}
+
+/*
+ * Print an error message to current monitor if we have one, else to stderr.
+ * Format arguments like sprintf(). The resulting message should be
+ * a single phrase, with no newline or trailing punctuation.
* Prepend the current location and append a newline.
* It's wrong to call this in a QMP monitor. Use error_setg() there.
*/
@@ -214,6 +273,39 @@ void error_report(const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- error_vreport(fmt, ap);
+ vreport(REPORT_TYPE_ERROR, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Print a warning message to current monitor if we have one, else to stderr.
+ * Format arguments like sprintf(). The resulting message should be a
+ * single phrase, with no newline or trailing punctuation.
+ * Prepend the current location and append a newline.
+ * It's wrong to call this in a QMP monitor. Use error_setg() there.
+ */
+void warn_report(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vreport(REPORT_TYPE_WARNING, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Print an information message to current monitor if we have one, else to
+ * stderr.
+ * Format arguments like sprintf(). The resulting message should be a
+ * single phrase, with no newline or trailing punctuation.
+ * Prepend the current location and append a newline.
+ * It's wrong to call this in a QMP monitor. Use error_setg() there.
+ */
+void info_report(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vreport(REPORT_TYPE_INFO, fmt, ap);
va_end(ap);
}
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index d3e51089de..1358c81bcc 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -104,17 +104,16 @@ NetworkAddressFamily inet_netfamily(int family)
* f t PF_INET6
* t - PF_INET
* t f PF_INET
- * t t PF_INET6
+ * t t PF_INET6/PF_UNSPEC
*
* NB, this matrix is only about getting the necessary results
* from getaddrinfo(). Some of the cases require further work
* after reading results from getaddrinfo in order to fully
- * apply the logic the end user wants. eg with the last case
- * ipv4=t + ipv6=t + PF_INET6, getaddrinfo alone can only
- * guarantee the ipv6=t part of the request - we need more
- * checks to provide ipv4=t part of the guarantee. This is
- * outside scope of this method and not currently handled by
- * callers at all.
+ * apply the logic the end user wants.
+ *
+ * In the first and last cases, we must set IPV6_V6ONLY=0
+ * when binding, to allow a single listener to potentially
+ * accept both IPv4+6 addresses.
*/
int inet_ai_family_from_address(InetSocketAddress *addr,
Error **errp)
@@ -124,6 +123,23 @@ int inet_ai_family_from_address(InetSocketAddress *addr,
error_setg(errp, "Cannot disable IPv4 and IPv6 at same time");
return PF_UNSPEC;
}
+ if ((addr->has_ipv6 && addr->ipv6) && (addr->has_ipv4 && addr->ipv4)) {
+ /*
+ * Some backends can only do a single listener. In that case
+ * we want empty hostname to resolve to "::" and then use the
+ * flag IPV6_V6ONLY==0 to get both protocols on 1 socket. This
+ * doesn't work for addresses other than "", so they're just
+ * inevitably broken until multiple listeners can be used,
+ * and thus we honour getaddrinfo automatic protocol detection
+ * Once all backends do multi-listener, remove the PF_INET6
+ * branch entirely.
+ */
+ if (!addr->host || g_str_equal(addr->host, "")) {
+ return PF_INET6;
+ } else {
+ return PF_UNSPEC;
+ }
+ }
if ((addr->has_ipv6 && addr->ipv6) || (addr->has_ipv4 && !addr->ipv4)) {
return PF_INET6;
}
@@ -208,22 +224,43 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
}
socket_set_fast_reuse(slisten);
-#ifdef IPV6_V6ONLY
- if (e->ai_family == PF_INET6) {
- /* listen on both ipv4 and ipv6 */
- const int off = 0;
- qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &off,
- sizeof(off));
- }
-#endif
port_min = inet_getport(e);
port_max = saddr->has_to ? saddr->to + port_offset : port_min;
for (p = port_min; p <= port_max; p++) {
+#ifdef IPV6_V6ONLY
+ /*
+ * Deals with first & last cases in matrix in comment
+ * for inet_ai_family_from_address().
+ */
+ int v6only =
+ ((!saddr->has_ipv4 && !saddr->has_ipv6) ||
+ (saddr->has_ipv4 && saddr->ipv4 &&
+ saddr->has_ipv6 && saddr->ipv6)) ? 0 : 1;
+#endif
inet_setport(e, p);
+#ifdef IPV6_V6ONLY
+ rebind:
+ if (e->ai_family == PF_INET6) {
+ qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &v6only,
+ sizeof(v6only));
+ }
+#endif
if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
goto listen;
}
+
+#ifdef IPV6_V6ONLY
+ /* If we got EADDRINUSE from an IPv6 bind & V6ONLY is unset,
+ * it could be that the IPv4 port is already claimed, so retry
+ * with V6ONLY set
+ */
+ if (e->ai_family == PF_INET6 && errno == EADDRINUSE && !v6only) {
+ v6only = 1;
+ goto rebind;
+ }
+#endif
+
if (p == port_max) {
if (!e->ai_next) {
error_setg_errno(errp, errno, "Failed to bind socket");
@@ -603,16 +640,12 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
error_setg(errp, "error parsing IPv6 address '%s'", str);
return -1;
}
- addr->ipv6 = addr->has_ipv6 = true;
} else {
/* hostname or IPv4 addr */
if (sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos) != 2) {
error_setg(errp, "error parsing address '%s'", str);
return -1;
}
- if (host[strspn(host, "0123456789.")] == '\0') {
- addr->ipv4 = addr->has_ipv4 = true;
- }
}
addr->host = g_strdup(host);
@@ -1325,40 +1358,6 @@ SocketAddress *socket_remote_address(int fd, Error **errp)
return socket_sockaddr_to_address(&ss, sslen, errp);
}
-char *socket_address_to_string(struct SocketAddress *addr, Error **errp)
-{
- char *buf;
- InetSocketAddress *inet;
-
- switch (addr->type) {
- case SOCKET_ADDRESS_TYPE_INET:
- inet = &addr->u.inet;
- if (strchr(inet->host, ':') == NULL) {
- buf = g_strdup_printf("%s:%s", inet->host, inet->port);
- } else {
- buf = g_strdup_printf("[%s]:%s", inet->host, inet->port);
- }
- break;
-
- case SOCKET_ADDRESS_TYPE_UNIX:
- buf = g_strdup(addr->u.q_unix.path);
- break;
-
- case SOCKET_ADDRESS_TYPE_FD:
- buf = g_strdup(addr->u.fd.str);
- break;
-
- case SOCKET_ADDRESS_TYPE_VSOCK:
- buf = g_strdup_printf("%s:%s",
- addr->u.vsock.cid,
- addr->u.vsock.port);
- break;
-
- default:
- abort();
- }
- return buf;
-}
SocketAddress *socket_address_flatten(SocketAddressLegacy *addr_legacy)
{
diff --git a/vl.c b/vl.c
index f7560de622..fb6b2efafa 100644
--- a/vl.c
+++ b/vl.c
@@ -952,8 +952,8 @@ static void bt_vhci_add(int vlan_id)
struct bt_scatternet_s *vlan = qemu_find_bt_vlan(vlan_id);
if (!vlan->slave)
- error_report("warning: adding a VHCI to an empty scatternet %i",
- vlan_id);
+ warn_report("adding a VHCI to an empty scatternet %i",
+ vlan_id);
bt_vhci_init(bt_new_hci(vlan));
}
@@ -979,8 +979,8 @@ static struct bt_device_s *bt_device_add(const char *opt)
vlan = qemu_find_bt_vlan(vlan_id);
if (!vlan->slave)
- error_report("warning: adding a slave device to an empty scatternet %i",
- vlan_id);
+ warn_report("adding a slave device to an empty scatternet %i",
+ vlan_id);
if (!strcmp(devname, "keyboard"))
return bt_keyboard_init(vlan);
@@ -2302,8 +2302,8 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp)
return -1;
}
if (strncmp(name, "opt/", 4) != 0) {
- error_report("warning: externally provided fw_cfg item names "
- "should be prefixed with \"opt/\"");
+ warn_report("externally provided fw_cfg item names "
+ "should be prefixed with \"opt/\"");
}
if (nonempty_str(str)) {
size = strlen(str); /* NUL terminator NOT included in fw_cfg blob */
@@ -3760,7 +3760,7 @@ int main(int argc, char **argv, char **envp)
qemu_opts_parse_noisily(olist, "accel=tcg", false);
break;
case QEMU_OPTION_no_kvm_pit: {
- error_report("warning: ignoring deprecated option");
+ warn_report("ignoring deprecated option");
break;
}
case QEMU_OPTION_no_kvm_pit_reinjection: {
@@ -3770,8 +3770,8 @@ int main(int argc, char **argv, char **envp)
.value = "discard",
};
- error_report("warning: deprecated, replaced by "
- "-global kvm-pit.lost_tick_policy=discard");
+ warn_report("deprecated, replaced by "
+ "-global kvm-pit.lost_tick_policy=discard");
qdev_prop_register_global(&kvm_pit_lost_tick_policy);
break;
}
@@ -3896,7 +3896,7 @@ int main(int argc, char **argv, char **envp)
}
break;
case QEMU_OPTION_tdf:
- error_report("warning: ignoring deprecated option");
+ warn_report("ignoring deprecated option");
break;
case QEMU_OPTION_name:
opts = qemu_opts_parse_noisily(qemu_find_opts("name"),
@@ -3933,10 +3933,10 @@ int main(int argc, char **argv, char **envp)
configure_rtc(opts);
break;
case QEMU_OPTION_tb_size:
- if (!tcg_enabled()) {
- error_report("TCG is disabled");
- exit(1);
- }
+#ifndef CONFIG_TCG
+ error_report("TCG is disabled");
+ exit(1);
+#endif
if (qemu_strtoul(optarg, NULL, 0, &tcg_tb_size) < 0) {
error_report("Invalid argument to -tb-size");
exit(1);