Re: [Qemu-devel] [RFC PATCH qemu] spapr: Stop providing RTAS blob

2019-07-15 Thread no-reply
Patchew URL: https://patchew.org/QEMU/20190716053522.78813-1-...@ozlabs.ru/



Hi,

This series failed build test on FreeBSD host. Please find the details below.

=== TEST SCRIPT BEGIN ===
#!/bin/bash
# Testing script will be invoked under the git checkout with
# HEAD pointing to a commit that has the patches applied on top of "base"
# branch
if qemu-system-x86_64 --help >/dev/null 2>&1; then
  QEMU=qemu-system-x86_64
elif /usr/libexec/qemu-kvm --help >/dev/null 2>&1; then
  QEMU=/usr/libexec/qemu-kvm
else
  exit 1
fi
make vm-build-freebsd J=21 QEMU=$QEMU
exit 0
=== TEST SCRIPT END ===




The full log is available at
http://patchew.org/logs/20190716053522.78813-1-...@ozlabs.ru/testing.FreeBSD/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-de...@redhat.com

[Qemu-devel] [RFC PATCH qemu] spapr: Stop providing RTAS blob

2019-07-15 Thread Alexey Kardashevskiy
SLOF implements one itself so let's remove it from QEMU. It is one less
image and simpler setup as the RTAS blob never stays in its initial place
anyway as the guest OS always decides where to put it.

This totally depends on https://patchwork.ozlabs.org/patch/1132440/ ,
hence RFC.

Signed-off-by: Alexey Kardashevskiy 
---
 configure   |   6 +
 Makefile|   2 +-
 pc-bios/spapr-rtas/Makefile |  27 -
 include/hw/ppc/spapr.h  |   2 --
 hw/ppc/spapr.c  |  32 ++---
 hw/ppc/spapr_rtas.c |  41 
 MAINTAINERS |   2 --
 pc-bios/spapr-rtas.bin  | Bin 20 -> 0 bytes
 pc-bios/spapr-rtas/spapr-rtas.S |  37 
 9 files changed, 4 insertions(+), 145 deletions(-)
 delete mode 100644 pc-bios/spapr-rtas/Makefile
 delete mode 100644 pc-bios/spapr-rtas.bin
 delete mode 100644 pc-bios/spapr-rtas/spapr-rtas.S

diff --git a/configure b/configure
index 4983c8b53300..a132d2eb5666 100755
--- a/configure
+++ b/configure
@@ -6205,9 +6205,6 @@ if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && 
\
 fi
 done
 fi
-if test "$ARCH" = "ppc64" && test "$targetos" != "Darwin" ; then
-  roms="$roms spapr-rtas"
-fi
 
 # Only build s390-ccw bios if we're on s390x and the compiler has -march=z900
 if test "$cpu" = "s390x" ; then
@@ -7919,14 +7916,13 @@ fi
 DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos 
tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests tests/vm"
 DIRS="$DIRS tests/fp tests/qgraph"
 DIRS="$DIRS docs docs/interop fsdev scsi"
-DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
+DIRS="$DIRS pc-bios/optionrom pc-bios/s390-ccw"
 DIRS="$DIRS roms/seabios roms/vgabios"
 LINKS="Makefile tests/tcg/Makefile"
 LINKS="$LINKS tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
 LINKS="$LINKS tests/tcg/lm32/Makefile tests/tcg/xtensa/Makefile po/Makefile"
 LINKS="$LINKS tests/fp/Makefile"
 LINKS="$LINKS pc-bios/optionrom/Makefile pc-bios/keymaps"
-LINKS="$LINKS pc-bios/spapr-rtas/Makefile"
 LINKS="$LINKS pc-bios/s390-ccw/Makefile"
 LINKS="$LINKS roms/seabios/Makefile roms/vgabios/Makefile"
 LINKS="$LINKS pc-bios/qemu-icon.bmp"
diff --git a/Makefile b/Makefile
index 1fcbaed62c76..d780f4eebceb 100644
--- a/Makefile
+++ b/Makefile
@@ -764,7 +764,7 @@ efi-e1000e.rom efi-vmxnet3.rom \
 bamboo.dtb canyonlands.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
 multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin pvh.bin \
 s390-ccw.img s390-netboot.img \
-spapr-rtas.bin slof.bin skiboot.lid \
+slof.bin skiboot.lid \
 palcode-clipper \
 u-boot.e500 u-boot-sam460-20100605.bin \
 qemu_vga.ndrv \
diff --git a/pc-bios/spapr-rtas/Makefile b/pc-bios/spapr-rtas/Makefile
deleted file mode 100644
index 4b9bb1230658..
--- a/pc-bios/spapr-rtas/Makefile
+++ /dev/null
@@ -1,27 +0,0 @@
-all: build-all
-# Dummy command so that make thinks it has done something
-   @true
-
-include ../../config-host.mak
-include $(SRC_PATH)/rules.mak
-
-$(call set-vpath, $(SRC_PATH)/pc-bios/spapr-rtas)
-
-.PHONY : all clean build-all
-
-#CFLAGS += -I$(SRC_PATH)
-#QEMU_CFLAGS = $(CFLAGS)
-
-build-all: spapr-rtas.bin
-
-%.o: %.S
-   $(call quiet-command,$(CCAS) -mbig -c -o $@ $<,"CCAS","$(TARGET_DIR)$@")
-
-%.img: %.o
-   $(call quiet-command,$(CC) -nostdlib -mbig -o $@ 
$<,"Building","$(TARGET_DIR)$@")
-
-%.bin: %.img
-   $(call quiet-command,$(OBJCOPY) -O binary -j .text $< 
$@,"Building","$(TARGET_DIR)$@")
-
-clean:
-   rm -f *.o *.d *.img *.bin *~
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 60553d32c4fa..b6640370c839 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -152,8 +152,6 @@ struct SpaprMachineState {
 
 hwaddr rma_size;
 int vrma_adjust;
-ssize_t rtas_size;
-void *rtas_blob;
 uint32_t fdt_size;
 uint32_t fdt_initial_size;
 void *fdt_blob;
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 8783b433960c..36cd45bd78b3 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -89,7 +89,6 @@
  * We load our kernel at 4M, leaving space for SLOF initial image
  */
 #define FDT_MAX_SIZE0x10
-#define RTAS_MAX_SIZE   0x1
 #define RTAS_MAX_ADDR   0x8000 /* RTAS must stay below that */
 #define FW_MAX_SIZE 0x40
 #define FW_FILE_NAME"slof.bin"
@@ -1704,8 +1703,7 @@ static void spapr_machine_reset(MachineState *machine)
 {
 SpaprMachineState *spapr = SPAPR_MACHINE(machine);
 PowerPCCPU *first_ppc_cpu;
-uint32_t rtas_limit;
-hwaddr rtas_addr, fdt_addr;
+hwaddr fdt_addr;
 void *fdt;
 int rc;
 
@@ -1783,14 +1781,10 @@ static void spapr_machine_reset(MachineState *machine)
  * or just below 2GB, whichever is lower, so that it can be
  * processed with 32-bit real mode code if necessary
  */
-rtas_limit = 

Re: [Qemu-devel] [PATCH v2 10/11] block/backup: support bitmap sync modes for non-bitmap backups

2019-07-15 Thread Markus Armbruster
John Snow  writes:

> Accept bitmaps and sync policies for the other backup modes.
> This allows us to do things like create a bitmap synced to a full backup
> without a transaction, or start a resumable backup process.
>
> Some combinations don't make sense, though:
>
> - NEVER policy combined with any non-BITMAP mode doesn't do anything,
>   because the bitmap isn't used for input or output.
>   It's harmless, but is almost certainly never what the user wanted.
>
> - sync=NONE is more questionable. It can't use on-success because this
>   job never completes with success anyway, and the resulting artifact
>   of 'always' is suspect: because we start with a full bitmap and only
>   copy out segments that get written to, the final output bitmap will
>   always be ... a fully set bitmap.
>
>   Maybe there's contexts in which bitmaps make sense for sync=none,
>   but not without more severe changes to the current job, and omitting
>   it here doesn't prevent us from adding it later.
>
> Signed-off-by: John Snow 
> ---
[...]
> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index 5a578806c5..099e4f37b2 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -1352,13 +1352,15 @@
>  # @speed: the maximum speed, in bytes per second. The default is 0,
>  # for unlimited.
>  #
> -# @bitmap: the name of a dirty bitmap if sync is "bitmap" or "incremental".
> +# @bitmap: The name of a dirty bitmap to use.
>  #  Must be present if sync is "bitmap" or "incremental".
> +#  Can be present if sync is "full" or "top".
>  #  Must not be present otherwise.
>  #  (Since 2.4 (drive-backup), 3.1 (blockdev-backup))
>  #
>  # @bitmap-mode: Specifies the type of data the bitmap should contain after
> -#   the operation concludes. Must be present if sync is "bitmap".
> +#   the operation concludes.
> +#   Must be present if a bitmap was provided,
>  #   Must NOT be present otherwise. (Since 4.2)
>  #
>  # @compress: true to compress data, if the target format supports it.

Do you expect management applications will want to know about the
presence of this patch?



[Qemu-devel] [PATCH] ppc/pnv: Warn when using -initrd and low ram

2019-07-15 Thread Joel Stanley
When booting with the default amount of RAM the powernv machine will
load the initrd above the top of RAM and cause the Linux kernel to crash
when it attempts to access the initrd:

  Linux/PowerPC load:
  Finalizing device tree... flat tree at 0x202770c0
  [0.070476] nvram: Failed to find or create lnx,oops-log partition, err -28
  [0.073270] nvram: Failed to initialize oops partition!
  [0.156302] BUG: Unable to handle kernel data access at 0xc0006000
  [0.158009] Faulting instruction address: 0xc1002e5c
  cpu 0x0: Vector: 300 (Data Access) at [c0003d1e3870]
  pc: c1002e5c: unpack_to_rootfs+0xdc/0x2f0
  lr: c1002df4: unpack_to_rootfs+0x74/0x2f0
  sp: c0003d1e3b00
 msr: 92009033
 dar: c0006000
   dsisr: 4000
current = 0xc0003d1c
paca= 0xc132 irqmask: 0x03   irq_happened: 0x01
  pid   = 1, comm = swapper/0
  Linux version 5.2.0-10292-g040e2e618374 (joel@voyager) (gcc version 8.3.0 
(Debian 8.3.0-2)) #1 SMP Tue Jul 16 13:50:32 ACST 2019
  enter ? for help
  [c0003d1e3bb0] c1003c90 populate_rootfs+0x84/0x1dc
  [c0003d1e3c40] c000f494 do_one_initcall+0x88/0x1d0
  [c0003d1e3d10] c1000fc4 kernel_init_freeable+0x24c/0x250
  [c0003d1e3db0] c000f7a0 kernel_init+0x1c/0x150
  [c0003d1e3e20] c000b8a4 ret_from_kernel_thread+0x5c/0x78

Provide a helpful message for users so they don't go reporting bugs to
kernel developers.

Signed-off-by: Joel Stanley 
---
We could solve this in other ways, such as warn when loading the initrd
outside of RAM, or load it within the known boundaries or RAM, but after
hitting this myself I wanted to start the discussion.

Signed-off-by: Joel Stanley 
---
 hw/ppc/pnv.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index bd4531c82260..bbd596ab9eca 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -649,6 +649,13 @@ static void pnv_init(MachineState *machine)
 
 /* load initrd */
 if (machine->initrd_filename) {
+if (machine->ram_size <= (1.5 * GiB)) {
+/* INITRD_LOAD_ADDR is at 1.5GB, so we require at least that much 
RAM
+ * when specifying the initrd on the command line */
+warn_report("initrd load requires > %ld MB of RAM",
+INITRD_LOAD_ADDR / MiB);
+}
+
 pnv->initrd_base = INITRD_LOAD_ADDR;
 pnv->initrd_size = load_image_targphys(machine->initrd_filename,
   pnv->initrd_base, INITRD_MAX_SIZE);
-- 
2.20.1




[Qemu-devel] [PULL 0/3] Build system and documentation patches for 2019-07-15

2019-07-15 Thread Markus Armbruster
The following changes since commit 5ea8ec2fcf57cb9af24ad2cf17b4d64adb03afdf:

  Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2019-07-15' 
into staging (2019-07-15 16:11:47 +0100)

are available in the Git repository at:

  git://repo.or.cz/qemu/armbru.git tags/pull-build-2019-07-15

for you to fetch changes up to 32481687e1a262a9ca0083f8e938d7b0614d823b:

  qemu-tech: Fix dangling @menu entries (2019-07-15 21:10:29 +0200)


Build system and documentation patches for 2019-07-15


Markus Armbruster (3):
  Makefile: Fix "make install" when "make all" needs work
  Makefile: Fix missing dependency of on qemu-tech.texi
  qemu-tech: Fix dangling @menu entries

 Makefile   | 4 +++-
 qemu-tech.texi | 3 ---
 2 files changed, 3 insertions(+), 4 deletions(-)

-- 
2.21.0




[Qemu-devel] [PULL 3/3] qemu-tech: Fix dangling @menu entries

2019-07-15 Thread Markus Armbruster
Recent commit 2f2c4e4731 "Convert "translator internals" docs to RST,
move to devel manual" and commit 282d36b5e2 "qemu-tech.texi: Remove
"QEMU compared to other emulators" section" removed @node, but left
their @menu entries behind.  This broke building qemu-doc.info (but
not qemu-doc.{html,pdf,txt}; how odd).  Bury the dead @menu entries.

Reported-by: Philippe Mathieu-Daudé 
Fixes: 2f2c4e4731449449a2b1aafcd73e4f9ae107d78b
Fixes: 282d36b5e27ba86d42d0638430e439c2c257367b
Signed-off-by: Markus Armbruster 
Message-Id: <20190715055736.15214-3-arm...@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé 
Tested-by: Philippe Mathieu-Daudé 
Reviewed-by: Peter Maydell 
---
 qemu-tech.texi | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/qemu-tech.texi b/qemu-tech.texi
index 3451cfaa5b..0380de77b6 100644
--- a/qemu-tech.texi
+++ b/qemu-tech.texi
@@ -3,10 +3,7 @@
 
 @menu
 * CPU emulation::
-* Translator Internals::
-* QEMU compared to other emulators::
 * Managed start up options::
-* Bibliography::
 @end menu
 
 @node CPU emulation
-- 
2.21.0




[Qemu-devel] [PULL 2/3] Makefile: Fix missing dependency of on qemu-tech.texi

2019-07-15 Thread Markus Armbruster
The qemu-doc.{html,info,pdf,txt} depend on qemu-doc.texi and its
include files.  Except qemu-tech.texi is missing.  Has always been
missing as far as I can see.  Fix it.

Signed-off-by: Markus Armbruster 
Message-Id: <20190715055736.15214-2-arm...@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé 
Tested-by: Philippe Mathieu-Daudé 
---
 Makefile | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 09b77e8a7b..f9791dcb82 100644
--- a/Makefile
+++ b/Makefile
@@ -1021,7 +1021,8 @@ pdf: qemu-doc.pdf docs/interop/qemu-qmp-ref.pdf 
docs/interop/qemu-ga-ref.pdf
 txt: qemu-doc.txt docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt
 
 qemu-doc.html qemu-doc.info qemu-doc.pdf qemu-doc.txt: \
-   qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \
+   qemu-img.texi qemu-nbd.texi qemu-options.texi \
+   qemu-tech.texi qemu-option-trace.texi \
qemu-deprecated.texi qemu-monitor.texi qemu-img-cmds.texi qemu-ga.texi \
qemu-monitor-info.texi docs/qemu-block-drivers.texi \
docs/qemu-cpu-models.texi docs/security.texi
-- 
2.21.0




[Qemu-devel] [PULL 1/3] Makefile: Fix "make install" when "make all" needs work

2019-07-15 Thread Markus Armbruster
Until recently, target install used to recurse into target directories
in its recipe: it ran make install in a for-loop.  Since target
install depends on target all, this trivially ensured we run the
sub-make install only after completing target all.

Commit 1338a4b "Makefile: Reuse all's recursion machinery for clean
and install" moved the target recursion to dependencies.  That's good
(the commit message explains why), but I forgot to add dependencies to
ensure make runs the sub-make install only after completing target
all.  Do that now.

Fixes: 1338a4b72659ce08eacb9de0205fe16202a22d9c
Reported-by: Mark Cave-Ayland 
Reported-by: Guenter Roeck 
Tested-by: Guenter Roeck 
Signed-off-by: Markus Armbruster 
Message-Id: <20190712055935.23061-1-arm...@redhat.com>
Reviewed-by: Daniel P. Berrangé 
Reviewed-by: Stefano Garzarella 
Tested-by: Mark Cave-Ayland 
---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index 1fcbaed62c..09b77e8a7b 100644
--- a/Makefile
+++ b/Makefile
@@ -522,6 +522,7 @@ $(ROM_DIRS_RULES):
 recurse-all: $(addsuffix /all, $(TARGET_DIRS) $(ROM_DIRS))
 recurse-clean: $(addsuffix /clean, $(TARGET_DIRS) $(ROM_DIRS))
 recurse-install: $(addsuffix /install, $(TARGET_DIRS))
+$(addsuffix /install, $(TARGET_DIRS)): all
 
 $(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ 
$<,"RC","version.o")
-- 
2.21.0




[Qemu-devel] [PATCH] ppc: Improve SMT experience with TCG accel

2019-07-15 Thread Jose Ricardo Ziviani
It's not possible to specify the number of threads of a guest when
running QEMU/TCG. Today, users can have setups like:

... -accel tcg,thread=multi -smp 8,threads=1,cores=8 ...
or
... -accel tcg,thread=multi -smp 8,sockets=2,cores=4,threads=1 ...

However, the following is not possible:

... -accel tcg,thread=multi -smp 16,threads=4,cores=2,sockets=2 ...
qemu-system-ppc64: TCG cannot support more than 1 thread/core on a pseries 
machine

The reason is due to how SMT is implemented since Power8. This patch
implements a very basic simulation of the msgsndp instruction, using ext
interrupt instead of doorbells. The result is a better user experience,
allowing them to play with SMT modes. However, it doesn't relate with
MTTCG threads in any way.

Results:
... -accel tcg,thread=multi -smp 16,threads=4,cores=2,sockets=2 ...

root@ubuntu:~# ppc64_cpu --smt
SMT=4
root@ubuntu:~# ppc64_cpu --info
Core   0:0*1*2*3*
Core   1:4*5*6*7*
Core   2:8*9*   10*   11*
Core   3:   12*   13*   14*   15*
root@ubuntu:~# ppc64_cpu --smt=2
root@ubuntu:~# ppc64_cpu --info
Core   0:0*1*2 3
Core   1:4*5*6 7
Core   2:8*9*   1011
Core   3:   12*   13*   1415
root@ubuntu:~# ppc64_cpu --smt=off
root@ubuntu:~# ppc64_cpu --info
Core   0:0*1 2 3
Core   1:4*5 6 7
Core   2:8*91011
Core   3:   12*   131415

root@ubuntu:~# ppc64_cpu --smt
SMT is off
root@ubuntu:~# lscpu
Architecture: ppc64le
Byte Order:   Little Endian
CPU(s):   16
On-line CPU(s) list:  0,4,8,12
Off-line CPU(s) list: 1-3,5-7,9-11,13-15
Thread(s) per core:   1
Core(s) per socket:   2
Socket(s):2
NUMA node(s): 1
Model:2.0 (pvr 004e 1200)
Model name:   POWER9 (architected), altivec supported
Hypervisor vendor:KVM
Virtualization type:  para
L1d cache:32K
L1i cache:32K
NUMA node0 CPU(s):0,4,8,12

root@ubuntu:~# ppc64_cpu --smt=4
root@ubuntu:~# lscpu
Architecture:ppc64le
Byte Order:  Little Endian
CPU(s):  16
On-line CPU(s) list: 0-15
Thread(s) per core:  4
Core(s) per socket:  2
Socket(s):   2
NUMA node(s):1
Model:   2.0 (pvr 004e 1200)
Model name:  POWER9 (architected), altivec supported
Hypervisor vendor:   KVM
Virtualization type: para
L1d cache:   32K
L1i cache:   32K
NUMA node0 CPU(s):   0-15

Note: it's also possible to simulate SMT in TCG single threaded mode.

Signed-off-by: Jose Ricardo Ziviani 
---
 hw/ppc/spapr.c   |  5 -
 target/ppc/excp_helper.c | 24 
 target/ppc/helper.h  |  1 +
 target/ppc/translate.c   | 11 +++
 4 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 8783b43396..3a864dfc7d 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -2572,11 +2572,6 @@ static void spapr_set_vsmt_mode(SpaprMachineState 
*spapr, Error **errp)
 int ret;
 unsigned int smp_threads = ms->smp.threads;
 
-if (!kvm_enabled() && (smp_threads > 1)) {
-error_setg(_err, "TCG cannot support more than 1 thread/core "
- "on a pseries machine");
-goto out;
-}
 if (!is_power_of_2(smp_threads)) {
 error_setg(_err, "Cannot support %d threads/core on a pseries "
  "machine because it must be a power of 2", smp_threads);
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 50b004d00d..ac5d196641 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1231,6 +1231,30 @@ static int book3s_dbell2irq(target_ulong rb)
 return msg == DBELL_TYPE_DBELL_SERVER ? PPC_INTERRUPT_HDOORBELL : -1;
 }
 
+void helper_msgsndp(target_ulong rb)
+{
+CPUState *cs;
+int irq = rb & DBELL_TYPE_MASK;
+int thread_id = rb & 0x3f;
+
+if (irq != DBELL_TYPE_DBELL_SERVER) {
+return;
+}
+
+qemu_mutex_lock_iothread();
+CPU_FOREACH(cs) {
+PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+if (cpu->vcpu_id == thread_id) {
+continue;
+}
+
+cpu->env.pending_interrupts |= 1 << PPC_INTERRUPT_EXT;
+cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+}
+qemu_mutex_unlock_iothread();
+}
+
 void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
 {
 int irq = book3s_dbell2irq(rb);
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 380c9b1e2a..eadd08324b 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -630,6 +630,7 @@ DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, 
tl, tl)
 
 DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_NO_RWG_SE, tl, tl)
 DEF_HELPER_1(msgsnd, void, tl)
+DEF_HELPER_1(msgsndp, void, tl)
 DEF_HELPER_2(msgclr, void, env, tl)
 DEF_HELPER_1(book3s_msgsnd, void, tl)
 DEF_HELPER_2(book3s_msgclr, void, env, tl)
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 

[Qemu-devel] [PATCH 1/1] virtio-net: check guest header length is valid

2019-07-15 Thread Oleinik, Alexander
virtio-net checks that the "out" sg is longer than the guest header, but
this check can be skipped if has_net_hdr is 0. Also perform this check
if host_hdr_len != guest_hdr_len

Signed-off-by: Alexander Oleinik 
---
 hw/net/virtio-net.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index b9e1cd71cf..46d715b4f5 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -2064,7 +2064,18 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
  */
 assert(n->host_hdr_len <= n->guest_hdr_len);
 if (n->host_hdr_len != n->guest_hdr_len) {
-unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg),
+unsigned sg_num;
+
+if (!n->has_vnet_hdr) {
+if (iov_to_buf(out_sg, out_num, 0, , n->guest_hdr_len) <
+n->guest_hdr_len) {
+virtio_error(vdev, "virtio-net header incorrect");
+virtqueue_detach_element(q->tx_vq, elem, 0);
+g_free(elem);
+return -EINVAL;
+}
+}
+sg_num = iov_copy(sg, ARRAY_SIZE(sg),
out_sg, out_num,
0, n->host_hdr_len);
 sg_num += iov_copy(sg + sg_num, ARRAY_SIZE(sg) - sg_num,
-- 
2.20.1




[Qemu-devel] [PATCH 0/1] Add check for header length in virtio-net-tx

2019-07-15 Thread Oleinik, Alexander
While fuzzing the virtio-net tx vq, I ran into an assertion failure due
to iov_copy offsets larger than the total iov size. Though there is
a check to cover this, it does not execute when !n->has_vnet_hdr. This
patch tries to fix this. 

The call stack for the assertion failure:

#8 in __assert_fail (libc.so.6+0x300f1)
#9 in iov_copy iov.c:266:5
#10 in virtio_net_flush_tx virtio-net.c:2073:23
#11 in virtio_net_tx_bh virtio-net.c:2197:11
#12 in aio_bh_poll async.c:118:13
#13 in aio_dispatch aio-posix.c:460:5
#14 in aio_ctx_dispatch async.c:261:5
#15 in g_main_context_dispatch (libglib-2.0.so.0+0x4df2d)
#16 in glib_pollfds_poll main-loop.c:213:9
#17 in os_host_main_loop_wait main-loop.c:236
#18 in main_loop_wait main-loop.c:512
#19 in virtio_net_tx_fuzz virtio-net-fuzz.c:160:3

Thanks
-Alex

Alexander Oleinik (1):
  virtio-net: check guest header length is valid

 hw/net/virtio-net.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

-- 
2.20.1




Re: [Qemu-devel] [PATCH v4 0/5] spapr: implement dispatch and suspend calls

2019-07-15 Thread no-reply
Patchew URL: https://patchew.org/QEMU/20190716024726.17864-1-npig...@gmail.com/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Subject: [Qemu-devel] [PATCH v4 0/5] spapr: implement dispatch and suspend calls
Message-id: 20190716024726.17864-1-npig...@gmail.com
Type: series

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Switched to a new branch 'test'
c432dea spapr: Implement ibm,suspend-me
09bae6b spapr: Implement H_JOIN
031bd3f spapr: Implement H_CONFER
a3d8bc2 spapr: Implement H_PROD
ed23e67 spapr: Implement dispatch counter and prod bit on tcg

=== OUTPUT BEGIN ===
1/5 Checking commit ed23e6798f18 (spapr: Implement dispatch counter and prod 
bit on tcg)
ERROR: line over 90 characters
#33: FILE: hw/ppc/spapr.c:4316:
+stl_be_phys(cs->as, spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, 
spapr_cpu->dispatch_counter);

total: 1 errors, 0 warnings, 131 lines checked

Patch 1/5 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

2/5 Checking commit a3d8bc2510cc (spapr: Implement H_PROD)
3/5 Checking commit 031bd3f6986b (spapr: Implement H_CONFER)
4/5 Checking commit 09bae6bec0c1 (spapr: Implement H_JOIN)
ERROR: braces {} are necessary for all arms of this statement
#55: FILE: hw/ppc/spapr_hcall.c:1092:
+if (c == cpu)
[...]

ERROR: code indent should never use tabs
#58: FILE: hw/ppc/spapr_hcall.c:1095:
+^I/* Don't have a way to indicate joined, so use halted && MSR[EE]=0 */$

total: 2 errors, 0 warnings, 63 lines checked

Patch 4/5 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

5/5 Checking commit c432deae5480 (spapr: Implement ibm,suspend-me)
ERROR: braces {} are necessary for all arms of this statement
#93: FILE: hw/ppc/spapr_rtas.c:234:
+if (c == cpu)
[...]

ERROR: code indent should never use tabs
#96: FILE: hw/ppc/spapr_rtas.c:237:
+^I/* See h_join */$

WARNING: Block comments use a leading /* on a separate line
#128: FILE: include/hw/ppc/spapr.h:174:
+/* Machine has been suspended, so the next machine_reset should not

WARNING: Block comments use a trailing */ on a separate line
#129: FILE: include/hw/ppc/spapr.h:175:
+ * reset state, but just return and allow execution to resume. */

total: 2 errors, 2 warnings, 108 lines checked

Patch 5/5 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20190716024726.17864-1-npig...@gmail.com/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-de...@redhat.com

[Qemu-devel] [PATCH v4 4/5] spapr: Implement H_JOIN

2019-07-15 Thread Nicholas Piggin
This has been useful to modify and test the Linux pseries suspend
code but it requires modification to the guest to call it (due to
being gated by other unimplemented features). It is not otherwise
used by Linux yet, but work is slowly progressing there.

Signed-off-by: Nicholas Piggin 
---
 hw/ppc/spapr.c   |  1 +
 hw/ppc/spapr_hcall.c | 44 
 2 files changed, 45 insertions(+)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 87b11e2484..5c54e1cb9a 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1066,6 +1066,7 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, void 
*fdt)
 add_str(hypertas, "hcall-tce");
 add_str(hypertas, "hcall-vio");
 add_str(hypertas, "hcall-splpar");
+add_str(hypertas, "hcall-join");
 add_str(hypertas, "hcall-bulk");
 add_str(hypertas, "hcall-set-mode");
 add_str(hypertas, "hcall-sprg0");
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 28d58113be..52847a7047 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1069,6 +1069,47 @@ static target_ulong h_cede(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
 return H_SUCCESS;
 }
 
+static target_ulong h_join(PowerPCCPU *cpu, SpaprMachineState *spapr,
+   target_ulong opcode, target_ulong *args)
+{
+CPUPPCState *env = >env;
+CPUState *cs;
+SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+bool last_unjoined = true;
+
+if (env->msr & (1ULL << MSR_EE)) {
+return H_BAD_MODE;
+}
+
+if (spapr_cpu->prod) {
+spapr_cpu->prod = false;
+return H_SUCCESS;
+}
+
+CPU_FOREACH(cs) {
+PowerPCCPU *c = POWERPC_CPU(cs);
+CPUPPCState *e = >env;
+if (c == cpu)
+continue;
+
+   /* Don't have a way to indicate joined, so use halted && MSR[EE]=0 */
+if (!cs->halted || (e->msr & (1ULL << MSR_EE))) {
+last_unjoined = false;
+break;
+}
+}
+if (last_unjoined) {
+return H_CONTINUE;
+}
+
+cs = CPU(cpu);
+cs->halted = 1;
+cs->exception_index = EXCP_HALTED;
+cs->exit_request = 1;
+
+return H_SUCCESS;
+}
+
 static target_ulong h_confer(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
 {
@@ -1959,6 +2000,9 @@ static void hypercall_register_types(void)
 spapr_register_hypercall(H_CONFER, h_confer);
 spapr_register_hypercall(H_PROD, h_prod);
 
+/* hcall-join */
+spapr_register_hypercall(H_JOIN, h_join);
+
 spapr_register_hypercall(H_SIGNAL_SYS_RESET, h_signal_sys_reset);
 
 /* processor register resource access h-calls */
-- 
2.20.1




[Qemu-devel] [PATCH v4 5/5] spapr: Implement ibm,suspend-me

2019-07-15 Thread Nicholas Piggin
This has been useful to modify and test the Linux pseries suspend
code but it requires modification to the guest to call it (due to
being gated by other unimplemented features). It is not otherwise
used by Linux yet, but work is slowly progressing there.

This allows a (lightly modified) guest kernel to suspend with
`echo mem > /sys/power/state` and be resumed with system_wakeup
monitor command.

Signed-off-by: Nicholas Piggin 
---
 hw/ppc/spapr.c | 26 ++
 hw/ppc/spapr_rtas.c| 32 
 include/hw/ppc/spapr.h |  7 ++-
 3 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 5c54e1cb9a..b85d41bb1e 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1710,6 +1710,11 @@ static void spapr_machine_reset(MachineState *machine)
 void *fdt;
 int rc;
 
+if (spapr->suspend_reset) {
+spapr->suspend_reset = false;
+return;
+}
+
 spapr_caps_apply(spapr);
 
 first_ppc_cpu = POWERPC_CPU(first_cpu);
@@ -2721,6 +2726,23 @@ static PCIHostState *spapr_create_default_phb(void)
 return PCI_HOST_BRIDGE(dev);
 }
 
+static Notifier wakeup;
+static void spapr_notify_wakeup(Notifier *notifier, void *data)
+{
+WakeupReason *reason = data;
+
+switch (*reason) {
+case QEMU_WAKEUP_REASON_RTC:
+break;
+case QEMU_WAKEUP_REASON_PMTIMER:
+break;
+case QEMU_WAKEUP_REASON_OTHER:
+break;
+default:
+break;
+}
+}
+
 /* pSeries LPAR / sPAPR hardware init */
 static void spapr_machine_init(MachineState *machine)
 {
@@ -3078,6 +3100,10 @@ static void spapr_machine_init(MachineState *machine)
 
 qemu_register_boot_set(spapr_boot_set, spapr);
 
+wakeup.notify = spapr_notify_wakeup;
+qemu_register_wakeup_notifier();
+qemu_register_wakeup_support();
+
 if (kvm_enabled()) {
 /* to stop and start vmclock */
 qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index a618a2ac0f..60a007ec38 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -216,6 +216,36 @@ static void rtas_stop_self(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
 qemu_cpu_kick(cs);
 }
 
+static void rtas_ibm_suspend_me(PowerPCCPU *cpu, SpaprMachineState *spapr,
+   uint32_t token, uint32_t nargs,
+   target_ulong args,
+   uint32_t nret, target_ulong rets)
+{
+CPUState *cs;
+
+if (nargs != 0 || nret != 1) {
+rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+return;
+}
+
+CPU_FOREACH(cs) {
+PowerPCCPU *c = POWERPC_CPU(cs);
+CPUPPCState *e = >env;
+if (c == cpu)
+continue;
+
+   /* See h_join */
+if (!cs->halted || (e->msr & (1ULL << MSR_EE))) {
+rtas_st(rets, 0, H_MULTI_THREADS_ACTIVE);
+return;
+}
+}
+
+spapr->suspend_reset = true;
+qemu_system_suspend_request();
+rtas_st(rets, 0, RTAS_OUT_SUCCESS);
+}
+
 static inline int sysparm_st(target_ulong addr, target_ulong len,
  const void *val, uint16_t vallen)
 {
@@ -483,6 +513,8 @@ static void core_rtas_register_types(void)
 rtas_query_cpu_stopped_state);
 spapr_rtas_register(RTAS_START_CPU, "start-cpu", rtas_start_cpu);
 spapr_rtas_register(RTAS_STOP_SELF, "stop-self", rtas_stop_self);
+spapr_rtas_register(RTAS_IBM_SUSPEND_ME, "ibm,suspend-me",
+rtas_ibm_suspend_me);
 spapr_rtas_register(RTAS_IBM_GET_SYSTEM_PARAMETER,
 "ibm,get-system-parameter",
 rtas_ibm_get_system_parameter);
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 5d36eec9d0..df0b0c15da 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -171,6 +171,10 @@ struct SpaprMachineState {
 bool use_hotplug_event_source;
 SpaprEventSource *event_sources;
 
+/* Machine has been suspended, so the next machine_reset should not
+ * reset state, but just return and allow execution to resume. */
+bool suspend_reset;
+
 /* ibm,client-architecture-support option negotiation */
 bool cas_reboot;
 bool cas_legacy_guest_workaround;
@@ -631,8 +635,9 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong 
opcode,
 #define RTAS_IBM_CREATE_PE_DMA_WINDOW   (RTAS_TOKEN_BASE + 0x27)
 #define RTAS_IBM_REMOVE_PE_DMA_WINDOW   (RTAS_TOKEN_BASE + 0x28)
 #define RTAS_IBM_RESET_PE_DMA_WINDOW(RTAS_TOKEN_BASE + 0x29)
+#define RTAS_IBM_SUSPEND_ME (RTAS_TOKEN_BASE + 0x2A)
 
-#define RTAS_TOKEN_MAX  (RTAS_TOKEN_BASE + 0x2A)
+#define RTAS_TOKEN_MAX  (RTAS_TOKEN_BASE + 0x2B)
 
 /* RTAS ibm,get-system-parameter token values */
 #define RTAS_SYSPARM_SPLPAR_CHARACTERISTICS  20
-- 
2.20.1




[Qemu-devel] [PATCH v4 3/5] spapr: Implement H_CONFER

2019-07-15 Thread Nicholas Piggin
This does not do directed yielding and is not quite as strict as PAPR
specifies in terms of precise dispatch behaviour. This generally will
mean suboptimal performance, rather than guest misbehaviour. Linux
does not rely on exact dispatch behaviour.

Signed-off-by: Nicholas Piggin 
---
 hw/ppc/spapr_hcall.c | 48 
 1 file changed, 48 insertions(+)

diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 8b208ab259..28d58113be 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1069,6 +1069,53 @@ static target_ulong h_cede(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
 return H_SUCCESS;
 }
 
+static target_ulong h_confer(PowerPCCPU *cpu, SpaprMachineState *spapr,
+   target_ulong opcode, target_ulong *args)
+{
+target_long target = args[0];
+uint32_t dispatch = args[1];
+PowerPCCPU *target_cpu = spapr_find_cpu(target);
+CPUState *target_cs = CPU(target_cpu);
+CPUState *cs = CPU(cpu);
+SpaprCpuState *spapr_cpu;
+
+/*
+ * This does not do a targeted yield or confer, but check the parameter
+ * anyway. -1 means confer to all/any other CPUs.
+ */
+if (target != -1 && !target_cs) {
+return H_PARAMETER;
+}
+
+spapr_cpu = spapr_cpu_state(target_cpu);
+
+/*
+ * PAPR specifies waiting until proded in this case, without dispatch
+ * counter check.
+ */
+if (cpu == target_cpu) {
+if (spapr_cpu->prod) {
+spapr_cpu->prod = false;
+return H_SUCCESS;
+}
+
+cs->halted = 1;
+cs->exception_index = EXCP_HALTED;
+cs->exit_request = 1;
+
+return H_SUCCESS;
+}
+
+if (spapr_cpu->dispatch_counter != dispatch || (dispatch & 1) == 0) {
+return H_SUCCESS;
+}
+
+cs->exception_index = EXCP_YIELD;
+cpu_loop_exit(cs);
+
+return H_SUCCESS;
+}
+
 static target_ulong h_prod(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
 {
@@ -1909,6 +1956,7 @@ static void hypercall_register_types(void)
 /* hcall-splpar */
 spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
 spapr_register_hypercall(H_CEDE, h_cede);
+spapr_register_hypercall(H_CONFER, h_confer);
 spapr_register_hypercall(H_PROD, h_prod);
 
 spapr_register_hypercall(H_SIGNAL_SYS_RESET, h_signal_sys_reset);
-- 
2.20.1




[Qemu-devel] [PATCH v4 0/5] spapr: implement dispatch and suspend calls

2019-07-15 Thread Nicholas Piggin
This series follows on from the previous that added H_PROD and
H_CONFER, but I've now aimed to make it conform better to PAPR.

It's still not completely there (as explained in comments), but
it's better than before and actually better matches KVM that
does implement the prod bit and dispatch counter.

The first 3 patches implement these splpar hcalls for tcg, as
KVM implements its own H_PROD, H_CONFER, H_CEDE, and dispatch
management. These would be nice to merge as they make qemu
behave more like KVM and PowerVM with these calls.

The last 2 patches implement some parts of the guest suspend
APIs I've been using to test Linux modifications to the pseries
(and generic kernel) suspend/hibernate code, but they are not
really useful to a Linux guest (yet) due to other missing bits.

I have some Linux code I'll try to gradually upstream to work
around the missing bits and make this suspend on QEMU "work",
which is at least useful for testing without having PowerVM.

Thanks,
Nick

Nicholas Piggin (5):
  spapr: Implement dispatch counter and prod bit on tcg
  spapr: Implement H_PROD
  spapr: Implement H_CONFER
  spapr: Implement H_JOIN
  spapr: Implement ibm,suspend-me

 hw/ppc/spapr.c  |  52 +
 hw/ppc/spapr_cpu_core.c |   5 +-
 hw/ppc/spapr_hcall.c| 126 ++--
 hw/ppc/spapr_rtas.c |  32 
 include/hw/ppc/spapr.h  |  14 +++-
 include/hw/ppc/spapr_cpu_core.h |   2 +
 target/ppc/cpu.h|   2 +
 target/ppc/translate_init.inc.c |  25 +++
 8 files changed, 251 insertions(+), 7 deletions(-)

-- 
2.20.1




[Qemu-devel] [PATCH v4 1/5] spapr: Implement dispatch counter and prod bit on tcg

2019-07-15 Thread Nicholas Piggin
Implement cpu_exec_enter/exit on ppc which calls into new methods of
the same name in PPCVirtualHypervisorClass. These are used by spapr
to implement these splpar elements, used in subsequent changes.

Signed-off-by: Nicholas Piggin 
---
 hw/ppc/spapr.c  | 25 +
 hw/ppc/spapr_cpu_core.c |  5 -
 hw/ppc/spapr_hcall.c|  5 -
 include/hw/ppc/spapr.h  |  7 +++
 include/hw/ppc/spapr_cpu_core.h |  2 ++
 target/ppc/cpu.h|  2 ++
 target/ppc/translate_init.inc.c | 25 +
 7 files changed, 65 insertions(+), 6 deletions(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 821f0d4a49..87b11e2484 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -4302,6 +4302,29 @@ PowerPCCPU *spapr_find_cpu(int vcpu_id)
 return NULL;
 }
 
+static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
+{
+SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+/* These are only called by TCG, KVM maintains dispatch state */
+
+spapr_cpu->prod = false;
+spapr_cpu->dispatch_counter++;
+assert((spapr_cpu->dispatch_counter & 1) == 0);
+if (spapr_cpu->vpa_addr) {
+CPUState *cs = CPU(cpu);
+stl_be_phys(cs->as, spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, 
spapr_cpu->dispatch_counter);
+}
+}
+
+static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
+{
+SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+spapr_cpu->dispatch_counter++;
+assert((spapr_cpu->dispatch_counter & 1) == 1);
+}
+
 static void spapr_machine_class_init(ObjectClass *oc, void *data)
 {
 MachineClass *mc = MACHINE_CLASS(oc);
@@ -4358,6 +4381,8 @@ static void spapr_machine_class_init(ObjectClass *oc, 
void *data)
 vhc->hpte_set_r = spapr_hpte_set_r;
 vhc->get_pate = spapr_get_pate;
 vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
+vhc->cpu_exec_enter = spapr_cpu_exec_enter;
+vhc->cpu_exec_exit = spapr_cpu_exec_exit;
 xic->ics_get = spapr_ics_get;
 xic->ics_resend = spapr_ics_resend;
 xic->icp_get = spapr_icp_get;
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 5621fb9a3d..fb2ed9e95d 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -261,6 +261,7 @@ error:
 static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp)
 {
 SpaprCpuCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(sc);
+SpaprCpuState *spapr_cpu;
 CPUCore *cc = CPU_CORE(sc);
 Object *obj;
 char *id;
@@ -287,7 +288,9 @@ static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int 
i, Error **errp)
 goto err;
 }
 
-cpu->machine_data = g_new0(SpaprCpuState, 1);
+spapr_cpu = g_new0(SpaprCpuState, 1);
+spapr_cpu->dispatch_counter = 1;
+cpu->machine_data = spapr_cpu;
 
 object_unref(obj);
 return cpu;
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 6808d4cda8..e615881ac4 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -874,11 +874,6 @@ unmap_out:
 #define FLAGS_DEREGISTER_DTL   0xc000ULL
 #define FLAGS_DEREGISTER_SLBSHADOW 0xe000ULL
 
-#define VPA_MIN_SIZE   640
-#define VPA_SIZE_OFFSET0x4
-#define VPA_SHARED_PROC_OFFSET 0x9
-#define VPA_SHARED_PROC_VAL0x2
-
 static target_ulong register_vpa(PowerPCCPU *cpu, target_ulong vpa)
 {
 CPUState *cs = CPU(cpu);
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 60553d32c4..5d36eec9d0 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -525,6 +525,13 @@ void spapr_register_hypercall(target_ulong opcode, 
spapr_hcall_fn fn);
 target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
  target_ulong *args);
 
+/* Virtual Processor Area structure constants */
+#define VPA_MIN_SIZE   640
+#define VPA_SIZE_OFFSET0x4
+#define VPA_SHARED_PROC_OFFSET 0x9
+#define VPA_SHARED_PROC_VAL0x2
+#define VPA_DISPATCH_COUNTER   0x100
+
 /* ibm,set-eeh-option */
 #define RTAS_EEH_DISABLE 0
 #define RTAS_EEH_ENABLE  1
diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h
index f9645a7290..3032dfa7ee 100644
--- a/include/hw/ppc/spapr_cpu_core.h
+++ b/include/hw/ppc/spapr_cpu_core.h
@@ -46,6 +46,8 @@ typedef struct SpaprCpuState {
 uint64_t vpa_addr;
 uint64_t slb_shadow_addr, slb_shadow_size;
 uint64_t dtl_addr, dtl_size;
+uint32_t dispatch_counter;
+bool prod;
 struct ICPState *icp;
 struct XiveTCTX *tctx;
 } SpaprCpuState;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index c9beba2a5c..78d6504acb 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1224,6 +1224,8 @@ struct PPCVirtualHypervisorClass {
 void (*hpte_set_r)(PPCVirtualHypervisor *vhyp, hwaddr ptex, uint64_t pte1);
 void (*get_pate)(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry);
 target_ulong 

[Qemu-devel] [PATCH v4 2/5] spapr: Implement H_PROD

2019-07-15 Thread Nicholas Piggin
H_PROD is added, and H_CEDE is modified to test the prod bit
according to PAPR.

Signed-off-by: Nicholas Piggin 
---
 hw/ppc/spapr_hcall.c | 29 +
 1 file changed, 29 insertions(+)

diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index e615881ac4..8b208ab259 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1050,14 +1050,41 @@ static target_ulong h_cede(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
 {
 CPUPPCState *env = >env;
 CPUState *cs = CPU(cpu);
+SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
 
 env->msr |= (1ULL << MSR_EE);
 hreg_compute_hflags(env);
+
+if (spapr_cpu->prod) {
+spapr_cpu->prod = false;
+return H_SUCCESS;
+}
+
 if (!cpu_has_work(cs)) {
 cs->halted = 1;
 cs->exception_index = EXCP_HLT;
 cs->exit_request = 1;
 }
+
+return H_SUCCESS;
+}
+
+static target_ulong h_prod(PowerPCCPU *cpu, SpaprMachineState *spapr,
+   target_ulong opcode, target_ulong *args)
+{
+target_long target = args[0];
+CPUState *cs;
+SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+cs = CPU(spapr_find_cpu(target));
+if (!cs) {
+return H_PARAMETER;
+}
+
+spapr_cpu->prod = true;
+cs->halted = 0;
+qemu_cpu_kick(cs);
+
 return H_SUCCESS;
 }
 
@@ -1882,6 +1909,8 @@ static void hypercall_register_types(void)
 /* hcall-splpar */
 spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
 spapr_register_hypercall(H_CEDE, h_cede);
+spapr_register_hypercall(H_PROD, h_prod);
+
 spapr_register_hypercall(H_SIGNAL_SYS_RESET, h_signal_sys_reset);
 
 /* processor register resource access h-calls */
-- 
2.20.1




Re: [Qemu-devel] [Qemu-ppc] [PULL 41/44] spapr: change default interrupt mode to 'dual'

2019-07-15 Thread David Gibson
On Mon, Jul 15, 2019 at 12:19:03PM +0200, Cédric Le Goater wrote:
> On 11/07/2019 03:26, David Gibson wrote:
> > On Wed, Jul 10, 2019 at 06:26:09PM +0200, Laurent Vivier wrote:
> >> On 29/05/2019 08:50, David Gibson wrote:
> >>> From: Cédric Le Goater 
> >>>
> >>> Now that XIVE support is complete (QEMU emulated and KVM devices),
> >>> change the pseries machine to advertise both interrupt modes: XICS
> >>> (P7/P8) and XIVE (P9).
> >>>
> >>> The machine default interrupt modes depends on the version. Current
> >>> settings are:
> >>>
> >>> pseries   default interrupt mode
> >>>
> >>> 4.1   dual
> >>> 4.0   xics
> >>> 3.1   xics
> >>> 3.0   legacy xics (different IRQ number space layout)
> >>>
> >>> Signed-off-by: Cédric Le Goater 
> >>> Message-Id: <20190522074016.10521-3-...@kaod.org>
> >>> Reviewed-by: Greg Kurz 
> >>> Signed-off-by: David Gibson 
> >>> ---
> >>>  hw/ppc/spapr.c | 3 ++-
> >>>  1 file changed, 2 insertions(+), 1 deletion(-)
> >>>
> >>> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> >>> index 39e698e9b0..4fd16b43f0 100644
> >>> --- a/hw/ppc/spapr.c
> >>> +++ b/hw/ppc/spapr.c
> >>> @@ -4352,7 +4352,7 @@ static void spapr_machine_class_init(ObjectClass 
> >>> *oc, void *data)
> >>>  smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
> >>>  smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
> >>>  spapr_caps_add_properties(smc, _abort);
> >>> -smc->irq = _irq_xics;
> >>> +smc->irq = _irq_dual;
> >>>  smc->dr_phb_enabled = true;
> >>>  }
> >>>  
> >>> @@ -4430,6 +4430,7 @@ static void 
> >>> spapr_machine_4_0_class_options(MachineClass *mc)
> >>>  spapr_machine_4_1_class_options(mc);
> >>>  compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len);
> >>>  smc->phb_placement = phb_placement_4_0;
> >>> +smc->irq = _irq_xics;
> >>>  }
> >>>  
> >>>  DEFINE_SPAPR_MACHINE(4_0, "4.0", false);
> >>>
> >>
> >> This patch breaks the '-no-reboot' parameter (I think the "dual" mode
> >> breaks the -no-reboot parameter)
> >>
> >> After grub loads the kernel and starts it, the kernel aborts:
> >>
> >> OF stdout device is: /vdevice/vty@7100
> >> Preparing to boot Linux version 4.18.0-112.el8.ppc64le
> >> (mockbu...@ppc-061.build.eng.bos.redhat.com) (gcc version 8.3.1 20190507
> >> (Red Hat 8.3.1-4) (GCC)) #1 SMP Fri Jul 5 11:21:28 UTC 2019
> >> Detected machine type: 0101
> >> command line: BOOT_IMAGE=/vmlinuz-4.18.0-112.el8.ppc64le
> >> root=/dev/mapper/rhel_ibm--p8--kvm--03--guest--02-root ro
> >> crashkernel=auto rd.lvm.lv=rhel_ibm-p8-kvm-03-guest-02/root
> >> rd.lvm.lv=rhel_ibm-p8-kvm-03-guest-02/swap
> >> Max number of cores passed to firmware: 256 (NR_CPUS = 2048)
> >> Calling ibm,client-architecture-support...[lvivier@localhost ~]$
> >>
> >> I bisected to this patch, and then after I understood the problem is
> >> with the -no-reboot parameter as the machine is reset by the CAS
> >> negotiation... and the -no-reboot prevents this reset.
> >>
> >> I don't know if it's a real problem or not.
> > 
> > Ah, bother.  I didn't think of the interaction between the CAS reboot
> > and -no-reboot.  I guess that's more reason to work out a way to do
> > the xics/xive switch without a full reset.  People were already not
> > thrilled with the extra reboots here.
> 
> QEMU builds a device tree depending on the interrupt mode negotiated 
> at CAS time. Can we dynamically add/remove nodes ?

I believe we can make essentially arbitrary change to the device tree
as part of the CAS process without a reboot.

Re-doing this is kind of awkward with the current structure, but it's
probably what we're going to want.

-- 
David Gibson| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au  | minimalist, thank you.  NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson


signature.asc
Description: PGP signature


[Qemu-devel] Fwd: virtio_scsi_ctx_check failed when detach virtio_scsi disk

2019-07-15 Thread l00284672




 Forwarded Message 
Subject:virtio_scsi_ctx_check failed when detach virtio_scsi disk
Date:   Mon, 15 Jul 2019 23:34:24 +0800
From:   l00284672 
To: 	kw...@redhat.com, be...@igalia.com, Stefan Hajnoczi 
, Paolo Bonzini 

CC: lizhen...@huawei.com



I found a problem  that virtio_scsi_ctx_check  failed when detaching 
virtio_scsi disk.  The  bt is below:


(gdb) bt
#0  0xb02e1bd0 in raise () from /lib64/libc.so.6
#1  0xb02e2f7c in abort () from /lib64/libc.so.6
#2  0xb02db124 in __assert_fail_base () from /lib64/libc.so.6
#3  0xb02db1a4 in __assert_fail () from /lib64/libc.so.6
#4  0x004eb9a8 invirtio_scsi_ctx_check (d=d@entry=0xc70d790, 
s=, s=)

    at /Images/lzg/code/710/qemu-2.8.1/hw/scsi/virtio-scsi.c:243
#5  0x004ec87c in virtio_scsi_handle_cmd_req_prepare 
(s=s@entry=0xd27a7a0, req=req@entry=0xafc4b90)

    at /Images/lzg/code/710/qemu-2.8.1/hw/scsi/virtio-scsi.c:553
#6  0x004ecc20 in virtio_scsi_handle_cmd_vq (s=0xd27a7a0, 
vq=0xd283410)

    at /Images/lzg/code/710/qemu-2.8.1/hw/scsi/virtio-scsi.c:588
#7  0x004eda20 in virtio_scsi_data_plane_handle_cmd (vdev=0x0, 
vq=0xae7a6f98)

    at /Images/lzg/code/710/qemu-2.8.1/hw/scsi/virtio-scsi-dataplane.c:57
#8  0x00877254 in aio_dispatch (ctx=0xac61010) at 
util/aio-posix.c:323
#9  0x008773ec in aio_poll (ctx=0xac61010, blocking=true) at 
util/aio-posix.c:472

#10 0x005cd7cc in iothread_run (opaque=0xac5e4b0) at iothread.c:49
#11 0x0087a8b8 in qemu_thread_start (args=0xac61360) at 
util/qemu-thread-posix.c:495
#12 0x008a04e8 in thread_entry_for_hotfix (pthread_cb=0x0) at 
uvp/hotpatch/qemu_hotpatch_helper.c:579

#13 0xb041c8bc in start_thread () from /lib64/libpthread.so.0
#14 0xb0382f8c in thread_start () from /lib64/libc.so.6

assert(blk_get_aio_context(d->conf.blk) == s->ctx) failed.

I think this patch 
(https://git.qemu.org/?p=qemu.git;a=commitdiff;h=a6f230c8d13a7ff3a0c7f1097412f44bfd9eff0b) 
introduce this problem.


commit a6f230c8d13a7ff3a0c7f1097412f44bfd9eff0b  move blockbackend back 
to main AioContext on unplug. It set the AioContext of


SCSIDevice  to the main AioContex, but s->ctx is still the iothread 
AioContext.  Is this a bug?


<>

[Qemu-devel] [PATCH v2] qapi: add dirty-bitmaps to query-named-block-nodes result

2019-07-15 Thread John Snow
From: Vladimir Sementsov-Ogievskiy 

Let's add a possibility to query dirty-bitmaps not only on root nodes.
It is useful when dealing both with snapshots and incremental backups.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
[Added deprecation and feature flag information. --js]
Signed-off-by: John Snow 
---
 block/qapi.c |  5 +
 qapi/block-core.json | 14 +-
 qemu-deprecated.texi | 12 
 3 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/block/qapi.c b/block/qapi.c
index 917435f022..15f1030264 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -79,6 +79,11 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
 info->backing_file = g_strdup(bs->backing_file);
 }
 
+if (!QLIST_EMPTY(>dirty_bitmaps)) {
+info->has_dirty_bitmaps = true;
+info->dirty_bitmaps = bdrv_query_dirty_bitmaps(bs);
+}
+
 info->detect_zeroes = bs->detect_zeroes;
 
 if (blk && blk_get_public(blk)->throttle_group_member.throttle_state) {
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 0d43d4f37c..0d67dd245c 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -360,6 +360,16 @@
 # @write_threshold: configured write threshold for the device.
 #   0 if disabled. (Since 2.3)
 #
+# @dirty-bitmaps: dirty bitmaps information (only present if node
+# has one or more dirty bitmaps) (Since 4.2)
+#
+# Features:
+# @node-dirty-bitmaps: Signals the capability to return dirty bitmap 
information
+#  per-node instead of per-drive. If this flag is present,
+#  dirty-bitmaps should not be read from the BlockInfo
+#  structure, the top-level data for query-block.
+#  (Since 4.2)
+#
 # Since: 0.14.0
 #
 ##
@@ -378,7 +388,8 @@
 '*bps_wr_max_length': 'int', '*iops_max_length': 'int',
 '*iops_rd_max_length': 'int', '*iops_wr_max_length': 'int',
 '*iops_size': 'int', '*group': 'str', 'cache': 'BlockdevCacheInfo',
-'write_threshold': 'int' } }
+'write_threshold': 'int', '*dirty-bitmaps': ['BlockDirtyInfo'] },
+  'features': [ { 'name': 'node-dirty-bitmaps' } ] }
 
 ##
 # @BlockDeviceIoStatus:
@@ -656,6 +667,7 @@
 #
 # @dirty-bitmaps: dirty bitmaps information (only present if the
 # driver has one or more dirty bitmaps) (Since 2.0)
+# Deprecated in 4.2; see BlockDirtyInfo instead.
 #
 # @io-status: @BlockDeviceIoStatus. Only present if the device
 # supports it and the VM is configured to stop on errors
diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi
index c90b08d553..bc4e5ac1d7 100644
--- a/qemu-deprecated.texi
+++ b/qemu-deprecated.texi
@@ -134,6 +134,18 @@ The ``status'' field of the ``BlockDirtyInfo'' structure, 
returned by
 the query-block command is deprecated. Two new boolean fields,
 ``recording'' and ``busy'' effectively replace it.
 
+@subsection query-block result field dirty-bitmaps (Since 4.2)
+
+The ``dirty-bitmaps`` field of the ``BlockInfo`` structure, returned by
+the query-block command is itself now deprecated. The ``dirty-bitmaps``
+field of the ``BlockDeviceInfo`` struct should be used instead, which is the
+type of the ``inserted`` field in query-block replies, as well as the
+type of array items in query-named-block-nodes.
+
+In the absence of bitmaps on either structure, management APIs may use the
+presence of the ``node-dirty-bitmaps`` feature flag on the ``BlockDeviceInfo``
+structure to know where to anticipate bitmap data when present.
+
 @subsection query-cpus (since 2.12.0)
 
 The ``query-cpus'' command is replaced by the ``query-cpus-fast'' command.
-- 
2.21.0




[Qemu-devel] [PATCH] migration: consolidate time info into populate_time_info

2019-07-15 Thread Wei Yang
Consolidate time information fill up into its function for better
readability.

Signed-off-by: Wei Yang 
---
 migration/migration.c | 40 ++--
 1 file changed, 22 insertions(+), 18 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index 47fe22d327..18ef933105 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -822,6 +822,25 @@ bool migration_is_setup_or_active(int state)
 }
 }
 
+static void populate_time_info(MigrationInfo *info, MigrationState *s)
+{
+info->has_status = true;
+info->has_setup_time = true;
+info->setup_time = s->setup_time;
+if (s->state == MIGRATION_STATUS_COMPLETED) {
+info->has_total_time = true;
+info->total_time = s->total_time;
+info->has_downtime = true;
+info->downtime = s->downtime;
+} else {
+info->has_total_time = true;
+info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) -
+   s->start_time;
+info->has_expected_downtime = true;
+info->expected_downtime = s->expected_downtime;
+}
+}
+
 static void populate_ram_info(MigrationInfo *info, MigrationState *s)
 {
 info->has_ram = true;
@@ -907,16 +926,8 @@ static void fill_source_migration_info(MigrationInfo *info)
 case MIGRATION_STATUS_DEVICE:
 case MIGRATION_STATUS_POSTCOPY_PAUSED:
 case MIGRATION_STATUS_POSTCOPY_RECOVER:
- /* TODO add some postcopy stats */
-info->has_status = true;
-info->has_total_time = true;
-info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
-- s->start_time;
-info->has_expected_downtime = true;
-info->expected_downtime = s->expected_downtime;
-info->has_setup_time = true;
-info->setup_time = s->setup_time;
-
+/* TODO add some postcopy stats */
+populate_time_info(info, s);
 populate_ram_info(info, s);
 populate_disk_info(info);
 break;
@@ -925,14 +936,7 @@ static void fill_source_migration_info(MigrationInfo *info)
 /* TODO: display COLO specific information (checkpoint info etc.) */
 break;
 case MIGRATION_STATUS_COMPLETED:
-info->has_status = true;
-info->has_total_time = true;
-info->total_time = s->total_time;
-info->has_downtime = true;
-info->downtime = s->downtime;
-info->has_setup_time = true;
-info->setup_time = s->setup_time;
-
+populate_time_info(info, s);
 populate_ram_info(info, s);
 break;
 case MIGRATION_STATUS_FAILED:
-- 
2.17.1




Re: [Qemu-devel] [PATCH] qapi: add dirty-bitmaps to query-named-block-nodes result

2019-07-15 Thread John Snow



On 6/5/19 8:46 AM, Markus Armbruster wrote:
> John Snow  writes:
> 
>> On 5/31/19 10:55 AM, Eric Blake wrote:
>>> On 5/30/19 11:26 AM, John Snow wrote:


 On 5/30/19 10:39 AM, Vladimir Sementsov-Ogievskiy wrote:
> Let's add a possibility to query dirty-bitmaps not only on root nodes.
> It is useful when dealing both with snapshots and incremental backups.
>
>>>
> +++ b/block/qapi.c
> @@ -78,6 +78,11 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend 
> *blk,
>  info->backing_file = g_strdup(bs->backing_file);
>  }
>  
> +if (!QLIST_EMPTY(>dirty_bitmaps)) {
> +info->has_dirty_bitmaps = true;
> +info->dirty_bitmaps = bdrv_query_dirty_bitmaps(bs);
> +}
> +
>  info->detect_zeroes = bs->detect_zeroes;
>  
>  if (blk && 
> blk_get_public(blk)->throttle_group_member.throttle_state) {
>

 So query-block uses bdrv_query_info, which calls bdrv_block_device_info,
 so we'll duplicate the bitmap output when doing the old-fashioned block
 query, but that's probably harmless overall.
>>>
>>> We already know that none of our existing query- interfaces are sane
>>> (either too little information, or too much).  Duplication starts to
>>> push an interface towards too much (it takes processor time to bundle up
>>> the extra JSON, especially if the other end is not going to care if it
>>> was present). I know Kevin still has somewhere on his to-do list the
>>> implementation of a saner query- command for the information we really
>>> want (about each block, without redundant information, and where we
>>> don't repeat information in a nested manner, but where we also don't
>>> omit information that would otherwise require multiple existing query-
>>> to reconstruct).
>>>

 We can continue to support the output in both places, or we could opt to
 deprecate the older interface; I think this is one of the last chances
 we'd get to do so before libvirt and wider adoption.

 I think that's probably Eric's choice.
>>>
>>> If you want to try to deprecate the old location, introspection at least
>>> works to allow libvirt to know which place to look for it on a given
>>> qemu. If you don't think deprecation is necessary, the duplication is
>>> probably tolerable for now (as ideally we'd be deprecating ALL of our
>>> not-quite-perfect query- block interfaces in favor of whatever sane
>>> interface Kevin comes up with).
>>>
>>
>> It sounds like it's probably the right move to deprecate the entire
>> legacy interface, but still... If you have 20 or 30 bitmaps on a root
>> node, you will see 40 or 60 entries.
>>
>> What's the smart way to deprecate it? We're not adding new flags or
>> showing new arguments or anything. There might not be bitmaps, so you
>> can't rely on that field being present or absent.
>>
>> Recommendations?
> 
> Kevin's "[PATCH v4 0/6] file-posix: Add dynamic-auto-read-only QAPI
> feature" adds "feature flags" to the QAPI schema language, limited to
> struct types, because that's what he needs.  They're visible in
> introspection.  I intend to complete his work, so we can tack
> "deprecated" feature flags to pretty much anything
> 
> Could that address your need?
> 

Hi Markus, digging this up again.

In brief, we are displaying bitmap info in the "wrong" part of the query
result (attached to drive instead of node) and would like to change it.
I'd like to avoid reporting bitmaps in both locations permanently, so if
we have a plan to deprecate reporting bitmaps in the old location, I
will tolerate the duplicated output temporarily.

Keeping in mind the bitmap fields are optional (so they can be absent
from both the new and old locations), what plan can we implement?

Perhaps I can add a feature flag "has-node-bitmaps" for 4.2. Then, for
the next three versions, I will report bitmaps from both locations.
Then, in 5.2+ I will remove the old location.

A client knows it can find bitmaps (if there are any) in the new
location if the feature flag is set. Otherwise, it should look in the
old location.

I think I've convinced myself that this is correct, so correct me if I
am wrong.

--js



[Qemu-devel] [PATCH v2 05/11] iotests/257: test API failures

2019-07-15 Thread John Snow
Signed-off-by: John Snow 
---
 tests/qemu-iotests/257 | 67 ++
 tests/qemu-iotests/257.out | 85 ++
 2 files changed, 152 insertions(+)

diff --git a/tests/qemu-iotests/257 b/tests/qemu-iotests/257
index aaa8f59504..53ab31c92e 100755
--- a/tests/qemu-iotests/257
+++ b/tests/qemu-iotests/257
@@ -447,10 +447,77 @@ def test_bitmap_sync(bsync_mode, msync_mode='bitmap', 
failure=None):
 compare_images(img_path, fbackup2)
 log('')
 
+def test_backup_api():
+"""
+Test malformed and prohibited invocations of the backup API.
+"""
+with iotests.FilePaths(['img', 'bsync1']) as \
+ (img_path, backup_path), \
+ iotests.VM() as vm:
+
+log("\n=== API failure tests ===\n")
+log('--- Preparing image & VM ---\n')
+drive0 = Drive(img_path, vm=vm)
+drive0.img_create(iotests.imgfmt, SIZE)
+vm.add_device("{},id=scsi0".format(iotests.get_virtio_scsi_device()))
+vm.launch()
+
+file_config = {
+'driver': 'file',
+'filename': drive0.path
+}
+
+vm.qmp_log('blockdev-add',
+   filters=[iotests.filter_qmp_testfiles],
+   node_name="drive0",
+   driver=drive0.fmt,
+   file=file_config)
+drive0.node = 'drive0'
+drive0.device = 'device0'
+vm.qmp_log("device_add", id=drive0.device,
+   drive=drive0.name, driver="scsi-hd")
+log('')
+
+target0 = Drive(backup_path, vm=vm)
+target0.create_target("backup_target", drive0.fmt, drive0.size)
+log('')
+
+vm.qmp_log("block-dirty-bitmap-add", node=drive0.name,
+   name="bitmap0", granularity=GRANULARITY)
+log('')
+
+log('-- Testing invalid QMP commands --\n')
+
+error_cases = {
+'incremental': {
+None:['on-success', 'always', 'never', None],
+'bitmap404': ['on-success', 'always', 'never', None],
+'bitmap0':   ['always', 'never']
+},
+'bitmap': {
+None:['on-success', 'always', 'never', None],
+'bitmap404': ['on-success', 'always', 'never', None],
+'bitmap0':   [None],
+},
+}
+
+# Dicts, as always, are not stably-ordered prior to 3.7, so use tuples:
+for sync_mode in ('incremental', 'bitmap'):
+log("-- Sync mode {:s} tests --\n".format(sync_mode))
+for bitmap in (None, 'bitmap404', 'bitmap0'):
+for policy in error_cases[sync_mode][bitmap]:
+blockdev_backup(drive0.vm, drive0.name, "backup_target",
+sync_mode, job_id='api_job',
+bitmap=bitmap, bitmap_mode=policy)
+log('')
+
+
 def main():
 for bsync_mode in ("never", "on-success", "always"):
 for failure in ("simulated", "intermediate", None):
 test_bitmap_sync(bsync_mode, "bitmap", failure)
 
+test_backup_api()
+
 if __name__ == '__main__':
 iotests.script_main(main, supported_fmts=['qcow2'])
diff --git a/tests/qemu-iotests/257.out b/tests/qemu-iotests/257.out
index 0abc96acd3..43f2e0f9c9 100644
--- a/tests/qemu-iotests/257.out
+++ b/tests/qemu-iotests/257.out
@@ -2245,3 +2245,88 @@ qemu_img compare "TEST_DIR/PID-bsync1" 
"TEST_DIR/PID-fbackup1" ==> Identical, OK
 qemu_img compare "TEST_DIR/PID-bsync2" "TEST_DIR/PID-fbackup2" ==> Identical, 
OK!
 qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fbackup2" ==> Identical, OK!
 
+
+=== API failure tests ===
+
+--- Preparing image & VM ---
+
+{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": 
{"driver": "file", "filename": "TEST_DIR/PID-img"}, "node-name": "drive0"}}
+{"return": {}}
+{"execute": "device_add", "arguments": {"drive": "drive0", "driver": 
"scsi-hd", "id": "device0"}}
+{"return": {}}
+
+{}
+{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}}
+{"return": {}}
+{}
+{}
+{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}}
+{"return": {}}
+{}
+
+{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, 
"name": "bitmap0", "node": "drive0"}}
+{"return": {}}
+
+-- Testing invalid QMP commands --
+
+-- Sync mode incremental tests --
+
+{"execute": "blockdev-backup", "arguments": {"bitmap-mode": "on-success", 
"device": "drive0", "job-id": "api_job", "sync": "incremental", "target": 
"backup_target"}}
+{"error": {"class": "GenericError", "desc": "must provide a valid bitmap name 
for 'incremental' sync mode"}}
+
+{"execute": "blockdev-backup", "arguments": {"bitmap-mode": "always", 
"device": "drive0", "job-id": "api_job", "sync": "incremental", "target": 
"backup_target"}}
+{"error": {"class": "GenericError", "desc": "must provide a valid bitmap name 
for 'incremental' sync mode"}}
+
+{"execute": 

[Qemu-devel] [PATCH v2 06/11] block/backup: improve sync=bitmap work estimates

2019-07-15 Thread John Snow
When making backups based on bitmaps, the work estimate can be more
accurate. Update iotests to reflect the new strategy.

TOP work estimates are broken, but do not get worse with this commit.
That issue is addressed in the following commits instead.

Signed-off-by: John Snow 
---
 block/backup.c |  8 +++-
 tests/qemu-iotests/256.out |  4 ++--
 tests/qemu-iotests/257.out | 36 ++--
 3 files changed, 23 insertions(+), 25 deletions(-)

diff --git a/block/backup.c b/block/backup.c
index a64b768e24..22fafbb80f 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -449,9 +449,8 @@ static void 
backup_incremental_init_copy_bitmap(BackupBlockJob *job)
 NULL, true);
 assert(ret);
 
-/* TODO job_progress_set_remaining() would make more sense */
-job_progress_update(>common.job,
-job->len - bdrv_get_dirty_count(job->copy_bitmap));
+job_progress_set_remaining(>common.job,
+   bdrv_get_dirty_count(job->copy_bitmap));
 }
 
 static int coroutine_fn backup_run(Job *job, Error **errp)
@@ -463,12 +462,11 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
 QLIST_INIT(>inflight_reqs);
 qemu_co_rwlock_init(>flush_rwlock);
 
-job_progress_set_remaining(job, s->len);
-
 if (s->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
 backup_incremental_init_copy_bitmap(s);
 } else {
 bdrv_set_dirty_bitmap(s->copy_bitmap, 0, s->len);
+job_progress_set_remaining(job, s->len);
 }
 
 s->before_write.notify = backup_before_write_notify;
diff --git a/tests/qemu-iotests/256.out b/tests/qemu-iotests/256.out
index eec38614ec..f18ecb0f91 100644
--- a/tests/qemu-iotests/256.out
+++ b/tests/qemu-iotests/256.out
@@ -113,7 +113,7 @@
 {
   "return": {}
 }
-{"data": {"device": "j2", "len": 67108864, "offset": 67108864, "speed": 0, 
"type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": 
{"microseconds": "USECS", "seconds": "SECS"}}
-{"data": {"device": "j3", "len": 67108864, "offset": 67108864, "speed": 0, 
"type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": 
{"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"device": "j2", "len": 0, "offset": 0, "speed": 0, "type": 
"backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": 
"USECS", "seconds": "SECS"}}
+{"data": {"device": "j3", "len": 0, "offset": 0, "speed": 0, "type": 
"backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": 
"USECS", "seconds": "SECS"}}
 
 --- Done ---
diff --git a/tests/qemu-iotests/257.out b/tests/qemu-iotests/257.out
index 43f2e0f9c9..811b1b11f1 100644
--- a/tests/qemu-iotests/257.out
+++ b/tests/qemu-iotests/257.out
@@ -150,7 +150,7 @@ expecting 7 dirty sectors; have 7. OK!
 {"execute": "job-cancel", "arguments": {"id": "backup_1"}}
 {"return": {}}
 {"data": {"id": "backup_1", "type": "backup"}, "event": "BLOCK_JOB_PENDING", 
"timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
-{"data": {"device": "backup_1", "len": 67108864, "offset": 67108864, "speed": 
0, "type": "backup"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": 
{"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"device": "backup_1", "len": 393216, "offset": 393216, "speed": 0, 
"type": "backup"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": 
{"microseconds": "USECS", "seconds": "SECS"}}
 {
   "bitmaps": {
 "device0": [
@@ -228,7 +228,7 @@ expecting 15 dirty sectors; have 15. OK!
 {"execute": "job-finalize", "arguments": {"id": "backup_2"}}
 {"return": {}}
 {"data": {"id": "backup_2", "type": "backup"}, "event": "BLOCK_JOB_PENDING", 
"timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
-{"data": {"device": "backup_2", "len": 67108864, "offset": 67108864, "speed": 
0, "type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": 
{"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"device": "backup_2", "len": 983040, "offset": 983040, "speed": 0, 
"type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": 
{"microseconds": "USECS", "seconds": "SECS"}}
 {
   "bitmaps": {
 "device0": [
@@ -367,7 +367,7 @@ expecting 6 dirty sectors; have 6. OK!
 {"execute": "blockdev-backup", "arguments": {"auto-finalize": false, "bitmap": 
"bitmap0", "bitmap-mode": "never", "device": "drive0", "job-id": "backup_1", 
"sync": "bitmap", "target": "backup_target_1"}}
 {"return": {}}
 {"data": {"action": "report", "device": "backup_1", "operation": "read"}, 
"event": "BLOCK_JOB_ERROR", "timestamp": {"microseconds": "USECS", "seconds": 
"SECS"}}
-{"data": {"device": "backup_1", "error": "Input/output error", "len": 
67108864, "offset": 66781184, "speed": 0, "type": "backup"}, "event": 
"BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": 
"SECS"}}
+{"data": {"device": "backup_1", "error": "Input/output error", "len": 393216, 
"offset": 65536, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_COMPLETED", 

[Qemu-devel] [PATCH v2 11/11] iotests/257: test traditional sync modes

2019-07-15 Thread John Snow
Signed-off-by: John Snow 
---
 tests/qemu-iotests/257 |   41 +-
 tests/qemu-iotests/257.out | 3089 
 2 files changed, 3128 insertions(+), 2 deletions(-)

diff --git a/tests/qemu-iotests/257 b/tests/qemu-iotests/257
index 53ab31c92e..c2a72c577a 100755
--- a/tests/qemu-iotests/257
+++ b/tests/qemu-iotests/257
@@ -283,6 +283,12 @@ def test_bitmap_sync(bsync_mode, msync_mode='bitmap', 
failure=None):
   Bitmaps are always synchronized, regardless of failure.
   (Partial images must be kept.)
 
+:param msync_mode: The mirror sync mode to use for the first backup.
+   Can be any one of:
+- bitmap: Backups based on bitmap manifest.
+- full:   Full backups.
+- top:Full backups of the top layer only.
+
 :param failure: Is the (optional) failure mode, and can be any of:
 - None: No failure. Test the normative path. Default.
 - simulated:Cancel the job right before it completes.
@@ -393,7 +399,7 @@ def test_bitmap_sync(bsync_mode, msync_mode='bitmap', 
failure=None):
 # group 1 gets cleared first, then group two gets written.
 if ((bsync_mode == 'on-success' and not failure) or
 (bsync_mode == 'always')):
-ebitmap.clear_group(1)
+ebitmap.clear()
 ebitmap.dirty_group(2)
 
 vm.run_job(job, auto_dismiss=True, auto_finalize=False,
@@ -404,8 +410,19 @@ def test_bitmap_sync(bsync_mode, msync_mode='bitmap', 
failure=None):
 log('')
 
 if bsync_mode == 'always' and failure == 'intermediate':
+# TOP treats anything allocated as dirty, expect to see:
+if msync_mode == 'top':
+ebitmap.dirty_group(0)
+
 # We manage to copy one sector (one bit) before the error.
 ebitmap.clear_bit(ebitmap.first_bit)
+
+# Full returns all bits set except what was copied/skipped
+if msync_mode == 'full':
+fail_bit = ebitmap.first_bit
+ebitmap.clear()
+ebitmap.dirty_bits(range(fail_bit, SIZE // GRANULARITY))
+
 ebitmap.compare(get_bitmap(bitmaps, drive0.device, 'bitmap0'))
 
 # 2 - Writes and Reference Backup
@@ -499,10 +516,25 @@ def test_backup_api():
 'bitmap404': ['on-success', 'always', 'never', None],
 'bitmap0':   [None],
 },
+'full': {
+None:['on-success', 'always', 'never'],
+'bitmap404': ['on-success', 'always', 'never', None],
+'bitmap0':   ['never', None],
+},
+'top': {
+None:['on-success', 'always', 'never'],
+'bitmap404': ['on-success', 'always', 'never', None],
+'bitmap0':   ['never', None],
+},
+'none': {
+None:['on-success', 'always', 'never'],
+'bitmap404': ['on-success', 'always', 'never', None],
+'bitmap0':   ['on-success', 'always', 'never', None],
+}
 }
 
 # Dicts, as always, are not stably-ordered prior to 3.7, so use tuples:
-for sync_mode in ('incremental', 'bitmap'):
+for sync_mode in ('incremental', 'bitmap', 'full', 'top', 'none'):
 log("-- Sync mode {:s} tests --\n".format(sync_mode))
 for bitmap in (None, 'bitmap404', 'bitmap0'):
 for policy in error_cases[sync_mode][bitmap]:
@@ -517,6 +549,11 @@ def main():
 for failure in ("simulated", "intermediate", None):
 test_bitmap_sync(bsync_mode, "bitmap", failure)
 
+for sync_mode in ('full', 'top'):
+for bsync_mode in ('on-success', 'always'):
+for failure in ('simulated', 'intermediate', None):
+test_bitmap_sync(bsync_mode, sync_mode, failure)
+
 test_backup_api()
 
 if __name__ == '__main__':
diff --git a/tests/qemu-iotests/257.out b/tests/qemu-iotests/257.out
index 811b1b11f1..abcd9044a1 100644
--- a/tests/qemu-iotests/257.out
+++ b/tests/qemu-iotests/257.out
@@ -2246,6 +2246,3002 @@ qemu_img compare "TEST_DIR/PID-bsync2" 
"TEST_DIR/PID-fbackup2" ==> Identical, OK
 qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fbackup2" ==> Identical, OK!
 
 
+=== Mode full; Bitmap Sync on-success with simulated failure ===
+
+--- Preparing image & VM ---
+
+{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": 
{"driver": "file", "filename": "TEST_DIR/PID-img"}, "node-name": "drive0"}}
+{"return": {}}
+{"execute": "device_add", "arguments": {"drive": "drive0", "driver": 
"scsi-hd", "id": "device0", "share-rw": true}}
+{"return": {}}
+
+--- Write #0 ---
+
+write -P0x49 0x000 0x1
+{"return": ""}
+write -P0x6c 0x010 0x1
+{"return": ""}
+write -P0x6f 0x200 0x1
+{"return": ""}
+write -P0x76 0x3ff 0x1
+{"return": 

[Qemu-devel] [PATCH v2 08/11] block/backup: add backup_is_cluster_allocated

2019-07-15 Thread John Snow
Modify the existing bdrv_is_unallocated_range to utilize the pnum return
from bdrv_is_allocated; optionally returning a full number of clusters
that share the same allocation status.

This will be used to carefully toggle bits in the bitmap for sync=top
initialization in the following commits.

Signed-off-by: John Snow 
---
 block/backup.c | 62 +++---
 1 file changed, 44 insertions(+), 18 deletions(-)

diff --git a/block/backup.c b/block/backup.c
index c88a70fe10..b407d57954 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -185,6 +185,48 @@ static int coroutine_fn 
backup_cow_with_offload(BackupBlockJob *job,
 return nbytes;
 }
 
+/*
+ * Check if the cluster starting at offset is allocated or not.
+ * return via pnum the number of contiguous clusters sharing this allocation.
+ */
+static int backup_is_cluster_allocated(BackupBlockJob *s, int64_t offset,
+   int64_t *pnum)
+{
+BlockDriverState *bs = blk_bs(s->common.blk);
+int64_t count, total_count = 0;
+int64_t bytes = s->len - offset;
+int ret;
+
+assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
+
+while (true) {
+ret = bdrv_is_allocated(bs, offset, bytes, );
+if (ret < 0) {
+return ret;
+}
+
+total_count += count;
+
+if (ret || count == 0) {
+/*
+ * ret: partial segment(s) are considered allocated.
+ * otherwise: unallocated tail is treated as an entire segment.
+ */
+*pnum = DIV_ROUND_UP(total_count, s->cluster_size);
+return ret;
+}
+
+/* Unallocated segment(s) with uncertain following segment(s) */
+if (total_count >= s->cluster_size) {
+*pnum = total_count / s->cluster_size;
+return 0;
+}
+
+offset += count;
+bytes -= count;
+}
+}
+
 static int coroutine_fn backup_do_cow(BackupBlockJob *job,
   int64_t offset, uint64_t bytes,
   bool *error_is_read,
@@ -388,34 +430,18 @@ static bool coroutine_fn yield_and_check(BackupBlockJob 
*job)
 return false;
 }
 
-static bool bdrv_is_unallocated_range(BlockDriverState *bs,
-  int64_t offset, int64_t bytes)
-{
-int64_t end = offset + bytes;
-
-while (offset < end && !bdrv_is_allocated(bs, offset, bytes, )) {
-if (bytes == 0) {
-return true;
-}
-offset += bytes;
-bytes = end - offset;
-}
-
-return offset >= end;
-}
-
 static int coroutine_fn backup_loop(BackupBlockJob *job)
 {
 bool error_is_read;
 int64_t offset;
 BdrvDirtyBitmapIter *bdbi;
-BlockDriverState *bs = blk_bs(job->common.blk);
 int ret = 0;
+int64_t dummy;
 
 bdbi = bdrv_dirty_iter_new(job->copy_bitmap);
 while ((offset = bdrv_dirty_iter_next(bdbi)) != -1) {
 if (job->sync_mode == MIRROR_SYNC_MODE_TOP &&
-bdrv_is_unallocated_range(bs, offset, job->cluster_size))
+!backup_is_cluster_allocated(job, offset, ))
 {
 bdrv_reset_dirty_bitmap(job->copy_bitmap, offset,
 job->cluster_size);
-- 
2.21.0




[Qemu-devel] [PATCH v2 07/11] block/backup: centralize copy_bitmap initialization

2019-07-15 Thread John Snow
Just a few housekeeping changes that keeps the following commit easier
to read; perform the initial copy_bitmap initialization in one place.

Signed-off-by: John Snow 
---
 block/backup.c | 29 +++--
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/block/backup.c b/block/backup.c
index 22fafbb80f..c88a70fe10 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -441,16 +441,22 @@ static int coroutine_fn backup_loop(BackupBlockJob *job)
 return ret;
 }
 
-/* init copy_bitmap from sync_bitmap */
-static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
+static void backup_init_copy_bitmap(BackupBlockJob *job)
 {
-bool ret = bdrv_dirty_bitmap_merge_internal(job->copy_bitmap,
-job->sync_bitmap,
-NULL, true);
-assert(ret);
+bool ret;
+uint64_t estimate;
 
-job_progress_set_remaining(>common.job,
-   bdrv_get_dirty_count(job->copy_bitmap));
+if (job->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
+ret = bdrv_dirty_bitmap_merge_internal(job->copy_bitmap,
+   job->sync_bitmap,
+   NULL, true);
+assert(ret);
+} else {
+bdrv_set_dirty_bitmap(job->copy_bitmap, 0, job->len);
+}
+
+estimate = bdrv_get_dirty_count(job->copy_bitmap);
+job_progress_set_remaining(>common.job, estimate);
 }
 
 static int coroutine_fn backup_run(Job *job, Error **errp)
@@ -462,12 +468,7 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
 QLIST_INIT(>inflight_reqs);
 qemu_co_rwlock_init(>flush_rwlock);
 
-if (s->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
-backup_incremental_init_copy_bitmap(s);
-} else {
-bdrv_set_dirty_bitmap(s->copy_bitmap, 0, s->len);
-job_progress_set_remaining(job, s->len);
-}
+backup_init_copy_bitmap(s);
 
 s->before_write.notify = backup_before_write_notify;
 bdrv_add_before_write_notifier(bs, >before_write);
-- 
2.21.0




[Qemu-devel] [PATCH v2 03/11] iotests/257: Refactor backup helpers

2019-07-15 Thread John Snow
This test needs support for non-bitmap backups and missing or
unspecified bitmap sync modes, so rewrite the helpers to be a little
more generic.

Signed-off-by: John Snow 
---
 tests/qemu-iotests/257 |  56 ++-
 tests/qemu-iotests/257.out | 192 ++---
 2 files changed, 128 insertions(+), 120 deletions(-)

diff --git a/tests/qemu-iotests/257 b/tests/qemu-iotests/257
index bc66ea03b2..aaa8f59504 100755
--- a/tests/qemu-iotests/257
+++ b/tests/qemu-iotests/257
@@ -207,31 +207,37 @@ def get_bitmap(bitmaps, drivename, name, recording=None):
 return bitmap
 return None
 
+def blockdev_backup(vm, device, target, sync, **kwargs):
+# Strip any arguments explicitly nulled by the caller:
+kwargs = {key: val for key, val in kwargs.items() if val is not None}
+result = vm.qmp_log('blockdev-backup',
+device=device,
+target=target,
+sync=sync,
+**kwargs)
+return result
+
+def blockdev_backup_mktarget(drive, target_id, filepath, sync, **kwargs):
+target_drive = Drive(filepath, vm=drive.vm)
+target_drive.create_target(target_id, drive.fmt, drive.size)
+blockdev_backup(drive.vm, drive.name, target_id, sync, **kwargs)
+
 def reference_backup(drive, n, filepath):
 log("--- Reference Backup #{:d} ---\n".format(n))
 target_id = "ref_target_{:d}".format(n)
 job_id = "ref_backup_{:d}".format(n)
-target_drive = Drive(filepath, vm=drive.vm)
-
-target_drive.create_target(target_id, drive.fmt, drive.size)
-drive.vm.qmp_log("blockdev-backup",
- job_id=job_id, device=drive.name,
- target=target_id, sync="full")
+blockdev_backup_mktarget(drive, target_id, filepath, "full",
+ job_id=job_id)
 drive.vm.run_job(job_id, auto_dismiss=True)
 log('')
 
-def bitmap_backup(drive, n, filepath, bitmap, bitmap_mode):
-log("--- Bitmap Backup #{:d} ---\n".format(n))
-target_id = "bitmap_target_{:d}".format(n)
-job_id = "bitmap_backup_{:d}".format(n)
-target_drive = Drive(filepath, vm=drive.vm)
-
-target_drive.create_target(target_id, drive.fmt, drive.size)
-drive.vm.qmp_log("blockdev-backup", job_id=job_id, device=drive.name,
- target=target_id, sync="bitmap",
- bitmap_mode=bitmap_mode,
- bitmap=bitmap,
- auto_finalize=False)
+def backup(drive, n, filepath, sync, **kwargs):
+log("--- Test Backup #{:d} ---\n".format(n))
+target_id = "backup_target_{:d}".format(n)
+job_id = "backup_{:d}".format(n)
+kwargs.setdefault('auto-finalize', False)
+blockdev_backup_mktarget(drive, target_id, filepath, sync,
+ job_id=job_id, **kwargs)
 return job_id
 
 def perform_writes(drive, n):
@@ -263,7 +269,7 @@ def compare_images(image, reference, baseimg=None, 
expected_match=True):
 "OK!" if ret == expected_ret else "ERROR!"),
 filters=[iotests.filter_testfiles])
 
-def test_bitmap_sync(bsync_mode, failure=None):
+def test_bitmap_sync(bsync_mode, msync_mode='bitmap', failure=None):
 """
 Test bitmap backup routines.
 
@@ -291,7 +297,7 @@ def test_bitmap_sync(bsync_mode, failure=None):
  fbackup0, fbackup1, fbackup2), \
  iotests.VM() as vm:
 
-mode = "Bitmap Sync Mode {:s}".format(bsync_mode)
+mode = "Mode {:s}; Bitmap Sync {:s}".format(msync_mode, bsync_mode)
 preposition = "with" if failure else "without"
 cond = "{:s} {:s}".format(preposition,
   "{:s} failure".format(failure) if failure
@@ -362,12 +368,13 @@ def test_bitmap_sync(bsync_mode, failure=None):
 ebitmap.compare(bitmap)
 reference_backup(drive0, 1, fbackup1)
 
-# 1 - Bitmap Backup (Optional induced failure)
+# 1 - Test Backup (w/ Optional induced failure)
 if failure == 'intermediate':
 # Activate blkdebug induced failure for second-to-next read
 log(vm.hmp_qemu_io(drive0.name, 'flush'))
 log('')
-job = bitmap_backup(drive0, 1, bsync1, "bitmap0", bsync_mode)
+job = backup(drive0, 1, bsync1, msync_mode,
+ bitmap="bitmap0", bitmap_mode=bsync_mode)
 
 def _callback():
 """Issue writes while the job is open to test bitmap divergence."""
@@ -408,7 +415,8 @@ def test_bitmap_sync(bsync_mode, failure=None):
 reference_backup(drive0, 2, fbackup2)
 
 # 2 - Bitmap Backup (In failure modes, this is a recovery.)
-job = bitmap_backup(drive0, 2, bsync2, "bitmap0", bsync_mode)
+job = backup(drive0, 2, bsync2, "bitmap",
+ bitmap="bitmap0", bitmap_mode=bsync_mode)
 vm.run_job(job, auto_dismiss=True, auto_finalize=False)
 bitmaps = query_bitmaps(vm)
 

[Qemu-devel] [PATCH v2 04/11] block/backup: hoist bitmap check into QMP interface

2019-07-15 Thread John Snow
This is nicer to do in the unified QMP interface that we have now,
because it lets us use the right terminology back at the user.

Signed-off-by: John Snow 
Reviewed-by: Max Reitz 
---
 block/backup.c | 13 -
 blockdev.c | 10 ++
 2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/block/backup.c b/block/backup.c
index e2729cf6fa..a64b768e24 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -566,6 +566,10 @@ BlockJob *backup_job_create(const char *job_id, 
BlockDriverState *bs,
 assert(bs);
 assert(target);
 
+/* QMP interface protects us from these cases */
+assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL);
+assert(sync_bitmap || sync_mode != MIRROR_SYNC_MODE_BITMAP);
+
 if (bs == target) {
 error_setg(errp, "Source and target cannot be the same");
 return NULL;
@@ -597,16 +601,7 @@ BlockJob *backup_job_create(const char *job_id, 
BlockDriverState *bs,
 return NULL;
 }
 
-/* QMP interface should have handled translating this to bitmap mode */
-assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL);
-
 if (sync_mode == MIRROR_SYNC_MODE_BITMAP) {
-if (!sync_bitmap) {
-error_setg(errp, "must provide a valid bitmap name for "
-   "'%s' sync mode", MirrorSyncMode_str(sync_mode));
-return NULL;
-}
-
 /* If we need to write to this bitmap, check that we can: */
 if (bitmap_mode != BITMAP_SYNC_MODE_NEVER &&
 bdrv_dirty_bitmap_check(sync_bitmap, BDRV_BITMAP_DEFAULT, errp)) {
diff --git a/blockdev.c b/blockdev.c
index 020d566c1b..3c76c85cb5 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3527,6 +3527,16 @@ static BlockJob *do_backup_common(BackupCommon *backup,
 return NULL;
 }
 
+if ((backup->sync == MIRROR_SYNC_MODE_BITMAP) ||
+(backup->sync == MIRROR_SYNC_MODE_INCREMENTAL)) {
+/* done before desugaring 'incremental' to print the right message */
+if (!backup->has_bitmap) {
+error_setg(errp, "must provide a valid bitmap name for "
+   "'%s' sync mode", MirrorSyncMode_str(backup->sync));
+return NULL;
+}
+}
+
 if (backup->sync == MIRROR_SYNC_MODE_INCREMENTAL) {
 if (backup->has_bitmap_mode &&
 backup->bitmap_mode != BITMAP_SYNC_MODE_ON_SUCCESS) {
-- 
2.21.0




[Qemu-devel] [PATCH v2 09/11] block/backup: teach TOP to never copy unallocated regions

2019-07-15 Thread John Snow
Presently, If sync=TOP is selected, we mark the entire bitmap as dirty.
In the write notifier handler, we dutifully copy out such regions.

Fix this in three parts:

1. Mark the bitmap as being initialized before the first yield.
2. After the first yield but before the backup loop, interrogate the
allocation status asynchronously and initialize the bitmap.
3. Teach the write notifier to interrogate allocation status if it is
invoked during bitmap initialization.

As an effect of this patch, the job progress for TOP backups
now behaves like this:

- total progress starts at bdrv_length.
- As allocation status is interrogated, total progress decreases.
- As blocks are copied, current progress increases.

Taken together, the floor and ceiling move to meet each other.

Signed-off-by: John Snow 
---
 block/backup.c | 78 --
 block/trace-events |  1 +
 2 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/block/backup.c b/block/backup.c
index b407d57954..e28fd23f6a 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -58,6 +58,7 @@ typedef struct BackupBlockJob {
 int64_t copy_range_size;
 
 bool serialize_target_writes;
+bool initializing_bitmap;
 } BackupBlockJob;
 
 static const BlockJobDriver backup_job_driver;
@@ -227,6 +228,35 @@ static int backup_is_cluster_allocated(BackupBlockJob *s, 
int64_t offset,
 }
 }
 
+/**
+ * Reset bits in copy_bitmap starting at offset if they represent unallocated
+ * data in the image. May reset subsequent contiguous bits.
+ * @return 0 when the cluster at @offset was unallocated,
+ * 1 otherwise, and -ret on error.
+ */
+static int64_t backup_bitmap_reset_unallocated(BackupBlockJob *s,
+   int64_t offset, int64_t *count)
+{
+int ret;
+int64_t clusters, bytes, estimate;
+
+ret = backup_is_cluster_allocated(s, offset, );
+if (ret < 0) {
+return ret;
+}
+
+bytes = clusters * s->cluster_size;
+
+if (!ret) {
+bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes);
+estimate = bdrv_get_dirty_count(s->copy_bitmap);
+job_progress_set_remaining(>common.job, estimate);
+}
+
+*count = bytes;
+return ret;
+}
+
 static int coroutine_fn backup_do_cow(BackupBlockJob *job,
   int64_t offset, uint64_t bytes,
   bool *error_is_read,
@@ -236,6 +266,7 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
 int ret = 0;
 int64_t start, end; /* bytes */
 void *bounce_buffer = NULL;
+int64_t skip_bytes;
 
 qemu_co_rwlock_rdlock(>flush_rwlock);
 
@@ -254,6 +285,15 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
 continue; /* already copied */
 }
 
+if (job->initializing_bitmap) {
+ret = backup_bitmap_reset_unallocated(job, start, _bytes);
+if (ret == 0) {
+trace_backup_do_cow_skip_range(job, start, skip_bytes);
+start += skip_bytes;
+continue;
+}
+}
+
 trace_backup_do_cow_process(job, start);
 
 if (job->use_copy_range) {
@@ -436,18 +476,9 @@ static int coroutine_fn backup_loop(BackupBlockJob *job)
 int64_t offset;
 BdrvDirtyBitmapIter *bdbi;
 int ret = 0;
-int64_t dummy;
 
 bdbi = bdrv_dirty_iter_new(job->copy_bitmap);
 while ((offset = bdrv_dirty_iter_next(bdbi)) != -1) {
-if (job->sync_mode == MIRROR_SYNC_MODE_TOP &&
-!backup_is_cluster_allocated(job, offset, ))
-{
-bdrv_reset_dirty_bitmap(job->copy_bitmap, offset,
-job->cluster_size);
-continue;
-}
-
 do {
 if (yield_and_check(job)) {
 goto out;
@@ -478,6 +509,13 @@ static void backup_init_copy_bitmap(BackupBlockJob *job)
NULL, true);
 assert(ret);
 } else {
+if (job->sync_mode == MIRROR_SYNC_MODE_TOP) {
+/*
+ * We can't hog the coroutine to initialize this thoroughly.
+ * Set a flag and resume work when we are able to yield safely.
+ */
+job->initializing_bitmap = true;
+}
 bdrv_set_dirty_bitmap(job->copy_bitmap, 0, job->len);
 }
 
@@ -499,6 +537,26 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
 s->before_write.notify = backup_before_write_notify;
 bdrv_add_before_write_notifier(bs, >before_write);
 
+if (s->sync_mode == MIRROR_SYNC_MODE_TOP) {
+int64_t offset = 0;
+int64_t count;
+
+for (offset = 0; offset < s->len; ) {
+if (yield_and_check(s)) {
+ret = -ECANCELED;
+goto out;
+}
+
+ret = backup_bitmap_reset_unallocated(s, offset, );
+if (ret < 0) {
+goto out;
+  

[Qemu-devel] [PATCH v2 01/11] iotests/257: add Pattern class

2019-07-15 Thread John Snow
Just kidding, this is easier to manage with a full class instead of a
namedtuple.

Signed-off-by: John Snow 
---
 tests/qemu-iotests/257 | 58 +++---
 1 file changed, 32 insertions(+), 26 deletions(-)

diff --git a/tests/qemu-iotests/257 b/tests/qemu-iotests/257
index 3952683749..02f9ae0649 100755
--- a/tests/qemu-iotests/257
+++ b/tests/qemu-iotests/257
@@ -19,7 +19,6 @@
 #
 # owner=js...@redhat.com
 
-from collections import namedtuple
 import math
 import os
 
@@ -29,10 +28,18 @@ from iotests import log, qemu_img
 SIZE = 64 * 1024 * 1024
 GRANULARITY = 64 * 1024
 
-Pattern = namedtuple('Pattern', ['byte', 'offset', 'size'])
-def mkpattern(byte, offset, size=GRANULARITY):
-"""Constructor for Pattern() with default size"""
-return Pattern(byte, offset, size)
+
+class Pattern:
+def __init__(self, byte, offset, size=GRANULARITY):
+self.byte = byte
+self.offset = offset
+self.size = size
+
+def bits(self, granularity):
+lower = self.offset // granularity
+upper = (self.offset + self.size - 1) // granularity
+return set(range(lower, upper + 1))
+
 
 class PatternGroup:
 """Grouping of Pattern objects. Initialize with an iterable of Patterns."""
@@ -43,40 +50,39 @@ class PatternGroup:
 """Calculate the unique bits dirtied by this pattern grouping"""
 res = set()
 for pattern in self.patterns:
-lower = pattern.offset // granularity
-upper = (pattern.offset + pattern.size - 1) // granularity
-res = res | set(range(lower, upper + 1))
+res |= pattern.bits(granularity)
 return res
 
+
 GROUPS = [
 PatternGroup([
 # Batch 0: 4 clusters
-mkpattern('0x49', 0x000),
-mkpattern('0x6c', 0x010),   # 1M
-mkpattern('0x6f', 0x200),   # 32M
-mkpattern('0x76', 0x3ff)]), # 64M - 64K
+Pattern('0x49', 0x000),
+Pattern('0x6c', 0x010),   # 1M
+Pattern('0x6f', 0x200),   # 32M
+Pattern('0x76', 0x3ff)]), # 64M - 64K
 PatternGroup([
 # Batch 1: 6 clusters (3 new)
-mkpattern('0x65', 0x000),   # Full overwrite
-mkpattern('0x77', 0x00f8000),   # Partial-left (1M-32K)
-mkpattern('0x72', 0x2008000),   # Partial-right (32M+32K)
-mkpattern('0x69', 0x3fe)]), # Adjacent-left (64M - 128K)
+Pattern('0x65', 0x000),   # Full overwrite
+Pattern('0x77', 0x00f8000),   # Partial-left (1M-32K)
+Pattern('0x72', 0x2008000),   # Partial-right (32M+32K)
+Pattern('0x69', 0x3fe)]), # Adjacent-left (64M - 128K)
 PatternGroup([
 # Batch 2: 7 clusters (3 new)
-mkpattern('0x74', 0x001),   # Adjacent-right
-mkpattern('0x69', 0x00e8000),   # Partial-left  (1M-96K)
-mkpattern('0x6e', 0x2018000),   # Partial-right (32M+96K)
-mkpattern('0x67', 0x3fe,
-  2*GRANULARITY)]), # Overwrite [(64M-128K)-64M)
+Pattern('0x74', 0x001),   # Adjacent-right
+Pattern('0x69', 0x00e8000),   # Partial-left  (1M-96K)
+Pattern('0x6e', 0x2018000),   # Partial-right (32M+96K)
+Pattern('0x67', 0x3fe,
+2*GRANULARITY)]), # Overwrite [(64M-128K)-64M)
 PatternGroup([
 # Batch 3: 8 clusters (5 new)
 # Carefully chosen such that nothing re-dirties the one cluster
 # that copies out successfully before failure in Group #1.
-mkpattern('0xaa', 0x001,
-  3*GRANULARITY),   # Overwrite and 2x Adjacent-right
-mkpattern('0xbb', 0x00d8000),   # Partial-left (1M-160K)
-mkpattern('0xcc', 0x2028000),   # Partial-right (32M+160K)
-mkpattern('0xdd', 0x3fc)]), # New; leaving a gap to the right
+Pattern('0xaa', 0x001,
+3*GRANULARITY),   # Overwrite and 2x Adjacent-right
+Pattern('0xbb', 0x00d8000),   # Partial-left (1M-160K)
+Pattern('0xcc', 0x2028000),   # Partial-right (32M+160K)
+Pattern('0xdd', 0x3fc)]), # New; leaving a gap to the right
 ]
 
 class Drive:
-- 
2.21.0




[Qemu-devel] [PATCH v2 00/11] bitmaps: allow bitmaps to be used with full and top

2019-07-15 Thread John Snow
Based-on: https://github.com/jnsnow/qemu/tree/bitmaps

This follows the previous series which adds the 'bitmap' sync mode
and uses it to add interactions with bitmaps to the 'full' and 'top'
modes to blockdev-backup and drive-backup.

Why?
 on-success: Can conveniently synchronize a bitmap to a full backup.
 Allows for transactionless anchor backups.
 Allows us to attempt an anchor backup without damaging
   our bitmap until the backup is successful.
 Allows for transactional, ungrouped anchor backups.
 always: Allows us to resume full/top style backups with a later
 invocation to sync=bitmap. Neat!

Summary:
1-3: Refactor iotest 257 to accommodate this;
4-5: Augment 257 to test trivial failure cases
6-9: Refactor sync=top for block/backup
10: Implement feature
11: Test feature

===
V2:
===

Key:
[] : patches are identical
[] : number of functional differences between upstream/downstream patch
[down] : patch is downstream-only
The flags [FC] indicate (F)unctional and (C)ontextual differences, respectively

001/11:[0010] [FC] 'iotests/257: add Pattern class'
002/11:[0003] [FC] 'iotests/257: add EmulatedBitmap class'
003/11:[0042] [FC] 'iotests/257: Refactor backup helpers'
004/11:[] [--] 'block/backup: hoist bitmap check into QMP interface'
005/11:[0016] [FC] 'iotests/257: test API failures'
006/11:[down] 'block/backup: improve sync=bitmap work estimates'
007/11:[down] 'block/backup: centralize copy_bitmap initialization'
008/11:[down] 'block/backup: add backup_is_cluster_allocated'
009/11:[down] 'block/backup: teach TOP to never copy unallocated regions'
010/11:[0002] [FC] 'block/backup: support bitmap sync modes for non-bitmap 
backups'
011/11:[0058] [FC] 'iotests/257: test traditional sync modes'

001: Fallout from changing floor(x / y) to x // y.
 Fallout from changing x = x | y to x |= y.
 (Decided not to keep RB.)
002: Removed dead variable
 Change x = x - y to x -= y in clear_bits()
003: Substantially reorganize patch. Hopefully 10% more clever and 10% less 
cute.
004: (Added RB.)
005: Added docstring to test_backup_api
 Fixed test matrix enumeration to have consistent order in python2/3
 (Declined RB.)
---: What was patch 006 was dropped, and became patches 6-9.
6-9: New!
010: Was 007;
 Formatting fix.
 (Added RB.)
011: Was 008;
 Adjust bitmap clearing/expected code as a consequence of #9.
 Fallout from changes to 005.

John Snow (11):
  iotests/257: add Pattern class
  iotests/257: add EmulatedBitmap class
  iotests/257: Refactor backup helpers
  block/backup: hoist bitmap check into QMP interface
  iotests/257: test API failures
  block/backup: improve sync=bitmap work estimates
  block/backup: centralize copy_bitmap initialization
  block/backup: add backup_is_cluster_allocated
  block/backup: teach TOP to never copy unallocated regions
  block/backup: support bitmap sync modes for non-bitmap backups
  iotests/257: test traditional sync modes

 block/backup.c |  188 +-
 block/trace-events |1 +
 blockdev.c |   32 +
 qapi/block-core.json   |6 +-
 tests/qemu-iotests/256.out |4 +-
 tests/qemu-iotests/257 |  342 ++--
 tests/qemu-iotests/257.out | 3366 +++-
 7 files changed, 3683 insertions(+), 256 deletions(-)

-- 
2.21.0




[Qemu-devel] [PATCH v2 02/11] iotests/257: add EmulatedBitmap class

2019-07-15 Thread John Snow
Represent a bitmap with an object that we can mark and clear bits in.
This makes it easier to manage partial writes when we don't write a
full group's worth of patterns before an error.

Signed-off-by: John Snow 
---
 tests/qemu-iotests/257 | 124 +
 1 file changed, 75 insertions(+), 49 deletions(-)

diff --git a/tests/qemu-iotests/257 b/tests/qemu-iotests/257
index 02f9ae0649..bc66ea03b2 100755
--- a/tests/qemu-iotests/257
+++ b/tests/qemu-iotests/257
@@ -85,6 +85,59 @@ GROUPS = [
 Pattern('0xdd', 0x3fc)]), # New; leaving a gap to the right
 ]
 
+
+class EmulatedBitmap:
+def __init__(self, granularity=GRANULARITY):
+self._bits = set()
+self.granularity = granularity
+
+def dirty_bits(self, bits):
+self._bits |= set(bits)
+
+def dirty_group(self, n):
+self.dirty_bits(GROUPS[n].bits(self.granularity))
+
+def clear(self):
+self._bits = set()
+
+def clear_bits(self, bits):
+self._bits -= set(bits)
+
+def clear_bit(self, bit):
+self.clear_bits({bit})
+
+def clear_group(self, n):
+self.clear_bits(GROUPS[n].bits(self.granularity))
+
+@property
+def first_bit(self):
+return sorted(self.bits)[0]
+
+@property
+def bits(self):
+return self._bits
+
+@property
+def count(self):
+return len(self.bits)
+
+def compare(self, qmp_bitmap):
+"""
+Print a nice human-readable message checking that a bitmap as reported
+by the QMP interface has as many bits set as we expect it to.
+"""
+
+name = qmp_bitmap.get('name', '(anonymous)')
+log("= Checking Bitmap {:s} =".format(name))
+
+want = self.count
+have = qmp_bitmap['count'] // qmp_bitmap['granularity']
+
+log("expecting {:d} dirty sectors; have {:d}. {:s}".format(
+want, have, "OK!" if want == have else "ERROR!"))
+log('')
+
+
 class Drive:
 """Represents, vaguely, a drive attached to a VM.
 Includes format, graph, and device information."""
@@ -195,27 +248,6 @@ def perform_writes(drive, n):
 log('')
 return bitmaps
 
-def calculate_bits(groups=None):
-"""Calculate how many bits we expect to see dirtied."""
-if groups:
-bits = set.union(*(GROUPS[group].bits(GRANULARITY) for group in 
groups))
-return len(bits)
-return 0
-
-def bitmap_comparison(bitmap, groups=None, want=0):
-"""
-Print a nice human-readable message checking that this bitmap has as
-many bits set as we expect it to.
-"""
-log("= Checking Bitmap {:s} =".format(bitmap.get('name', '(anonymous)')))
-
-if groups:
-want = calculate_bits(groups)
-have = bitmap['count'] // bitmap['granularity']
-
-log("expecting {:d} dirty sectors; have {:d}. {:s}".format(
-want, have, "OK!" if want == have else "ERROR!"))
-log('')
 
 def compare_images(image, reference, baseimg=None, expected_match=True):
 """
@@ -321,12 +353,13 @@ def test_bitmap_sync(bsync_mode, failure=None):
 vm.qmp_log("block-dirty-bitmap-add", node=drive0.name,
name="bitmap0", granularity=GRANULARITY)
 log('')
+ebitmap = EmulatedBitmap()
 
 # 1 - Writes and Reference Backup
 bitmaps = perform_writes(drive0, 1)
-dirty_groups = {1}
+ebitmap.dirty_group(1)
 bitmap = get_bitmap(bitmaps, drive0.device, 'bitmap0')
-bitmap_comparison(bitmap, groups=dirty_groups)
+ebitmap.compare(bitmap)
 reference_backup(drive0, 1, fbackup1)
 
 # 1 - Bitmap Backup (Optional induced failure)
@@ -342,54 +375,47 @@ def test_bitmap_sync(bsync_mode, failure=None):
 log('')
 bitmaps = perform_writes(drive0, 2)
 # Named bitmap (static, should be unchanged)
-bitmap_comparison(get_bitmap(bitmaps, drive0.device, 'bitmap0'),
-  groups=dirty_groups)
+ebitmap.compare(get_bitmap(bitmaps, drive0.device, 'bitmap0'))
 # Anonymous bitmap (dynamic, shows new writes)
-bitmap_comparison(get_bitmap(bitmaps, drive0.device, '',
- recording=True), groups={2})
-dirty_groups.add(2)
+anonymous = EmulatedBitmap()
+anonymous.dirty_group(2)
+anonymous.compare(get_bitmap(bitmaps, drive0.device, '',
+ recording=True))
+
+# Simulate the order in which this will happen:
+# group 1 gets cleared first, then group two gets written.
+if ((bsync_mode == 'on-success' and not failure) or
+(bsync_mode == 'always')):
+ebitmap.clear_group(1)
+ebitmap.dirty_group(2)
 
 vm.run_job(job, auto_dismiss=True, auto_finalize=False,
pre_finalize=_callback,
cancel=(failure == 

[Qemu-devel] [PATCH v2 10/11] block/backup: support bitmap sync modes for non-bitmap backups

2019-07-15 Thread John Snow
Accept bitmaps and sync policies for the other backup modes.
This allows us to do things like create a bitmap synced to a full backup
without a transaction, or start a resumable backup process.

Some combinations don't make sense, though:

- NEVER policy combined with any non-BITMAP mode doesn't do anything,
  because the bitmap isn't used for input or output.
  It's harmless, but is almost certainly never what the user wanted.

- sync=NONE is more questionable. It can't use on-success because this
  job never completes with success anyway, and the resulting artifact
  of 'always' is suspect: because we start with a full bitmap and only
  copy out segments that get written to, the final output bitmap will
  always be ... a fully set bitmap.

  Maybe there's contexts in which bitmaps make sense for sync=none,
  but not without more severe changes to the current job, and omitting
  it here doesn't prevent us from adding it later.

Signed-off-by: John Snow 
---
 block/backup.c   |  8 +---
 blockdev.c   | 22 ++
 qapi/block-core.json |  6 --
 3 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/block/backup.c b/block/backup.c
index e28fd23f6a..47628aca24 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -686,7 +686,7 @@ BlockJob *backup_job_create(const char *job_id, 
BlockDriverState *bs,
 return NULL;
 }
 
-if (sync_mode == MIRROR_SYNC_MODE_BITMAP) {
+if (sync_bitmap) {
 /* If we need to write to this bitmap, check that we can: */
 if (bitmap_mode != BITMAP_SYNC_MODE_NEVER &&
 bdrv_dirty_bitmap_check(sync_bitmap, BDRV_BITMAP_DEFAULT, errp)) {
@@ -697,12 +697,6 @@ BlockJob *backup_job_create(const char *job_id, 
BlockDriverState *bs,
 if (bdrv_dirty_bitmap_create_successor(bs, sync_bitmap, errp) < 0) {
 return NULL;
 }
-} else if (sync_bitmap) {
-error_setg(errp,
-   "a bitmap was given to backup_job_create, "
-   "but it received an incompatible sync_mode (%s)",
-   MirrorSyncMode_str(sync_mode));
-return NULL;
 }
 
 len = bdrv_getlength(bs);
diff --git a/blockdev.c b/blockdev.c
index 3c76c85cb5..29c6c6044a 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3565,6 +3565,28 @@ static BlockJob *do_backup_common(BackupCommon *backup,
 if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_ALLOW_RO, errp)) {
 return NULL;
 }
+
+/* This does not produce a useful bitmap artifact: */
+if (backup->sync == MIRROR_SYNC_MODE_NONE) {
+error_setg(errp, "sync mode '%s' does not produce meaningful 
bitmap"
+   " outputs", MirrorSyncMode_str(backup->sync));
+return NULL;
+}
+
+/* If the bitmap isn't used for input or output, this is useless: */
+if (backup->bitmap_mode == BITMAP_SYNC_MODE_NEVER &&
+backup->sync != MIRROR_SYNC_MODE_BITMAP) {
+error_setg(errp, "Bitmap sync mode '%s' has no meaningful effect"
+   " when combined with sync mode '%s'",
+   BitmapSyncMode_str(backup->bitmap_mode),
+   MirrorSyncMode_str(backup->sync));
+return NULL;
+}
+}
+
+if (!backup->has_bitmap && backup->has_bitmap_mode) {
+error_setg(errp, "Cannot specify bitmap sync mode without a bitmap");
+return NULL;
 }
 
 if (!backup->auto_finalize) {
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 5a578806c5..099e4f37b2 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1352,13 +1352,15 @@
 # @speed: the maximum speed, in bytes per second. The default is 0,
 # for unlimited.
 #
-# @bitmap: the name of a dirty bitmap if sync is "bitmap" or "incremental".
+# @bitmap: The name of a dirty bitmap to use.
 #  Must be present if sync is "bitmap" or "incremental".
+#  Can be present if sync is "full" or "top".
 #  Must not be present otherwise.
 #  (Since 2.4 (drive-backup), 3.1 (blockdev-backup))
 #
 # @bitmap-mode: Specifies the type of data the bitmap should contain after
-#   the operation concludes. Must be present if sync is "bitmap".
+#   the operation concludes.
+#   Must be present if a bitmap was provided,
 #   Must NOT be present otherwise. (Since 4.2)
 #
 # @compress: true to compress data, if the target format supports it.
-- 
2.21.0




Re: [Qemu-devel] [PATCH-for-4.1 v2 9/9] NSIS: Add missing firmware blobs

2019-07-15 Thread Laszlo Ersek
On 07/15/19 19:48, Philippe Mathieu-Daudé wrote:
> Various firmwares has been added in the pc-bios/ directory:
> 
> - CCW (since commit 0c1fecdd523)
> - Skiboot (since commit bcad45de6a0)
> - EDK2(since commit f7fa38b74c3)
> 
> Since we install qemu-system able to run the architectures
> targetted by these firmware, include them in the NSIS exe.
> 
> Signed-off-by: Philippe Mathieu-Daudé 
> ---
>  qemu.nsi | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/qemu.nsi b/qemu.nsi
> index 75f1608b9e..89c7c04f95 100644
> --- a/qemu.nsi
> +++ b/qemu.nsi
> @@ -122,6 +122,9 @@ Section "${PRODUCT} (required)"
>  File "${BINDIR}\*.bmp"
>  File "${BINDIR}\*.bin"
>  File "${BINDIR}\*.dtb"
> +File "${BINDIR}\*.fd"
> +File "${BINDIR}\*.img"
> +File "${BINDIR}\*.lid"
>  File "${BINDIR}\*.rom"
>  File "${BINDIR}\openbios-*"
>  
> 

This is the only patch I can (remotely) comment on... So I guess, from
another patch, NSIS stands for "Nullsoft Installer".

Acked-by: Laszlo Ersek 

I guess :)

Laszlo



[Qemu-devel] Any function to access nested guest virtual address space?

2019-07-15 Thread Jidong Xiao
Hi, All,

I know this function cpu_memory_rw_debug() allows us to access a
virtual machine's virtual memory address. Is there any similar
function that allows us to access the virtual memory space of a nested
virtual machine? i.e., L2.

Thanks.

-Jidong



Re: [Qemu-devel] [Qemu-riscv] [PATCH 2/2] riscv: sifive_u: Update the plic hart config to support multicore

2019-07-15 Thread Alistair Francis
On Sat, Jul 13, 2019 at 8:23 PM Bin Meng  wrote:
>
> Hi Fabien,
>
> On Tue, Jul 9, 2019 at 12:31 AM Fabien Chouteau  wrote:
> >
> > Hi Bin,
> >
> > Thanks for this patch.
> >
> > I know I am very late to the game but I have a comment here.
> >
> > On 17/05/2019 17:51, Bin Meng wrote:
> > > +/* create PLIC hart topology configuration string */
> > > +plic_hart_config_len = (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1) * 
> > > smp_cpus;
> > > +plic_hart_config = g_malloc0(plic_hart_config_len);
> > > +for (i = 0; i < smp_cpus; i++) {
> > > +if (i != 0) {
> > > +strncat(plic_hart_config, ",", plic_hart_config_len);
> > > +}
> > > +strncat(plic_hart_config, SIFIVE_U_PLIC_HART_CONFIG,
> > > +plic_hart_config_len);
> > > +plic_hart_config_len -= (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1);
> > > +}
> > > +
> >
> > This will create up to 4 MS PLIC devices. However on the Unleashed FU540 
> > the PLICs are M,MS,MS,MS,MS because of the monitor hart #0.
> >
> > This means a different memory layout than the real hardware.
> >
> > For instance address 0x0C00_2080 will be hart #0 S-Mode interrupt enables 
> > in QEMU, instead of #1 M-Mode interrupt enables for the real hardware.
>
> Thanks for the notes! I agree to better match the real hardware, it
> should be modeled like that. However I am not sure what the original
> intention was when creating the "sifive_u" machine. Both OpenSBI and
> U-Boot list sifive_u as a special target, instead of the real
> Unleashed board hence I assume this is a hypothetical target too, like
> the "virt", but was created to best match the real Unleashed board
> though.

I thought (Palmer correct me if I'm wrong) that the sifive_u machine
*should* match the hardware. The problem is that QEMU doesn't support
everything that the HW supports which is why U-Boot and OpenSBI have
their own targets. The goal is to not require special QEMU targets, so
this is a step in the right direction.

Alistair

>
> >
> > To fix this I suggest to change this loop to:
> >
> > for (i = 0; i < smp_cpus; i++) {
> > if (i != 0) {
> > strncat(plic_hart_config, "," SIFIVE_U_PLIC_HART_CONFIG,
> > plic_hart_config_len);
> > } else {
> > strncat(plic_hart_config, "M", plic_hart_config_len);
> > }
> > plic_hart_config_len -= (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1);
> > }
> >
> > This will make hart #0 PLIC in M mode and the others in MS.
> >
> > What do you think?
>
>
> Regards,
> Bin
>



Re: [Qemu-devel] [PATCH v2 00/14] Multiple simultaneous audio backends

2019-07-15 Thread no-reply
Patchew URL: 
https://patchew.org/QEMU/cover.1563224628.git.dirty.ice...@gmail.com/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Message-id: cover.1563224628.git.dirty.ice...@gmail.com
Type: series
Subject: [Qemu-devel] [PATCH v2 00/14] Multiple simultaneous audio backends

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
9bd8bc6 audio: fix memory leak reported by ASAN
e8d23f6 audio: use size_t where makes sense
7035d9f audio: remove read and write pcm_ops
82038f1 paaudio: fix playback glitches
ad773f9 audio: do not run each backend in audio_run
e5bae54 audio: remove audio_MIN, audio_MAX
3f525e4 paaudio: properly disconnect streams in fini_*
e76429c paaudio: do not move stream when sink/source name is specified
232f925 audio: audiodev= parameters no longer optional when -audiodev present
0475ef4 paaudio: prepare for multiple audiodev
d0ccdb3 audio: add audiodev properties to frontends
b8bbf6b audio: add audiodev property to vnc and wav_capture
45bece9 audio: basic support for multi backend audio
b8ed8fa audio: reduce glob_audio_state usage

=== OUTPUT BEGIN ===
1/14 Checking commit b8ed8fa72e64 (audio: reduce glob_audio_state usage)
2/14 Checking commit 45bece9445ff (audio: basic support for multi backend audio)
3/14 Checking commit b8bbf6b1534a (audio: add audiodev property to vnc and 
wav_capture)
4/14 Checking commit d0ccdb31831d (audio: add audiodev properties to frontends)
5/14 Checking commit 0475ef4aa556 (paaudio: prepare for multiple audiodev)
6/14 Checking commit 232f925703f4 (audio: audiodev= parameters no longer 
optional when -audiodev present)
7/14 Checking commit e76429c12dda (paaudio: do not move stream when sink/source 
name is specified)
8/14 Checking commit 3f525e459011 (paaudio: properly disconnect streams in 
fini_*)
9/14 Checking commit e5bae54fc748 (audio: remove audio_MIN, audio_MAX)
ERROR: space prohibited between function name and open parenthesis '('
#23: FILE: audio/alsaaudio.c:637:
+int len = MIN (alsa->pending, left_till_end_samples);

ERROR: space prohibited between function name and open parenthesis '('
#32: FILE: audio/alsaaudio.c:700:
+decr = MIN (live, avail);

ERROR: space prohibited between function name and open parenthesis '('
#41: FILE: audio/alsaaudio.c:918:
+decr = MIN (dead, avail);

ERROR: space prohibited between function name and open parenthesis '('
#54: FILE: audio/audio.c:536:
+m = MIN (m, sw->total_hw_samples_acquired);

ERROR: space prohibited between function name and open parenthesis '('
#63: FILE: audio/audio.c:556:
+int len = MIN (left, live);

ERROR: space prohibited between function name and open parenthesis '('
#71: FILE: audio/audio.c:563:
+int samples_to_clip = MIN (len, samples_till_end_of_buf);

ERROR: space prohibited between function name and open parenthesis '('
#80: FILE: audio/audio.c:617:
+swlim = MIN (swlim, samples);

ERROR: space prohibited between function name and open parenthesis '('
#89: FILE: audio/audio.c:665:
+m = MIN (m, sw->total_hw_samples_mixed);

ERROR: space prohibited between function name and open parenthesis '('
#98: FILE: audio/audio.c:728:
+swlim = MIN (swlim, samples);

ERROR: space prohibited between function name and open parenthesis '('
#107: FILE: audio/audio.c:740:
+blck = MIN (dead, left);

ERROR: space prohibited between function name and open parenthesis '('
#116: FILE: audio/audio.c:1032:
+int to_write = MIN (till_end_of_hw, n);

ERROR: space prohibited between function name and open parenthesis '('
#125: FILE: audio/audio.c:1050:
+n = MIN (samples, hw->samples - rpos);

ERROR: space prohibited between function name and open parenthesis '('
#134: FILE: audio/audio.c:1206:
+int to_capture = MIN (live, left);

ERROR: space prohibited between function name and open parenthesis '('
#175: FILE: audio/coreaudio.c:416:
+decr = MIN (core->decr, live);

ERROR: space prohibited between function name and open parenthesis '('
#188: FILE: audio/dsoundaudio.c:710:
+len = MIN (len, dead);

ERROR: space prohibited between function name and open parenthesis '('
#206: FILE: audio/noaudio.c:59:
+decr = MIN (live, samples);

ERROR: space prohibited between function name and open parenthesis '('
#215: FILE: audio/noaudio.c:114:
+bytes = MIN (bytes, INT_MAX);

ERROR: space prohibited between function name and open parenthesis '('
#218: FILE: audio/noaudio.c:116:
+samples = MIN (samples, dead);

ERROR: space prohibited between function name and open parenthesis '('
#227: FILE: audio/noaudio.c:127:
+int to_clear = MIN (samples, total);

ERROR: space 

[Qemu-devel] [PATCH v2 13/14] audio: use size_t where makes sense

2019-07-15 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/audio.h   |   4 +-
 audio/audio_int.h   |  26 +++
 audio/audio_template.h  |  14 ++--
 audio/mixeng.h  |   9 +--
 audio/rate_template.h   |   2 +-
 include/sysemu/replay.h |   4 +-
 audio/alsaaudio.c   |  26 +++
 audio/audio.c   | 156 
 audio/coreaudio.c   |  10 +--
 audio/dsoundaudio.c |  11 +--
 audio/noaudio.c |  16 ++---
 audio/ossaudio.c|  45 ++--
 audio/paaudio.c |  44 ++--
 audio/sdlaudio.c|  20 +++---
 audio/spiceaudio.c  |  12 ++--
 audio/wavaudio.c|   8 +--
 replay/replay-audio.c   |  16 ++---
 replay/replay.c |   2 +-
 18 files changed, 212 insertions(+), 213 deletions(-)

diff --git a/audio/audio.h b/audio/audio.h
index 4a95758516..2db27bba7b 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -112,7 +112,7 @@ SWVoiceOut *AUD_open_out (
 );
 
 void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
-int  AUD_write (SWVoiceOut *sw, void *pcm_buf, int size);
+size_t AUD_write (SWVoiceOut *sw, void *pcm_buf, size_t size);
 int  AUD_get_buffer_size_out (SWVoiceOut *sw);
 void AUD_set_active_out (SWVoiceOut *sw, int on);
 int  AUD_is_active_out (SWVoiceOut *sw);
@@ -133,7 +133,7 @@ SWVoiceIn *AUD_open_in (
 );
 
 void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
-int  AUD_read (SWVoiceIn *sw, void *pcm_buf, int size);
+size_t AUD_read (SWVoiceIn *sw, void *pcm_buf, size_t size);
 void AUD_set_active_in (SWVoiceIn *sw, int on);
 int  AUD_is_active_in (SWVoiceIn *sw);
 
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 003b7ab8cc..a674c5374a 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -61,12 +61,12 @@ typedef struct HWVoiceOut {
 
 f_sample *clip;
 
-int rpos;
+size_t rpos;
 uint64_t ts_helper;
 
 struct st_sample *mix_buf;
 
-int samples;
+size_t samples;
 QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
 QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
 int ctl_caps;
@@ -82,13 +82,13 @@ typedef struct HWVoiceIn {
 
 t_sample *conv;
 
-int wpos;
-int total_samples_captured;
+size_t wpos;
+size_t total_samples_captured;
 uint64_t ts_helper;
 
 struct st_sample *conv_buf;
 
-int samples;
+size_t samples;
 QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
 int ctl_caps;
 struct audio_pcm_ops *pcm_ops;
@@ -103,7 +103,7 @@ struct SWVoiceOut {
 int64_t ratio;
 struct st_sample *buf;
 void *rate;
-int total_hw_samples_mixed;
+size_t total_hw_samples_mixed;
 int active;
 int empty;
 HWVoiceOut *hw;
@@ -120,7 +120,7 @@ struct SWVoiceIn {
 struct audio_pcm_info info;
 int64_t ratio;
 void *rate;
-int total_hw_samples_acquired;
+size_t total_hw_samples_acquired;
 struct st_sample *buf;
 f_sample *clip;
 HWVoiceIn *hw;
@@ -149,12 +149,12 @@ struct audio_driver {
 struct audio_pcm_ops {
 int  (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque);
 void (*fini_out)(HWVoiceOut *hw);
-int  (*run_out) (HWVoiceOut *hw, int live);
+size_t (*run_out)(HWVoiceOut *hw, size_t live);
 int  (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
 
 int  (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaque);
 void (*fini_in) (HWVoiceIn *hw);
-int  (*run_in)  (HWVoiceIn *hw);
+size_t (*run_in)(HWVoiceIn *hw);
 int  (*ctl_in)  (HWVoiceIn *hw, int cmd, ...);
 };
 
@@ -208,10 +208,10 @@ audio_driver *audio_driver_lookup(const char *name);
 void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
 void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int 
len);
 
-int  audio_pcm_hw_get_live_in (HWVoiceIn *hw);
+size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw);
 
-int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
-   int live, int pending);
+size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf,
+ size_t live, size_t pending);
 
 int audio_bug (const char *funcname, int cond);
 void *audio_calloc (const char *funcname, int nmemb, size_t size);
@@ -224,7 +224,7 @@ void audio_run(AudioState *s, const char *msg);
 
 #define VOICE_VOLUME_CAP (1 << VOICE_VOLUME)
 
-static inline int audio_ring_dist (int dst, int src, int len)
+static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len)
 {
 return (dst >= src) ? (dst - src) : (len - src + dst);
 }
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 54f07338e7..2562bf5f00 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -75,16 +75,16 @@ static void glue (audio_pcm_hw_free_resources_, TYPE) (HW 
*hw)
 HWBUF = NULL;
 }
 
-static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
+static bool glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
 {
 HWBUF = audio_calloc(__func__, hw->samples, 

Re: [Qemu-devel] [RFC PATCH-for-4.1? v2 0/5] semihosting: Build with CONFIG_SEMIHOSTING disabled

2019-07-15 Thread no-reply
Patchew URL: https://patchew.org/QEMU/20190715152225.26135-1-phi...@redhat.com/



Hi,

This series failed build test on s390x host. Please find the details below.

=== TEST SCRIPT BEGIN ===
#!/bin/bash
# Testing script will be invoked under the git checkout with
# HEAD pointing to a commit that has the patches applied on top of "base"
# branch
set -e

echo
echo "=== ENV ==="
env

echo
echo "=== PACKAGES ==="
rpm -qa

echo
echo "=== UNAME ==="
uname -a

CC=$HOME/bin/cc
INSTALL=$PWD/install
BUILD=$PWD/build
mkdir -p $BUILD $INSTALL
SRC=$PWD
cd $BUILD
$SRC/configure --cc=$CC --prefix=$INSTALL
make -j4
# XXX: we need reliable clean up
# make check -j4 V=1
make install
=== TEST SCRIPT END ===

  CC  mips64-linux-user/linux-user/fd-trans.o
  CC  mips64-linux-user/target/mips/translate.o
  CC  mips64el-linux-user/target/mips/mips-semi-stubs.o
/var/tmp/patchew-tester-tmp-n0mrs_zw/src/target/mips/mips-semi-stubs.c:19:6: 
error: no previous prototype for ‘helper_do_semihosting’ 
[-Werror=missing-prototypes]
   19 | void helper_do_semihosting(CPUMIPSState *env)
  |  ^
cc1: all warnings being treated as errors
---
  CC  mipsel-linux-user/target/mips/translate.o
  CC  mips64-linux-user/target/mips/msa_helper.o
  CC  mips64-linux-user/target/mips/mips-semi-stubs.o
/var/tmp/patchew-tester-tmp-n0mrs_zw/src/target/mips/mips-semi-stubs.c:19:6: 
error: no previous prototype for ‘helper_do_semihosting’ 
[-Werror=missing-prototypes]
   19 | void helper_do_semihosting(CPUMIPSState *env)
  |  ^
cc1: all warnings being treated as errors
---
  CC  mipsel-linux-user/target/mips/mips-semi-stubs.o
  GEN trace/generated-helpers.c
  CC  mipsel-linux-user/trace/control-target.o
/var/tmp/patchew-tester-tmp-n0mrs_zw/src/target/mips/mips-semi-stubs.c:19:6: 
error: no previous prototype for ‘helper_do_semihosting’ 
[-Werror=missing-prototypes]
   19 | void helper_do_semihosting(CPUMIPSState *env)
  |  ^
cc1: all warnings being treated as errors


The full log is available at
http://patchew.org/logs/20190715152225.26135-1-phi...@redhat.com/testing.s390x/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-de...@redhat.com

[Qemu-devel] [PATCH v2 09/14] audio: remove audio_MIN, audio_MAX

2019-07-15 Thread Kővágó, Zoltán
There's already a MIN and MAX macro in include/qemu/osdep.h, use them
instead.

Signed-off-by: Kővágó, Zoltán 
Reviewed-by: Marc-André Lureau 
---
 audio/audio.h | 17 -
 audio/alsaaudio.c |  6 +++---
 audio/audio.c | 20 ++--
 audio/coreaudio.c |  2 +-
 audio/dsoundaudio.c   |  2 +-
 audio/noaudio.c   | 10 +-
 audio/ossaudio.c  |  6 +++---
 audio/paaudio.c   | 12 ++--
 audio/sdlaudio.c  |  6 +++---
 audio/spiceaudio.c| 10 +-
 audio/wavaudio.c  |  4 ++--
 hw/audio/ac97.c   | 10 +-
 hw/audio/adlib.c  |  4 ++--
 hw/audio/cs4231a.c|  4 ++--
 hw/audio/es1370.c |  6 +++---
 hw/audio/gus.c|  6 +++---
 hw/audio/hda-codec.c  | 16 
 hw/audio/milkymist-ac97.c |  8 
 hw/audio/pcspk.c  |  2 +-
 hw/audio/sb16.c   |  2 +-
 hw/audio/wm8750.c |  4 ++--
 21 files changed, 70 insertions(+), 87 deletions(-)

diff --git a/audio/audio.h b/audio/audio.h
index c0722a5cda..4a95758516 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -146,23 +146,6 @@ static inline void *advance (void *p, int incr)
 return (d + incr);
 }
 
-#ifdef __GNUC__
-#define audio_MIN(a, b) ( __extension__ ({  \
-__typeof (a) ta = a;\
-__typeof (b) tb = b;\
-((ta)>(tb)?(tb):(ta));  \
-}))
-
-#define audio_MAX(a, b) ( __extension__ ({  \
-__typeof (a) ta = a;\
-__typeof (b) tb = b;\
-((ta)<(tb)?(tb):(ta));  \
-}))
-#else
-#define audio_MIN(a, b) ((a)>(b)?(b):(a))
-#define audio_MAX(a, b) ((a)<(b)?(b):(a))
-#endif
-
 int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
   int freq, int bits, int nchannels);
 
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 3745c823ad..6b9e0f06af 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -634,7 +634,7 @@ static void alsa_write_pending (ALSAVoiceOut *alsa)
 
 while (alsa->pending) {
 int left_till_end_samples = hw->samples - alsa->wpos;
-int len = audio_MIN (alsa->pending, left_till_end_samples);
+int len = MIN (alsa->pending, left_till_end_samples);
 char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
 
 while (len) {
@@ -697,7 +697,7 @@ static int alsa_run_out (HWVoiceOut *hw, int live)
 return 0;
 }
 
-decr = audio_MIN (live, avail);
+decr = MIN (live, avail);
 decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
 alsa->pending += decr;
 alsa_write_pending (alsa);
@@ -915,7 +915,7 @@ static int alsa_run_in (HWVoiceIn *hw)
 }
 }
 
-decr = audio_MIN (dead, avail);
+decr = MIN (dead, avail);
 if (!decr) {
 return 0;
 }
diff --git a/audio/audio.c b/audio/audio.c
index d131958194..cb0222ab4a 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -533,7 +533,7 @@ static int audio_pcm_hw_find_min_in (HWVoiceIn *hw)
 
 for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
 if (sw->active) {
-m = audio_MIN (m, sw->total_hw_samples_acquired);
+m = MIN (m, sw->total_hw_samples_acquired);
 }
 }
 return m;
@@ -553,14 +553,14 @@ int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
int live, int pending)
 {
 int left = hw->samples - pending;
-int len = audio_MIN (left, live);
+int len = MIN (left, live);
 int clipped = 0;
 
 while (len) {
 struct st_sample *src = hw->mix_buf + hw->rpos;
 uint8_t *dst = advance (pcm_buf, hw->rpos << hw->info.shift);
 int samples_till_end_of_buf = hw->samples - hw->rpos;
-int samples_to_clip = audio_MIN (len, samples_till_end_of_buf);
+int samples_to_clip = MIN (len, samples_till_end_of_buf);
 
 hw->clip (dst, src, samples_to_clip);
 
@@ -614,7 +614,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
 }
 
 swlim = (live * sw->ratio) >> 32;
-swlim = audio_MIN (swlim, samples);
+swlim = MIN (swlim, samples);
 
 while (swlim) {
 src = hw->conv_buf + rpos;
@@ -662,7 +662,7 @@ static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int 
*nb_livep)
 
 for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
 if (sw->active || !sw->empty) {
-m = audio_MIN (m, sw->total_hw_samples_mixed);
+m = MIN (m, sw->total_hw_samples_mixed);
 nb_live += 1;
 }
 }
@@ -725,7 +725,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
 
 dead = hwsamples - live;
 swlim = ((int64_t) dead << 32) / sw->ratio;
-swlim = audio_MIN (swlim, samples);
+swlim = MIN (swlim, samples);
 if (swlim) {
 sw->conv (sw->buf, buf, 

[Qemu-devel] [PATCH v2 08/14] paaudio: properly disconnect streams in fini_*

2019-07-15 Thread Kővágó, Zoltán
Currently this needs a workaround due to bug #247 in pulseaudio.

Signed-off-by: Kővágó, Zoltán 
Reviewed-by: Marc-André Lureau 
---
 audio/paaudio.c | 25 +++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index 24d98b344a..1d68173636 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -685,6 +685,27 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings 
*as, void *drv_opaque)
 return -1;
 }
 
+static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
+{
+int err;
+
+pa_threaded_mainloop_lock(c->mainloop);
+/*
+ * wait until actually connects. workaround pa bug #247
+ * https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/247
+ */
+while (pa_stream_get_state(stream) == PA_STREAM_CREATING) {
+pa_threaded_mainloop_wait(c->mainloop);
+}
+
+err = pa_stream_disconnect(stream);
+if (err != 0) {
+dolog("Failed to disconnect! err=%d\n", err);
+}
+pa_stream_unref(stream);
+pa_threaded_mainloop_unlock(c->mainloop);
+}
+
 static void qpa_fini_out (HWVoiceOut *hw)
 {
 void *ret;
@@ -696,7 +717,7 @@ static void qpa_fini_out (HWVoiceOut *hw)
 audio_pt_join(>pt, , __func__);
 
 if (pa->stream) {
-pa_stream_unref (pa->stream);
+qpa_simple_disconnect(pa->g->conn, pa->stream);
 pa->stream = NULL;
 }
 
@@ -716,7 +737,7 @@ static void qpa_fini_in (HWVoiceIn *hw)
 audio_pt_join(>pt, , __func__);
 
 if (pa->stream) {
-pa_stream_unref (pa->stream);
+qpa_simple_disconnect(pa->g->conn, pa->stream);
 pa->stream = NULL;
 }
 
-- 
2.22.0




[Qemu-devel] [PATCH v2 10/14] audio: do not run each backend in audio_run

2019-07-15 Thread Kővágó, Zoltán
audio_run is called manually by alsa and oss backends when polling.
In this case only the requesting backend should be run, not all of them.

Signed-off-by: Kővágó, Zoltán 
Reviewed-by: Marc-André Lureau 
---
 audio/audio_int.h |  2 +-
 audio/alsaaudio.c |  7 +--
 audio/audio.c | 14 +-
 audio/ossaudio.c  | 12 ++--
 4 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 9f01f6ad00..7e00c1332e 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -221,7 +221,7 @@ int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
 int audio_bug (const char *funcname, int cond);
 void *audio_calloc (const char *funcname, int nmemb, size_t size);
 
-void audio_run (const char *msg);
+void audio_run(AudioState *s, const char *msg);
 
 #define VOICE_ENABLE 1
 #define VOICE_DISABLE 2
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 6b9e0f06af..3daa7c8f8f 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -39,6 +39,7 @@ struct pollhlp {
 struct pollfd *pfds;
 int count;
 int mask;
+AudioState *s;
 };
 
 typedef struct ALSAVoiceOut {
@@ -199,11 +200,11 @@ static void alsa_poll_handler (void *opaque)
 break;
 
 case SND_PCM_STATE_PREPARED:
-audio_run ("alsa run (prepared)");
+audio_run(hlp->s, "alsa run (prepared)");
 break;
 
 case SND_PCM_STATE_RUNNING:
-audio_run ("alsa run (running)");
+audio_run(hlp->s, "alsa run (running)");
 break;
 
 default:
@@ -749,6 +750,7 @@ static int alsa_init_out(HWVoiceOut *hw, struct audsettings 
*as,
 return -1;
 }
 
+alsa->pollhlp.s = hw->s;
 alsa->handle = handle;
 alsa->dev = dev;
 return 0;
@@ -850,6 +852,7 @@ static int alsa_init_in(HWVoiceIn *hw, struct audsettings 
*as, void *drv_opaque)
 return -1;
 }
 
+alsa->pollhlp.s = hw->s;
 alsa->handle = handle;
 alsa->dev = dev;
 return 0;
diff --git a/audio/audio.c b/audio/audio.c
index cb0222ab4a..07b35ffa03 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -835,7 +835,7 @@ static void audio_timer (void *opaque)
 }
 s->timer_last = now;
 
-audio_run("timer");
+audio_run(s, "timer");
 audio_reset_timer(s);
 }
 
@@ -1237,15 +1237,11 @@ static void audio_run_capture (AudioState *s)
 }
 }
 
-void audio_run (const char *msg)
+void audio_run(AudioState *s, const char *msg)
 {
-AudioState *s;
-
-QTAILQ_FOREACH(s, _states, list) {
-audio_run_out(s);
-audio_run_in(s);
-audio_run_capture(s);
-}
+audio_run_out(s);
+audio_run_in(s);
+audio_run_capture(s);
 
 #ifdef DEBUG_POLL
 {
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index 29139ef1f5..456fba7480 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -110,28 +110,28 @@ static void oss_anal_close (int *fdp)
 
 static void oss_helper_poll_out (void *opaque)
 {
-(void) opaque;
-audio_run ("oss_poll_out");
+AudioState *s = opaque;
+audio_run(s, "oss_poll_out");
 }
 
 static void oss_helper_poll_in (void *opaque)
 {
-(void) opaque;
-audio_run ("oss_poll_in");
+AudioState *s = opaque;
+audio_run(s, "oss_poll_in");
 }
 
 static void oss_poll_out (HWVoiceOut *hw)
 {
 OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 
-qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL);
+qemu_set_fd_handler(oss->fd, NULL, oss_helper_poll_out, hw->s);
 }
 
 static void oss_poll_in (HWVoiceIn *hw)
 {
 OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 
-qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL);
+qemu_set_fd_handler(oss->fd, oss_helper_poll_in, NULL, hw->s);
 }
 
 static int oss_write (SWVoiceOut *sw, void *buf, int len)
-- 
2.22.0




[Qemu-devel] [PATCH v2 07/14] paaudio: do not move stream when sink/source name is specified

2019-07-15 Thread Kővágó, Zoltán
Unless we disable stream moving, pulseaudio can easily move the stream
on connect, effectively ignoring the source/sink specified by the user.

Signed-off-by: Kővágó, Zoltán 
Reviewed-by: Marc-André Lureau 
---
 audio/paaudio.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index cc3a34c2ea..24d98b344a 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -517,6 +517,11 @@ static pa_stream *qpa_simple_new (
 #endif
 | PA_STREAM_AUTO_TIMING_UPDATE;
 
+if (dev) {
+/* don't move the stream if the user specified a sink/source */
+flags |= PA_STREAM_DONT_MOVE;
+}
+
 if (dir == PA_STREAM_PLAYBACK) {
 r = pa_stream_connect_playback(stream, dev, attr, flags, NULL, NULL);
 } else {
-- 
2.22.0




[Qemu-devel] [PATCH v2 14/14] audio: fix memory leak reported by ASAN

2019-07-15 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/audio.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/audio/audio.c b/audio/audio.c
index d3c639211d..ebe49f3ca1 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1343,6 +1343,12 @@ static void free_audio_state(AudioState *s)
 qapi_free_Audiodev(s->dev);
 s->dev = NULL;
 }
+
+if (s->ts) {
+timer_free(s->ts);
+s->ts = NULL;
+}
+
 g_free(s);
 }
 
-- 
2.22.0




[Qemu-devel] [PATCH v2 06/14] audio: audiodev= parameters no longer optional when -audiodev present

2019-07-15 Thread Kővágó, Zoltán
This means you should probably stop using -soundhw (as it doesn't allow
you to specify any options) and add the device manually with -device.
The exception is pcspk, it's currently not possible to manually add it.
To use it with audiodev, use something like this:

-audiodev id=foo,... -global isa-pcspk.audiodev=foo -soundhw pcspk

Signed-off-by: Kővágó, Zoltán 
---

Notes:
Changes from v1:

* Split off paaudio changes to a different commit.

 audio/audio.c | 24 +++-
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index 4baa37caac..d131958194 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -101,6 +101,8 @@ const struct mixeng_volume nominal_volume = {
 #endif
 };
 
+static bool legacy_config = true;
+
 #ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
 #error No its not
 #else
@@ -1392,7 +1394,7 @@ static AudiodevListEntry *audiodev_find(
  * if dev == NULL => legacy implicit initialization, return the already created
  *   state or create a new one
  */
-static AudioState *audio_init(Audiodev *dev)
+static AudioState *audio_init(Audiodev *dev, const char *name)
 {
 static bool atexit_registered;
 size_t i;
@@ -1406,12 +1408,13 @@ static AudioState *audio_init(Audiodev *dev)
 
 if (dev) {
 /* -audiodev option */
+legacy_config = false;
 drvname = AudiodevDriver_str(dev->driver);
 } else if (!QTAILQ_EMPTY(_states)) {
-/*
- * todo: check for -audiodev once we have normal audiodev selection
- * support
- */
+if (!legacy_config) {
+dolog("You must specify an audiodev= for the device %s\n", name);
+exit(1);
+}
 return QTAILQ_FIRST(_states);
 } else {
 /* legacy implicit initialization */
@@ -1518,7 +1521,7 @@ void audio_free_audiodev_list(AudiodevListHead *head)
 void AUD_register_card (const char *name, QEMUSoundCard *card)
 {
 if (!card->state) {
-card->state = audio_init(NULL);
+card->state = audio_init(NULL, name);
 }
 
 card->name = g_strdup (name);
@@ -1544,8 +1547,11 @@ CaptureVoiceOut *AUD_add_capture(
 struct capture_callback *cb;
 
 if (!s) {
-/* todo: remove when we have normal audiodev selection support */
-s = audio_init(NULL);
+if (!legacy_config) {
+dolog("You must specify audiodev when trying to capture\n");
+return NULL;
+}
+s = audio_init(NULL, NULL);
 }
 
 if (audio_validate_settings (as)) {
@@ -1776,7 +1782,7 @@ void audio_init_audiodevs(void)
 AudiodevListEntry *e;
 
 QSIMPLEQ_FOREACH(e, , next) {
-audio_init(e->dev);
+audio_init(e->dev, NULL);
 }
 }
 
-- 
2.22.0




[Qemu-devel] [PATCH v2 11/14] paaudio: fix playback glitches

2019-07-15 Thread Kővágó, Zoltán
Pulseaudio normally assumes that when the server wants it, the client
can generate the audio samples and send it right away.  Unfortunately
this is not the case with QEMU -- it's up to the emulated system when
does it generate the samples.  Buffering the samples and sending them
from a background thread is just a workaround, that doesn't work too
well.  Instead enable pa's compatibility support and let pa worry about
the details.

Signed-off-by: Kővágó, Zoltán 
---
 audio/paaudio.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index f3864e1d50..c8ae1a6eca 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -512,10 +512,8 @@ static pa_stream *qpa_simple_new (
 
 flags =
 PA_STREAM_INTERPOLATE_TIMING
-#ifdef PA_STREAM_ADJUST_LATENCY
-| PA_STREAM_ADJUST_LATENCY
-#endif
-| PA_STREAM_AUTO_TIMING_UPDATE;
+| PA_STREAM_AUTO_TIMING_UPDATE
+| PA_STREAM_EARLY_REQUESTS;
 
 if (dev) {
 /* don't move the stream if the user specified a sink/source */
-- 
2.22.0




[Qemu-devel] [PATCH v2 12/14] audio: remove read and write pcm_ops

2019-07-15 Thread Kővágó, Zoltán
They just called audio_pcm_sw_read/write anyway, so it makes no sense
to have them too.  (The noaudio's read is the only exception, but it
should work with the generic code too.)

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_int.h   |  5 -
 audio/alsaaudio.c   | 12 
 audio/audio.c   |  8 
 audio/coreaudio.c   |  6 --
 audio/dsoundaudio.c | 12 
 audio/noaudio.c | 19 ---
 audio/ossaudio.c| 12 
 audio/paaudio.c | 12 
 audio/sdlaudio.c|  6 --
 audio/spiceaudio.c  | 12 
 audio/wavaudio.c|  6 --
 11 files changed, 4 insertions(+), 106 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 7e00c1332e..003b7ab8cc 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -150,13 +150,11 @@ struct audio_pcm_ops {
 int  (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque);
 void (*fini_out)(HWVoiceOut *hw);
 int  (*run_out) (HWVoiceOut *hw, int live);
-int  (*write)   (SWVoiceOut *sw, void *buf, int size);
 int  (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
 
 int  (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaque);
 void (*fini_in) (HWVoiceIn *hw);
 int  (*run_in)  (HWVoiceIn *hw);
-int  (*read)(SWVoiceIn *sw, void *buf, int size);
 int  (*ctl_in)  (HWVoiceIn *hw, int cmd, ...);
 };
 
@@ -210,11 +208,8 @@ audio_driver *audio_driver_lookup(const char *name);
 void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
 void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int 
len);
 
-int  audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
 int  audio_pcm_hw_get_live_in (HWVoiceIn *hw);
 
-int  audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int len);
-
 int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
int live, int pending);
 
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 3daa7c8f8f..e9e3a4819c 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -270,11 +270,6 @@ static int alsa_poll_in (HWVoiceIn *hw)
 return alsa_poll_helper (alsa->handle, >pollhlp, POLLIN);
 }
 
-static int alsa_write (SWVoiceOut *sw, void *buf, int len)
-{
-return audio_pcm_sw_write (sw, buf, len);
-}
-
 static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
 {
 switch (fmt) {
@@ -988,11 +983,6 @@ static int alsa_run_in (HWVoiceIn *hw)
 return read_samples;
 }
 
-static int alsa_read (SWVoiceIn *sw, void *buf, int size)
-{
-return audio_pcm_sw_read (sw, buf, size);
-}
-
 static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
 {
 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
@@ -1076,13 +1066,11 @@ static struct audio_pcm_ops alsa_pcm_ops = {
 .init_out = alsa_init_out,
 .fini_out = alsa_fini_out,
 .run_out  = alsa_run_out,
-.write= alsa_write,
 .ctl_out  = alsa_ctl_out,
 
 .init_in  = alsa_init_in,
 .fini_in  = alsa_fini_in,
 .run_in   = alsa_run_in,
-.read = alsa_read,
 .ctl_in   = alsa_ctl_in,
 };
 
diff --git a/audio/audio.c b/audio/audio.c
index 07b35ffa03..254499dfa1 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -594,7 +594,7 @@ static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw)
 }
 }
 
-int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
+static int audio_pcm_sw_read(SWVoiceIn *sw, void *buf, int size)
 {
 HWVoiceIn *hw = sw->hw;
 int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
@@ -696,7 +696,7 @@ static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int 
*nb_live)
 /*
  * Soft voice (playback)
  */
-int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
+static int audio_pcm_sw_write(SWVoiceOut *sw, void *buf, int size)
 {
 int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
 int ret = 0, pos = 0, total = 0;
@@ -854,7 +854,7 @@ int AUD_write (SWVoiceOut *sw, void *buf, int size)
 return 0;
 }
 
-return sw->hw->pcm_ops->write(sw, buf, size);
+return audio_pcm_sw_write(sw, buf, size);
 }
 
 int AUD_read (SWVoiceIn *sw, void *buf, int size)
@@ -869,7 +869,7 @@ int AUD_read (SWVoiceIn *sw, void *buf, int size)
 return 0;
 }
 
-return sw->hw->pcm_ops->read(sw, buf, size);
+return audio_pcm_sw_read(sw, buf, size);
 }
 
 int AUD_get_buffer_size_out (SWVoiceOut *sw)
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index f0ab4014a8..091fe84a34 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -489,11 +489,6 @@ static OSStatus audioDeviceIOProc(
 return 0;
 }
 
-static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
-{
-return audio_pcm_sw_write (sw, buf, len);
-}
-
 static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
   void *drv_opaque)
 {
@@ -692,7 +687,6 @@ static struct audio_pcm_ops coreaudio_pcm_ops = {
 .init_out = coreaudio_init_out,
 .fini_out = 

[Qemu-devel] [PATCH v2 05/14] paaudio: prepare for multiple audiodev

2019-07-15 Thread Kővágó, Zoltán
Have a pool of refcounted connections per server, so if the user creates
multiple audiodevs to the same pa server, it will use a single connection.  (It
will still create different streams, so the user can manage those streams
separately in pulseaudio.)

Signed-off-by: Kővágó, Zoltán 
---
 audio/paaudio.c | 329 +++-
 1 file changed, 188 insertions(+), 141 deletions(-)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index 5fc886bb33..cc3a34c2ea 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -11,10 +11,21 @@
 #include "audio_int.h"
 #include "audio_pt_int.h"
 
-typedef struct {
-Audiodev *dev;
+typedef struct PAConnection {
+char *server;
+int refcount;
+QTAILQ_ENTRY(PAConnection) list;
+
 pa_threaded_mainloop *mainloop;
 pa_context *context;
+} PAConnection;
+
+static QTAILQ_HEAD(PAConnectionHead, PAConnection) pa_conns =
+QTAILQ_HEAD_INITIALIZER(pa_conns);
+
+typedef struct {
+Audiodev *dev;
+PAConnection *conn;
 } paaudio;
 
 typedef struct {
@@ -45,7 +56,7 @@ typedef struct {
 int samples;
 } PAVoiceIn;
 
-static void qpa_audio_fini(void *opaque);
+static void qpa_conn_fini(PAConnection *c);
 
 static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
 {
@@ -108,11 +119,11 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
 
 static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int 
*rerror)
 {
-paaudio *g = p->g;
+PAConnection *c = p->g->conn;
 
-pa_threaded_mainloop_lock (g->mainloop);
+pa_threaded_mainloop_lock(c->mainloop);
 
-CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
 
 while (length > 0) {
 size_t l;
@@ -121,11 +132,11 @@ static int qpa_simple_read (PAVoiceIn *p, void *data, 
size_t length, int *rerror
 int r;
 
 r = pa_stream_peek (p->stream, >read_data, >read_length);
-CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
+CHECK_SUCCESS_GOTO(c, rerror, r == 0, unlock_and_fail);
 
 if (!p->read_data) {
-pa_threaded_mainloop_wait (g->mainloop);
-CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+pa_threaded_mainloop_wait(c->mainloop);
+CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
 } else {
 p->read_index = 0;
 }
@@ -148,53 +159,53 @@ static int qpa_simple_read (PAVoiceIn *p, void *data, 
size_t length, int *rerror
 p->read_length = 0;
 p->read_index = 0;
 
-CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
+CHECK_SUCCESS_GOTO(c, rerror, r == 0, unlock_and_fail);
 }
 }
 
-pa_threaded_mainloop_unlock (g->mainloop);
+pa_threaded_mainloop_unlock(c->mainloop);
 return 0;
 
 unlock_and_fail:
-pa_threaded_mainloop_unlock (g->mainloop);
+pa_threaded_mainloop_unlock(c->mainloop);
 return -1;
 }
 
 static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, 
int *rerror)
 {
-paaudio *g = p->g;
+PAConnection *c = p->g->conn;
 
-pa_threaded_mainloop_lock (g->mainloop);
+pa_threaded_mainloop_lock(c->mainloop);
 
-CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
 
 while (length > 0) {
 size_t l;
 int r;
 
 while (!(l = pa_stream_writable_size (p->stream))) {
-pa_threaded_mainloop_wait (g->mainloop);
-CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+pa_threaded_mainloop_wait(c->mainloop);
+CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
 }
 
-CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail);
+CHECK_SUCCESS_GOTO(c, rerror, l != (size_t) -1, unlock_and_fail);
 
 if (l > length) {
 l = length;
 }
 
 r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
-CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail);
+CHECK_SUCCESS_GOTO(c, rerror, r >= 0, unlock_and_fail);
 
 data = (const uint8_t *) data + l;
 length -= l;
 }
 
-pa_threaded_mainloop_unlock (g->mainloop);
+pa_threaded_mainloop_unlock(c->mainloop);
 return 0;
 
 unlock_and_fail:
-pa_threaded_mainloop_unlock (g->mainloop);
+pa_threaded_mainloop_unlock(c->mainloop);
 return -1;
 }
 
@@ -432,13 +443,13 @@ static AudioFormat pa_to_audfmt (pa_sample_format_t fmt, 
int *endianness)
 
 static void context_state_cb (pa_context *c, void *userdata)
 {
-paaudio *g = userdata;
+PAConnection *conn = userdata;
 
 switch (pa_context_get_state(c)) {
 case PA_CONTEXT_READY:
 case PA_CONTEXT_TERMINATED:
 case PA_CONTEXT_FAILED:
-pa_threaded_mainloop_signal (g->mainloop, 0);
+

[Qemu-devel] [PATCH v2 02/14] audio: basic support for multi backend audio

2019-07-15 Thread Kővágó, Zoltán
Audio functions no longer access glob_audio_state, instead they get an
AudioState as a parameter.  This is required in order to support
multiple backends.

glob_audio_state is also gone, and replaced with a tailq so we can store
more than one states.

Signed-off-by: Kővágó, Zoltán 
---

Notes:
Changes from v1:

* Moved wav_capture/vnc audiodev param to a separate commit

 audio/audio.h  |  12 +++--
 audio/audio_int.h  |   2 +
 audio/audio_template.h |   2 +-
 audio/audio.c  | 102 +++--
 audio/wavcapture.c |   6 +--
 monitor/misc.c |   2 +-
 ui/vnc.c   |   2 +-
 7 files changed, 95 insertions(+), 33 deletions(-)

diff --git a/audio/audio.h b/audio/audio.h
index 64b0f761bc..ad2457f4de 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -78,8 +78,10 @@ typedef struct SWVoiceOut SWVoiceOut;
 typedef struct CaptureVoiceOut CaptureVoiceOut;
 typedef struct SWVoiceIn SWVoiceIn;
 
+typedef struct AudioState AudioState;
 typedef struct QEMUSoundCard {
 char *name;
+AudioState *state;
 QLIST_ENTRY (QEMUSoundCard) entries;
 } QEMUSoundCard;
 
@@ -92,7 +94,8 @@ void AUD_log (const char *cap, const char *fmt, ...) 
GCC_FMT_ATTR(2, 3);
 
 void AUD_register_card (const char *name, QEMUSoundCard *card);
 void AUD_remove_card (QEMUSoundCard *card);
-CaptureVoiceOut *AUD_add_capture (
+CaptureVoiceOut *AUD_add_capture(
+AudioState *s,
 struct audsettings *as,
 struct audio_capture_ops *ops,
 void *opaque
@@ -160,8 +163,8 @@ static inline void *advance (void *p, int incr)
 #define audio_MAX(a, b) ((a)<(b)?(b):(a))
 #endif
 
-int wav_start_capture (CaptureState *s, const char *path, int freq,
-   int bits, int nchannels);
+int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
+  int freq, int bits, int nchannels);
 
 bool audio_is_cleaning_up(void);
 void audio_cleanup(void);
@@ -175,4 +178,7 @@ void audio_parse_option(const char *opt);
 void audio_init_audiodevs(void);
 void audio_legacy_help(void);
 
+AudioState *audio_state_by_name(const char *name);
+const char *audio_get_id(QEMUSoundCard *card);
+
 #endif /* QEMU_AUDIO_H */
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 8164696b2c..9f01f6ad00 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -196,6 +196,8 @@ typedef struct AudioState {
 
 bool timer_running;
 uint64_t timer_last;
+
+QTAILQ_ENTRY(AudioState) list;
 } AudioState;
 
 extern const struct mixeng_volume nominal_volume;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index c721fed75d..54f07338e7 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -428,7 +428,7 @@ SW *glue (AUD_open_, TYPE) (
 struct audsettings *as
 )
 {
-AudioState *s = _audio_state;
+AudioState *s = card->state;
 AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
 
 if (audio_bug(__func__, !card || !name || !callback_fn || !as)) {
diff --git a/audio/audio.c b/audio/audio.c
index 8d2f580788..4baa37caac 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -87,7 +87,8 @@ audio_driver *audio_driver_lookup(const char *name)
 return NULL;
 }
 
-static AudioState glob_audio_state;
+static QTAILQ_HEAD(AudioStateHead, AudioState) audio_states =
+QTAILQ_HEAD_INITIALIZER(audio_states);
 
 const struct mixeng_volume nominal_volume = {
 .mute = 0,
@@ -1236,11 +1237,14 @@ static void audio_run_capture (AudioState *s)
 
 void audio_run (const char *msg)
 {
-AudioState *s = _audio_state;
+AudioState *s;
+
+QTAILQ_FOREACH(s, _states, list) {
+audio_run_out(s);
+audio_run_in(s);
+audio_run_capture(s);
+}
 
-audio_run_out (s);
-audio_run_in (s);
-audio_run_capture (s);
 #ifdef DEBUG_POLL
 {
 static double prevtime;
@@ -1304,13 +1308,11 @@ bool audio_is_cleaning_up(void)
 return is_cleaning_up;
 }
 
-void audio_cleanup(void)
+static void free_audio_state(AudioState *s)
 {
-AudioState *s = _audio_state;
 HWVoiceOut *hwo, *hwon;
 HWVoiceIn *hwi, *hwin;
 
-is_cleaning_up = true;
 QLIST_FOREACH_SAFE(hwo, >hw_head_out, entries, hwon) {
 SWVoiceCap *sc;
 
@@ -1347,6 +1349,17 @@ void audio_cleanup(void)
 qapi_free_Audiodev(s->dev);
 s->dev = NULL;
 }
+g_free(s);
+}
+
+void audio_cleanup(void)
+{
+is_cleaning_up = true;
+while (!QTAILQ_EMPTY(_states)) {
+AudioState *s = QTAILQ_FIRST(_states);
+QTAILQ_REMOVE(_states, s, list);
+free_audio_state(s);
+}
 }
 
 static const VMStateDescription vmstate_audio = {
@@ -1373,28 +1386,33 @@ static AudiodevListEntry *audiodev_find(
 return NULL;
 }
 
-static int audio_init(Audiodev *dev)
+/*
+ * if we have dev, this function was called because of an -audiodev argument =>
+ *   initialize a new state with it
+ * if dev == NULL => legacy implicit initialization, return the already created
+ 

[Qemu-devel] [PATCH v2 00/14] Multiple simultaneous audio backends

2019-07-15 Thread Kővágó, Zoltán
Hello,

This is the v2 of my audio patches.  Copmpared to the previous version, the only
major change is the splitting of 2 commits ("basic support for multi backend
audio" and "audio: audiodev= parameters no longer optional when -audiodev
present") to ease review.

I also included a patch that fixes a memory leak reported by ASAN.

Regards,
Zoltan

Kővágó, Zoltán (14):
  audio: reduce glob_audio_state usage
  audio: basic support for multi backend audio
  audio: add audiodev property to vnc and wav_capture
  audio: add audiodev properties to frontends
  paaudio: prepare for multiple audiodev
  audio: audiodev= parameters no longer optional when -audiodev present
  paaudio: do not move stream when sink/source name is specified
  paaudio: properly disconnect streams in fini_*
  audio: remove audio_MIN, audio_MAX
  audio: do not run each backend in audio_run
  paaudio: fix playback glitches
  audio: remove read and write pcm_ops
  audio: use size_t where makes sense
  audio: fix memory leak reported by ASAN

 audio/audio.h|  36 +--
 audio/audio_int.h|  43 ++--
 audio/audio_template.h   |  62 +++--
 audio/mixeng.h   |   9 +-
 audio/rate_template.h|   2 +-
 include/hw/qdev-properties.h |   3 +
 include/sysemu/replay.h  |   4 +-
 ui/vnc.h |   2 +
 audio/alsaaudio.c|  49 ++--
 audio/audio.c| 345 ++---
 audio/coreaudio.c|  18 +-
 audio/dsoundaudio.c  |  25 +-
 audio/noaudio.c  |  39 +--
 audio/ossaudio.c |  75 +++---
 audio/paaudio.c  | 421 ++-
 audio/sdlaudio.c |  30 +--
 audio/spiceaudio.c   |  34 +--
 audio/wavaudio.c |  18 +-
 audio/wavcapture.c   |   6 +-
 hw/audio/ac97.c  |  11 +-
 hw/audio/adlib.c |   5 +-
 hw/audio/cs4231a.c   |   5 +-
 hw/audio/es1370.c|  13 +-
 hw/audio/gus.c   |   7 +-
 hw/audio/hda-codec.c |  17 +-
 hw/audio/milkymist-ac97.c|  14 +-
 hw/audio/pcspk.c |   3 +-
 hw/audio/pl041.c |   1 +
 hw/audio/sb16.c  |   3 +-
 hw/audio/wm8750.c|  10 +-
 hw/core/qdev-properties-system.c |  57 +
 hw/usb/dev-audio.c   |   1 +
 monitor/misc.c   |  12 +-
 replay/replay-audio.c|  16 +-
 replay/replay.c  |   2 +-
 ui/vnc.c |  15 +-
 hmp-commands.hx  |  13 +-
 qemu-options.hx  |   6 +
 38 files changed, 790 insertions(+), 642 deletions(-)

-- 
2.22.0




[Qemu-devel] [PATCH v2 01/14] audio: reduce glob_audio_state usage

2019-07-15 Thread Kővágó, Zoltán
Remove glob_audio_state from functions, where possible without breaking
the API.  This means that most static functions in audio.c now take an
AudioState pointer instead of implicitly using glob_audio_state.  Also
included a pointer in SWVoice*, HWVoice* structs, so that functions
dealing them can know the audio state without having to pass it around
separately.

This is required in order to support multiple simultaneous audio
backends (added in a later commit).

Signed-off-by: Kővágó, Zoltán 
Reviewed-by: Marc-André Lureau 
---
 audio/audio_int.h  |  8 ++
 audio/audio_template.h | 46 
 audio/audio.c  | 59 +++---
 3 files changed, 57 insertions(+), 56 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 3f14842709..8164696b2c 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -49,9 +49,11 @@ struct audio_pcm_info {
 int swap_endianness;
 };
 
+typedef struct AudioState AudioState;
 typedef struct SWVoiceCap SWVoiceCap;
 
 typedef struct HWVoiceOut {
+AudioState *s;
 int enabled;
 int poll_mode;
 int pending_disable;
@@ -73,6 +75,7 @@ typedef struct HWVoiceOut {
 } HWVoiceOut;
 
 typedef struct HWVoiceIn {
+AudioState *s;
 int enabled;
 int poll_mode;
 struct audio_pcm_info info;
@@ -94,6 +97,7 @@ typedef struct HWVoiceIn {
 
 struct SWVoiceOut {
 QEMUSoundCard *card;
+AudioState *s;
 struct audio_pcm_info info;
 t_sample *conv;
 int64_t ratio;
@@ -111,6 +115,7 @@ struct SWVoiceOut {
 
 struct SWVoiceIn {
 QEMUSoundCard *card;
+AudioState *s;
 int active;
 struct audio_pcm_info info;
 int64_t ratio;
@@ -188,6 +193,9 @@ typedef struct AudioState {
 int nb_hw_voices_in;
 int vm_running;
 int64_t period_ticks;
+
+bool timer_running;
+uint64_t timer_last;
 } AudioState;
 
 extern const struct mixeng_volume nominal_volume;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 1232bb54db..c721fed75d 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -36,9 +36,9 @@
 #define HWBUF hw->conv_buf
 #endif
 
-static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv)
+static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
+  struct audio_driver *drv)
 {
-AudioState *s = _audio_state;
 int max_voices = glue (drv->max_voices_, TYPE);
 int voice_size = glue (drv->voice_size_, TYPE);
 
@@ -183,8 +183,8 @@ static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
 
 static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
 {
-AudioState *s = _audio_state;
 HW *hw = *hwp;
+AudioState *s = hw->s;
 
 if (!hw->sw_head.lh_first) {
 #ifdef DAC
@@ -199,15 +199,14 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
 }
 }
 
-static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw)
+static HW *glue(audio_pcm_hw_find_any_, TYPE)(AudioState *s, HW *hw)
 {
-AudioState *s = _audio_state;
 return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first;
 }
 
-static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (HW *hw)
+static HW *glue(audio_pcm_hw_find_any_enabled_, TYPE)(AudioState *s, HW *hw)
 {
-while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
+while ((hw = glue(audio_pcm_hw_find_any_, TYPE)(s, hw))) {
 if (hw->enabled) {
 return hw;
 }
@@ -215,12 +214,10 @@ static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) 
(HW *hw)
 return NULL;
 }
 
-static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
-HW *hw,
-struct audsettings *as
-)
+static HW *glue(audio_pcm_hw_find_specific_, TYPE)(AudioState *s, HW *hw,
+   struct audsettings *as)
 {
-while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
+while ((hw = glue(audio_pcm_hw_find_any_, TYPE)(s, hw))) {
 if (audio_pcm_info_eq (>info, as)) {
 return hw;
 }
@@ -228,10 +225,10 @@ static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
 return NULL;
 }
 
-static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
+static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
+ struct audsettings *as)
 {
 HW *hw;
-AudioState *s = _audio_state;
 struct audio_driver *drv = s->drv;
 
 if (!glue (s->nb_hw_voices_, TYPE)) {
@@ -255,6 +252,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct 
audsettings *as)
 return NULL;
 }
 
+hw->s = s;
 hw->pcm_ops = drv->pcm_ops;
 hw->ctl_caps = drv->ctl_caps;
 
@@ -328,33 +326,33 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, 
TYPE)(Audiodev *dev)
 abort();
 }
 
-static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as)
+static HW *glue(audio_pcm_hw_add_, TYPE)(AudioState *s, struct audsettings *as)
 {
 HW *hw;
-AudioState *s = _audio_state;
 

[Qemu-devel] [PATCH v2 04/14] audio: add audiodev properties to frontends

2019-07-15 Thread Kővágó, Zoltán
Finally add audiodev= options to audio frontends so users can specify
which backend to use when multiple backends exist.  Not specifying an
audiodev= option currently causes the first audiodev to be used, this is
fixed in the next commit.

Example usage: -audiodev pa,id=foo -device AC97,audiodev=foo

Signed-off-by: Kővágó, Zoltán 
Reviewed-by: Marc-André Lureau 
---
 audio/audio.h|  3 ++
 include/hw/qdev-properties.h |  3 ++
 hw/audio/ac97.c  |  1 +
 hw/audio/adlib.c |  1 +
 hw/audio/cs4231a.c   |  1 +
 hw/audio/es1370.c|  7 +++-
 hw/audio/gus.c   |  1 +
 hw/audio/hda-codec.c |  1 +
 hw/audio/milkymist-ac97.c|  6 
 hw/audio/pcspk.c |  1 +
 hw/audio/pl041.c |  1 +
 hw/audio/sb16.c  |  1 +
 hw/audio/wm8750.c|  6 
 hw/core/qdev-properties-system.c | 57 
 hw/usb/dev-audio.c   |  1 +
 15 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/audio/audio.h b/audio/audio.h
index ad2457f4de..c0722a5cda 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -181,4 +181,7 @@ void audio_legacy_help(void);
 AudioState *audio_state_by_name(const char *name);
 const char *audio_get_id(QEMUSoundCard *card);
 
+#define DEFINE_AUDIO_PROPERTIES(_s, _f) \
+DEFINE_PROP_AUDIODEV("audiodev", _s, _f)
+
 #endif /* QEMU_AUDIO_H */
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 1eae5ab056..de0b2c8423 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -35,6 +35,7 @@ extern const PropertyInfo qdev_prop_blocksize;
 extern const PropertyInfo qdev_prop_pci_host_devaddr;
 extern const PropertyInfo qdev_prop_uuid;
 extern const PropertyInfo qdev_prop_arraylen;
+extern const PropertyInfo qdev_prop_audiodev;
 extern const PropertyInfo qdev_prop_link;
 extern const PropertyInfo qdev_prop_off_auto_pcibar;
 extern const PropertyInfo qdev_prop_pcie_link_speed;
@@ -236,6 +237,8 @@ extern const PropertyInfo qdev_prop_pcie_link_width;
 + type_check(QemuUUID, typeof_field(_state, _field)),  \
 .set_default = true,   \
 }
+#define DEFINE_PROP_AUDIODEV(_n, _s, _f) \
+DEFINE_PROP(_n, _s, _f, qdev_prop_audiodev, QEMUSoundCard)
 
 #define DEFINE_PROP_END_OF_LIST()   \
 {}
diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c
index fb98da2678..0d8e524233 100644
--- a/hw/audio/ac97.c
+++ b/hw/audio/ac97.c
@@ -1409,6 +1409,7 @@ static int ac97_init (PCIBus *bus)
 }
 
 static Property ac97_properties[] = {
+DEFINE_AUDIO_PROPERTIES(AC97LinkState, card),
 DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0),
 DEFINE_PROP_END_OF_LIST (),
 };
diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c
index 7dd9a89b89..df2e781788 100644
--- a/hw/audio/adlib.c
+++ b/hw/audio/adlib.c
@@ -299,6 +299,7 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
 }
 
 static Property adlib_properties[] = {
+DEFINE_AUDIO_PROPERTIES(AdlibState, card),
 DEFINE_PROP_UINT32 ("iobase",  AdlibState, port, 0x220),
 DEFINE_PROP_UINT32 ("freq",AdlibState, freq,  44100),
 DEFINE_PROP_END_OF_LIST (),
diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c
index 7216b41cc1..e3ea830b47 100644
--- a/hw/audio/cs4231a.c
+++ b/hw/audio/cs4231a.c
@@ -689,6 +689,7 @@ static int cs4231a_init (ISABus *bus)
 }
 
 static Property cs4231a_properties[] = {
+DEFINE_AUDIO_PROPERTIES(CSState, card),
 DEFINE_PROP_UINT32 ("iobase",  CSState, port, 0x534),
 DEFINE_PROP_UINT32 ("irq", CSState, irq,  9),
 DEFINE_PROP_UINT32 ("dma", CSState, dma,  3),
diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index 260c142b70..7589671d20 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -887,6 +887,11 @@ static int es1370_init (PCIBus *bus)
 return 0;
 }
 
+static Property es1370_properties[] = {
+DEFINE_AUDIO_PROPERTIES(ES1370State, card),
+DEFINE_PROP_END_OF_LIST(),
+};
+
 static void es1370_class_init (ObjectClass *klass, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS (klass);
@@ -903,6 +908,7 @@ static void es1370_class_init (ObjectClass *klass, void 
*data)
 dc->desc = "ENSONIQ AudioPCI ES1370";
 dc->vmsd = _es1370;
 dc->reset = es1370_on_reset;
+dc->props = es1370_properties;
 }
 
 static const TypeInfo es1370_info = {
@@ -923,4 +929,3 @@ static void es1370_register_types (void)
 }
 
 type_init (es1370_register_types)
-
diff --git a/hw/audio/gus.c b/hw/audio/gus.c
index 9ab51631d9..566864bc9e 100644
--- a/hw/audio/gus.c
+++ b/hw/audio/gus.c
@@ -297,6 +297,7 @@ static int GUS_init (ISABus *bus)
 }
 
 static Property gus_properties[] = {
+DEFINE_AUDIO_PROPERTIES(GUSState, card),
 DEFINE_PROP_UINT32 ("freq",GUSState, freq,44100),
 DEFINE_PROP_UINT32 ("iobase",  GUSState, port,0x240),
 

[Qemu-devel] [PATCH v2 03/14] audio: add audiodev property to vnc and wav_capture

2019-07-15 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 ui/vnc.h|  2 ++
 monitor/misc.c  | 12 +++-
 ui/vnc.c| 15 ++-
 hmp-commands.hx | 13 -
 qemu-options.hx |  6 ++
 5 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/ui/vnc.h b/ui/vnc.h
index 2f84db3142..6f54653455 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -183,6 +183,8 @@ struct VncDisplay
 #ifdef CONFIG_VNC_SASL
 VncDisplaySASL sasl;
 #endif
+
+AudioState *audio_state;
 };
 
 typedef struct VncTight {
diff --git a/monitor/misc.c b/monitor/misc.c
index e39a0e..f97810d370 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -1148,7 +1148,17 @@ static void hmp_wavcapture(Monitor *mon, const QDict 
*qdict)
 int bits = qdict_get_try_int(qdict, "bits", -1);
 int has_channels = qdict_haskey(qdict, "nchannels");
 int nchannels = qdict_get_try_int(qdict, "nchannels", -1);
+const char *audiodev = qdict_get_try_str(qdict, "audiodev");
 CaptureState *s;
+AudioState *as = NULL;
+
+if (audiodev) {
+as = audio_state_by_name(audiodev);
+if (!as) {
+monitor_printf(mon, "Invalid audiodev specified\n");
+return;
+}
+}
 
 s = g_malloc0 (sizeof (*s));
 
@@ -1156,7 +1166,7 @@ static void hmp_wavcapture(Monitor *mon, const QDict 
*qdict)
 bits = has_bits ? bits : 16;
 nchannels = has_channels ? nchannels : 2;
 
-if (wav_start_capture(NULL, s, path, freq, bits, nchannels)) {
+if (wav_start_capture(as, s, path, freq, bits, nchannels)) {
 monitor_printf(mon, "Failed to add wave capture\n");
 g_free (s);
 return;
diff --git a/ui/vnc.c b/ui/vnc.c
index 140f364dda..24f9be5b5d 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1222,7 +1222,7 @@ static void audio_add(VncState *vs)
 ops.destroy = audio_capture_destroy;
 ops.capture = audio_capture;
 
-vs->audio_cap = AUD_add_capture(NULL, >as, , vs);
+vs->audio_cap = AUD_add_capture(vs->vd->audio_state, >as, , vs);
 if (!vs->audio_cap) {
 error_report("Failed to add audio capture");
 }
@@ -3369,6 +3369,9 @@ static QemuOptsList qemu_vnc_opts = {
 },{
 .name = "non-adaptive",
 .type = QEMU_OPT_BOOL,
+},{
+.name = "audiodev",
+.type = QEMU_OPT_STRING,
 },
 { /* end of list */ }
 },
@@ -3806,6 +3809,7 @@ void vnc_display_open(const char *id, Error **errp)
 const char *saslauthz;
 int lock_key_sync = 1;
 int key_delay_ms;
+const char *audiodev;
 
 if (!vd) {
 error_setg(errp, "VNC display not active");
@@ -3991,6 +3995,15 @@ void vnc_display_open(const char *id, Error **errp)
 }
 vd->ledstate = 0;
 
+audiodev = qemu_opt_get(opts, "audiodev");
+if (audiodev) {
+vd->audio_state = audio_state_by_name(audiodev);
+if (!vd->audio_state) {
+error_setg(errp, "Audiodev '%s' not found", audiodev);
+goto fail;
+}
+}
+
 device_id = qemu_opt_get(opts, "display");
 if (device_id) {
 int head = qemu_opt_get_number(opts, "head", 0);
diff --git a/hmp-commands.hx b/hmp-commands.hx
index bfa5681dd2..fa7f009268 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -819,16 +819,19 @@ ETEXI
 
 {
 .name   = "wavcapture",
-.args_type  = "path:F,freq:i?,bits:i?,nchannels:i?",
-.params = "path [frequency [bits [channels]]]",
+.args_type  = "path:F,freq:i?,bits:i?,nchannels:i?,audiodev:s?",
+.params = "path [frequency [bits [channels [audiodev",
 .help   = "capture audio to a wave file (default frequency=44100 
bits=16 channels=2)",
 .cmd= hmp_wavcapture,
 },
 STEXI
-@item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels}]]]
+@item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels} 
[@var{audiodev}
 @findex wavcapture
-Capture audio into @var{filename}. Using sample rate @var{frequency}
-bits per sample @var{bits} and number of channels @var{channels}.
+Capture audio into @var{filename} from @var{audiodev}, using sample rate
+@var{frequency} bits per sample @var{bits} and number of channels
+@var{channels}. When not using an -audiodev argument on command line,
+@var{audiodev} must be omitted, otherwise is must specify a valid
+audiodev.
 
 Defaults:
 @itemize @minus
diff --git a/qemu-options.hx b/qemu-options.hx
index 9621e934c0..a308e5f5aa 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1978,6 +1978,12 @@ can help the device and guest to keep up and not lose 
events in case
 events are arriving in bulk.  Possible causes for the latter are flaky
 network connections, or scripts for automated testing.
 
+@item audiodev=@var{audiodev}
+
+Use the specified @var{audiodev} when the VNC client requests audio
+transmission. When not using an -audiodev argument, this option must
+be omitted, otherwise is must be present and specify a valid 

[Qemu-devel] [PULL 2/3] target/mips: Add missing 'break' for certain cases of MFTR handling

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

This was found by GCC 8.3 static analysis.

Fixes: ead9360e2fb

Reported-by: Stefan Weil 
Reviewed-by: Philippe Mathieu-Daudé 
Tested-by: Philippe Mathieu-Daudé 
Signed-off-by: Aleksandar Markovic 
Message-Id: <1563220847-14630-4-git-send-email-aleksandar.marko...@rt-rk.com>
---
 target/mips/translate.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index cce1f12..b4898d5 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -9826,6 +9826,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext 
*ctx, int rt, int rd,
 gen_mfc0(ctx, t0, rt, sel);
 break;
 }
+break;
 case 12:
 switch (sel) {
 case 0:
@@ -9835,6 +9836,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext 
*ctx, int rt, int rd,
 gen_mfc0(ctx, t0, rt, sel);
 break;
 }
+break;
 case 13:
 switch (sel) {
 case 0:
-- 
2.7.4




[Qemu-devel] [PULL 3/3] target/mips: Add missing 'break' for certain cases of MTTR handling

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

This was found by GCC 8.3 static analysis.

Fixes: ead9360e2fb

Reported-by: Stefan Weil 
Reviewed-by: Philippe Mathieu-Daudé 
Tested-by: Philippe Mathieu-Daudé 
Signed-off-by: Aleksandar Markovic 
Message-Id: <1563220847-14630-5-git-send-email-aleksandar.marko...@rt-rk.com>
---
 target/mips/translate.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index b4898d5..3575eff 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -10055,6 +10055,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext 
*ctx, int rd, int rt,
 gen_mtc0(ctx, t0, rd, sel);
 break;
 }
+break;
 case 12:
 switch (sel) {
 case 0:
@@ -10064,6 +10065,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext 
*ctx, int rd, int rt,
 gen_mtc0(ctx, t0, rd, sel);
 break;
 }
+break;
 case 13:
 switch (sel) {
 case 0:
-- 
2.7.4




[Qemu-devel] [PULL 1/3] target/mips: Add missing 'break' for a case of MTHC0 handling

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

This was found by GCC 8.3 static analysis.

Fixes: 5fb2dcd1792

Reported-by: Stefan Weil 
Reviewed-by: Philippe Mathieu-Daudé 
Tested-by: Philippe Mathieu-Daudé 
Signed-off-by: Aleksandar Markovic 
Message-Id: <1563220847-14630-3-git-send-email-aleksandar.marko...@rt-rk.com>
---
 target/mips/translate.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index f96f141..cce1f12 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -6745,6 +6745,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int 
reg, int sel)
 default:
 goto cp0_unimplemented;
 }
+break;
 case CP0_REGISTER_17:
 switch (sel) {
 case 0:
-- 
2.7.4




[Qemu-devel] [PULL 0/3] MIPS queue for July 15th, 2019

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

The following changes since commit 5ea8ec2fcf57cb9af24ad2cf17b4d64adb03afdf:

  Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2019-07-15' 
into staging (2019-07-15 16:11:47 +0100)

are available in the git repository at:

  https://github.com/AMarkovic/qemu tags/mips-queue-jul-15-2019

for you to fetch changes up to 0d0304f2c4967c892a3216638fc4cb078afa2b44:

  target/mips: Add missing 'break' for certain cases of MTTR handling 
(2019-07-15 22:22:05 +0200)



MIPS queue for July 15th, 2019

Notes:

  - two patches from the serieas 'MIPS fixes for 4.1' did not get
  reviewed on time to be included for 4.1 rc1, so they are left
  possibly for 4.1 rc2

Highlights:

  - fixes for missing 'break' in switch statements



Aleksandar Markovic (3):
  target/mips: Add missing 'break' for a case of MTHC0 handling
  target/mips: Add missing 'break' for certain cases of MFTR handling
  target/mips: Add missing 'break' for certain cases of MTTR handling

 target/mips/translate.c | 5 +
 1 file changed, 5 insertions(+)

-- 
2.7.4




[Qemu-devel] [PATCH 2/3] block/io_uring: fix EINTR request resubmission

2019-07-15 Thread Stefan Hajnoczi
Adding the request to sq_overflow isn't enough:
1. luringcb->sqeq is uninitialized if there was space in the sq ring at
   submission time.
2. Not all code paths invoke ioq_submit() after processing completions,
   so the request could hang.

Additional bugs include checking for EINTR instead of -EINTR and
forgetting to skip the completion callback when a request is
resubmitted.

Fix this by always initializing luringcb->sqeq and ensuring that all
code paths invoke ioq_submit() after appending to sq_overflow.  Ensure
that luring_process_completions() marks the cqe seen and decrements
in_flight before resubmitting the request.

Signed-off-by: Stefan Hajnoczi 
---
 block/io_uring.c | 64 
 1 file changed, 37 insertions(+), 27 deletions(-)

diff --git a/block/io_uring.c b/block/io_uring.c
index 19919da4c9..97e4f876d7 100644
--- a/block/io_uring.c
+++ b/block/io_uring.c
@@ -87,6 +87,18 @@ int luring_register_fd(LuringState *s, unsigned int fd)
  s->fd.head, s->fd.size);
 }
 
+/**
+ * luring_resubmit:
+ *
+ * Resubmit a request by appending it to sq_overflow.  The caller must ensure
+ * that ioq_submit() is called later so that sq_overflow requests are started.
+ */
+static void luring_resubmit(LuringState *s, LuringAIOCB *luringcb)
+{
+QSIMPLEQ_INSERT_TAIL(>io_q.sq_overflow, luringcb, next);
+s->io_q.in_queue++;
+}
+
 /**
  * luring_process_completions:
  * @s: AIO state
@@ -102,7 +114,6 @@ int luring_register_fd(LuringState *s, unsigned int fd)
 static void luring_process_completions(LuringState *s)
 {
 struct io_uring_cqe *cqes;
-int ret;
 
 /*
  * Request completion callbacks can run the nested event loop.
@@ -122,11 +133,20 @@ static void luring_process_completions(LuringState *s)
 qemu_bh_schedule(s->completion_bh);
 
 while (io_uring_peek_cqe(>ring, ) == 0) {
+LuringAIOCB *luringcb;
+int ret;
+
 if (!cqes) {
 break;
 }
-LuringAIOCB *luringcb = io_uring_cqe_get_data(cqes);
+
+luringcb = io_uring_cqe_get_data(cqes);
 ret = cqes->res;
+io_uring_cqe_seen(>ring, cqes);
+cqes = NULL;
+
+/* Change counters one-by-one because we can be nested. */
+s->io_q.in_flight--;
 
 trace_luring_process_completion(s, luringcb, ret);
 
@@ -143,17 +163,12 @@ static void luring_process_completions(LuringState *s)
 ret = -ENOSPC;;
 }
 /* Add to overflow queue to be resubmitted later */
-} else if (ret == EINTR) {
-QSIMPLEQ_INSERT_TAIL(>io_q.sq_overflow, luringcb, next);
+} else if (ret == -EINTR) {
+luring_resubmit(s, luringcb);
+continue;
 }
 luringcb->ret = ret;
 
-
-io_uring_cqe_seen(>ring, cqes);
-cqes = NULL;
-/* Change counters one-by-one because we can be nested. */
-s->io_q.in_flight--;
-
 /*
  * If the coroutine is already entered it must be in ioq_submit()
  * and will notice luringcb->ret has been filled in when it
@@ -245,16 +260,16 @@ static int ioq_submit(LuringState *s)
 }
 s->io_q.in_flight += ret;
 s->io_q.in_queue  -= ret;
+
+if (s->io_q.in_flight) {
+/*
+ * We can try to complete something just right away if there are
+ * still requests in-flight.
+ */
+luring_process_completions(s);
+}
 }
 s->io_q.blocked = (s->io_q.in_queue > 0);
-
-if (s->io_q.in_flight) {
-/*
- * We can try to complete something just right away if there are
- * still requests in-flight.
- */
-luring_process_completions(s);
-}
 return ret;
 }
 
@@ -290,15 +305,7 @@ static int luring_do_submit(int fd, LuringAIOCB *luringcb, 
LuringState *s,
 uint64_t offset, int type)
 {
 int ret;
-struct io_uring_sqe *sqes = io_uring_get_sqe(>ring);
-/* 
- *If the ring is full and cannot fetch new sqes, add the request to
- * to an overflow queue to be submitted later
- */
-if (!sqes) {
-sqes = >sqeq;
-QSIMPLEQ_INSERT_TAIL(>io_q.sq_overflow, luringcb, next);
-}
+struct io_uring_sqe *sqes = >sqeq;
 
 switch (type) {
 case QEMU_AIO_WRITE:
@@ -318,7 +325,10 @@ static int luring_do_submit(int fd, LuringAIOCB *luringcb, 
LuringState *s,
 abort();
 }
 io_uring_sqe_set_data(sqes, luringcb);
+
+QSIMPLEQ_INSERT_TAIL(>io_q.sq_overflow, luringcb, next);
 s->io_q.in_queue++;
+
 trace_luring_do_submit(s, s->io_q.blocked, s->io_q.plugged,
s->io_q.in_queue, s->io_q.in_flight);
 if (!s->io_q.blocked &&
-- 
2.21.0




[Qemu-devel] [PATCH 1/3] block/io_uring: add submission and completion trace events

2019-07-15 Thread Stefan Hajnoczi
It is useful to follow individual requests as they are submitted.  Add
trace events that show details of each request.

Signed-off-by: Stefan Hajnoczi 
---
 block/io_uring.c   | 5 +
 block/trace-events | 3 +++
 2 files changed, 8 insertions(+)

diff --git a/block/io_uring.c b/block/io_uring.c
index 22e8d3d9ca..19919da4c9 100644
--- a/block/io_uring.c
+++ b/block/io_uring.c
@@ -128,6 +128,8 @@ static void luring_process_completions(LuringState *s)
 LuringAIOCB *luringcb = io_uring_cqe_get_data(cqes);
 ret = cqes->res;
 
+trace_luring_process_completion(s, luringcb, ret);
+
 if (ret == luringcb->qiov->size) {
 ret = 0;
 } else if (ret >= 0) {
@@ -233,6 +235,7 @@ static int ioq_submit(LuringState *s)
 QSIMPLEQ_REMOVE_HEAD(>io_q.sq_overflow, next);
 }
 ret = io_uring_submit(>ring);
+trace_luring_io_uring_submit(s, ret);
 /* Prevent infinite loop if submission is refused */
 if (ret <= 0) {
 if (ret == -EAGAIN) {
@@ -339,6 +342,8 @@ int coroutine_fn luring_co_submit(BlockDriverState *bs, 
LuringState *s, int fd,
 .is_read= (type == QEMU_AIO_READ),
 };
 
+trace_luring_co_submit(bs, s, , fd, offset, qiov ? qiov->size : 
0, type);
+
 ret = luring_do_submit(fd, , s, offset, type);
 if (ret < 0) {
 return ret;
diff --git a/block/trace-events b/block/trace-events
index 069779773b..02952fe4cb 100644
--- a/block/trace-events
+++ b/block/trace-events
@@ -67,6 +67,9 @@ luring_io_plug(void *s) "LuringState %p plug"
 luring_io_unplug(void *s, int blocked, int plugged, int queued, int inflight) 
"LuringState %p blocked %d plugged %d queued %d inflight %d"
 luring_do_submit(void *s, int blocked, int plugged, int queued, int inflight) 
"LuringState %p blocked %d plugged %d queued %d inflight %d"
 luring_do_submit_done(void *s, int ret) "LuringState %p submitted to kernel %d"
+luring_co_submit(void *bs, void *s, void *luringcb, int fd, uint64_t offset, 
size_t nbytes, int type) "bs %p s %p luringcb %p fd %d offset %" PRId64 " 
nbytes %zd type %d"
+luring_process_completion(void *s, void *aiocb, int ret) "LuringState %p 
luringcb %p ret %d"
+luring_io_uring_submit(void *s, int ret) "LuringState %p ret %d"
 
 # qcow2.c
 qcow2_writev_start_req(void *co, int64_t offset, int bytes) "co %p offset 0x%" 
PRIx64 " bytes %d"
-- 
2.21.0




[Qemu-devel] [PATCH 3/3] block/io_uring: resubmit short buffered reads

2019-07-15 Thread Stefan Hajnoczi
The io_uring API had unusual read behavior up until recently, where
short reads could occur when the start of the file range was in the page
cache and a later portion was not in the page cache.  Normally read(2)
does not expose this detail to applications and this behavior has been
fixed in Linux commit 9d93a3f5a0c ("io_uring: punt short reads to async
* context").

In the meantime Linux distros have shipped kernels where io_uring
exhibits the old behavior and there is no simple way to detect it.

Add a slow path for resubmitting short read requests.  The idea is
simple: shorten the iovecs and increment the file offset each time a
short read occurs and then resubmit the request.  The implementation
requires adding additional fields to LuringAIOCB to keep track of where
we were.

Signed-off-by: Stefan Hajnoczi 
---
 block/io_uring.c   | 75 +++---
 block/trace-events |  3 +-
 2 files changed, 67 insertions(+), 11 deletions(-)

diff --git a/block/io_uring.c b/block/io_uring.c
index 97e4f876d7..12cef71175 100644
--- a/block/io_uring.c
+++ b/block/io_uring.c
@@ -28,6 +28,12 @@ typedef struct LuringAIOCB {
 QEMUIOVector *qiov;
 bool is_read;
 QSIMPLEQ_ENTRY(LuringAIOCB) next;
+
+/* Buffered reads may require resubmission, see
+ * luring_resubmit_short_read().
+ */
+int total_read;
+QEMUIOVector resubmit_qiov;
 } LuringAIOCB;
 
 typedef struct LuringQueue {
@@ -99,6 +105,43 @@ static void luring_resubmit(LuringState *s, LuringAIOCB 
*luringcb)
 s->io_q.in_queue++;
 }
 
+/* Before Linux commit 9d93a3f5a0c ("io_uring: punt short reads to async
+ * context") a buffered I/O request with the start of the file range in the
+ * page cache could result in a short read.  Applications need to resubmit the
+ * remaining read request.
+ *
+ * This is a slow path but recent kernels never take it.
+ */
+static void luring_resubmit_short_read(LuringState *s, LuringAIOCB *luringcb,
+   int nread)
+{
+QEMUIOVector *resubmit_qiov;
+size_t remaining;
+
+trace_luring_resubmit_short_read(s, luringcb, nread);
+
+/* Update read position */
+luringcb->total_read += nread;
+remaining = luringcb->qiov->size - luringcb->total_read;
+
+/* Shorten qiov */
+resubmit_qiov = >resubmit_qiov;
+if (resubmit_qiov->iov == NULL) {
+qemu_iovec_init(resubmit_qiov, luringcb->qiov->niov);
+} else {
+qemu_iovec_reset(resubmit_qiov);
+}
+qemu_iovec_concat(resubmit_qiov, luringcb->qiov, luringcb->total_read,
+  remaining);
+
+/* Update sqe */
+luringcb->sqeq.off += nread;
+luringcb->sqeq.addr = (__u64)(uintptr_t)luringcb->resubmit_qiov.iov;
+luringcb->sqeq.len = luringcb->resubmit_qiov.niov;
+
+luring_resubmit(s, luringcb);
+}
+
 /**
  * luring_process_completions:
  * @s: AIO state
@@ -135,6 +178,7 @@ static void luring_process_completions(LuringState *s)
 while (io_uring_peek_cqe(>ring, ) == 0) {
 LuringAIOCB *luringcb;
 int ret;
+int total_bytes;
 
 if (!cqes) {
 break;
@@ -150,25 +194,36 @@ static void luring_process_completions(LuringState *s)
 
 trace_luring_process_completion(s, luringcb, ret);
 
-if (ret == luringcb->qiov->size) {
+/* total_read is non-zero only for resubmitted read requests */
+total_bytes = ret + luringcb->total_read;
+
+if (ret < 0) {
+if (ret == -EINTR) {
+luring_resubmit(s, luringcb);
+continue;
+}
+} else if (total_bytes == luringcb->qiov->size) {
 ret = 0;
-} else if (ret >= 0) {
+} else {
 /* Short Read/Write */
 if (luringcb->is_read) {
-/* Read, pad with zeroes */
-qemu_iovec_memset(luringcb->qiov, ret, 0,
-luringcb->qiov->size - ret);
-ret = 0;
+if (ret > 0) {
+luring_resubmit_short_read(s, luringcb, ret);
+continue;
+} else {
+/* Pad with zeroes */
+qemu_iovec_memset(luringcb->qiov, total_bytes, 0,
+  luringcb->qiov->size - total_bytes);
+ret = 0;
+}
 } else {
 ret = -ENOSPC;;
 }
-/* Add to overflow queue to be resubmitted later */
-} else if (ret == -EINTR) {
-luring_resubmit(s, luringcb);
-continue;
 }
 luringcb->ret = ret;
 
+qemu_iovec_destroy(>resubmit_qiov);
+
 /*
  * If the coroutine is already entered it must be in ioq_submit()
  * and will notice luringcb->ret has been filled in when it
diff --git a/block/trace-events b/block/trace-events
index 02952fe4cb..f434cac634 100644
--- a/block/trace-events
+++ b/block/trace-events
@@ 

[Qemu-devel] [PATCH 0/3] block/io_uring: fix EINTR and resubmit short reads

2019-07-15 Thread Stefan Hajnoczi
Short reads are possible with cache=writeback (see Patch 3 for details).
Handle this by resubmitting requests until the read is completed.

Patch 1 adds trace events useful for debugging io_uring.

Patch 2 fixes EINTR.  This lays the groundwork for resubmitting requests in
Patch 3.

Aarushi: Feel free to squash this into your patch series if you are happy with
the code, I don't mind if the authorship information is lost.  After applying
these patches I can successfully boot a Fedora 30 guest qcow2 file with
cache=writeback.

Based-on: <20190610134905.22294-1-mehta.aar...@gmail.com>

Stefan Hajnoczi (3):
  block/io_uring: add submission and completion trace events
  block/io_uring: fix EINTR request resubmission
  block/io_uring: resubmit short buffered reads

 block/io_uring.c   | 136 ++---
 block/trace-events |   6 +-
 2 files changed, 108 insertions(+), 34 deletions(-)

-- 
2.21.0




Re: [Qemu-devel] [PATCH v4 00/18] bitmaps: introduce 'bitmap' sync mode

2019-07-15 Thread John Snow



On 7/9/19 7:25 PM, John Snow wrote:
> This series adds a new "BITMAP" sync mode that is meant to replace the
> existing "INCREMENTAL" sync mode.
> 
> This mode can have its behavior modified by issuing any of three bitmap sync
> modes, passed as arguments to the job.
> 
> The three bitmap sync modes are:
> - ON-SUCCESS: This is an alias for the old incremental mode. The bitmap is
>   conditionally synchronized based on the return code of the job
>   upon completion.
> - NEVER: This is, effectively, the differential backup mode. It never clears
>  the bitmap, as the name suggests.
> - ALWAYS: Here is the new, exciting thing. The bitmap is always synchronized,
>   even on failure. On success, this is identical to incremental, but
>   on failure it clears only the bits that were copied successfully.
>   This can be used to "resume" incremental backups from later points
>   in times.
> 
> I wrote this series by accident on my way to implement incremental mode
> for mirror, but this happened first -- the problem is that Mirror mode
> uses its existing modes in a very particular way; and this was the best
> way to add bitmap support into the mirror job properly.
> 
> Summary:
> - 01-03: refactor blockdev-backup and drive-backup to share more interface 
> code
> - 04-05: add the new 'bitmap' sync mode with sync policy 'conditional',
>  which is functionally identical to 'incremental' sync mode.
> - 06:add sync policy 'never' ("Differential" backups.)
> - 07-11: rework some merging code to facilite patch 12;
> - 12:add sync policy 'always' ("Resumable" backups)
> - 13-16: test infrastructure changes to support patch 16:
> - 17:new iotest!
> - 18:minor policy loosening as a QOL improvement
> 
> Future work:
>  - Update bitmaps.rst to explain these. (WIP, it's hard, sorry!)
>  - Add these modes to Mirror. (Done*, but needs tests.)
>  - Allow the use of bitmaps and bitmap sync modes with non-BITMAP modes;
>This will allow for resumable/re-tryable full backups.
> 
> ===
> V4:
> ===
> 
> [] : patches are identical
> [] : number of functional differences between upstream/downstream patch
> [down] : patch is downstream-only
> The flags [FC] indicate (F)unctional and (C)ontextual differences, 
> respectively
> 
> 001/18:[] [--] 'qapi/block-core: Introduce BackupCommon'
> 002/18:[] [--] 'drive-backup: create do_backup_common'
> 003/18:[] [--] 'blockdev-backup: utilize do_backup_common'
> 004/18:[] [--] 'qapi: add BitmapSyncMode enum'
> 005/18:[] [--] 'block/backup: Add mirror sync mode 'bitmap''
> 006/18:[] [--] 'block/backup: add 'never' policy to bitmap sync mode'
> 007/18:[] [--] 'hbitmap: Fix merge when b is empty, and result is not an 
> alias of a'
> 008/18:[] [--] 'hbitmap: enable merging across granularities'
> 009/18:[0004] [FC] 'block/dirty-bitmap: add bdrv_dirty_bitmap_merge_internal'
> 010/18:[] [--] 'block/dirty-bitmap: add bdrv_dirty_bitmap_get'
> 011/18:[0008] [FC] 'block/backup: upgrade copy_bitmap to BdrvDirtyBitmap'
> 012/18:[] [--] 'block/backup: add 'always' bitmap sync policy'
> 013/18:[] [--] 'iotests: add testing shim for script-style python tests'
> 014/18:[] [--] 'iotests: teach run_job to cancel pending jobs'
> 015/18:[] [--] 'iotests: teach FilePath to produce multiple paths'
> 016/18:[] [--] 'iotests: Add virtio-scsi device helper'
> 017/18:[0063] [FC] 'iotests: add test 257 for bitmap-mode backups'
> 018/18:[] [--] 'block/backup: loosen restriction on readonly bitmaps'
> 
> Changes:
> 009: Added assertions.
> 011: Moved copy bitmap to source node.
> 017: Rework get_bitmap to tolerate multiple anonymous bitmaps
>  Update test output to accommodate the same.
> 
> ===
> V3:
> ===
> 
> Changes:
> 001: Made suggested doc fixes.
>  Changed 'since' to 4.2.
> 002: Added bds and aio_context to backup_common
>  Removed accidental extraneous unref on target_bs
>  Removed local_err propagation
> 003: Fallout from #002; hoist aio_context acquisition up into 
> do_blockdev_backup
> 004: 'conditional' --> 'on-success'
> 005: Rediscover the lost stanza that ensures a bitmap mode was given
>  Fallout from 2, 3, 4.
> 006: Block comment fix for patchew
>  Fallout from #4
> 009: Fix assert() style issue. Why'd they let a macro be lowercase like that?
>  Probably to make specifically my life difficult.
> 010: Fix style issue {
> 011: Fix long lines
>  rename "bs" --> "target_bs" where appropriate
>  Free copy_bitmap from the right node
> 012: Multiline comment changes for patchew
>  Fallout from #4
> 015: Fix long line for patchew
>  Reinstate that second newline that Max likes
> 017: Fallout from #4.
> 
> ===
> V2:
> ===
> 
> Changes:
> 004: Fixed typo
>  Change @conditional docstring
> 005: Moved desugaring code into blockdev.c, facilitated by patches 1-3.
> 006: Change @never docstring slightly.
> 007: 

[Qemu-devel] [PATCH for 4.1 v4 0/5] target/mips: Fixes for 4.1 rc1

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

At the moment, this includes fixes for problems in switch statements
found by GCC 8.3 improved code analysis features, and one big endian
host fix.

v3->v4:

  - complete the last patch

v2->v3:

  - fix handling of MSA pack instructions on big endian host

v1->v2:

  - excluded the patch on "ucontext" that will go into linux user queue

Aleksandar Markovic (5):
  target/mips: Add 'fall through' comments for handling nanoMips' SHXS,
SWXS
  target/mips: Add missing 'break' for a case of MTHC0 handling
  target/mips: Add missing 'break' for certain cases of MFTR handling
  target/mips: Add missing 'break' for certain cases of MTTR handling
  target/mips: Fix emulation of MSA pack instructions on big endian
hosts

 target/mips/msa_helper.c | 74 
 target/mips/translate.c  |  7 +
 2 files changed, 81 insertions(+)

-- 
2.7.4




[Qemu-devel] [PATCH for 4.1 v4 3/5] target/mips: Add missing 'break' for certain cases of MFTR handling

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

This was found by GCC 8.3 static analysis.

Fixes: ead9360e2fb

Reported-by: Stefan Weil 
Reviewed-by: Philippe Mathieu-Daudé 
Tested-by: Philippe Mathieu-Daudé 
Signed-off-by: Aleksandar Markovic 
---
 target/mips/translate.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index 59d4acd..b1cf5f0 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -9826,6 +9826,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext 
*ctx, int rt, int rd,
 gen_mfc0(ctx, t0, rt, sel);
 break;
 }
+break;
 case 12:
 switch (sel) {
 case 0:
@@ -9835,6 +9836,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext 
*ctx, int rt, int rd,
 gen_mfc0(ctx, t0, rt, sel);
 break;
 }
+break;
 case 13:
 switch (sel) {
 case 0:
-- 
2.7.4




[Qemu-devel] [PATCH for 4.1 v4 5/5] target/mips: Fix emulation of MSA pack instructions on big endian hosts

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

Fix emulation of MSA pack instructions on big endian hosts.

Signed-off-by: Aleksandar Markovic 
---
 target/mips/msa_helper.c | 74 
 1 file changed, 74 insertions(+)

diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c
index a383c40..27560ac 100644
--- a/target/mips/msa_helper.c
+++ b/target/mips/msa_helper.c
@@ -2113,6 +2113,24 @@ void helper_msa_pckev_df(CPUMIPSState *env, uint32_t df, 
uint32_t wd,
 
 switch (df) {
 case DF_BYTE:
+#if defined(HOST_WORDS_BIGENDIAN)
+pwd->b[8]  = pws->b[9];
+pwd->b[10] = pws->b[13];
+pwd->b[12] = pws->b[1];
+pwd->b[14] = pws->b[5];
+pwd->b[0]  = pwt->b[9];
+pwd->b[2]  = pwt->b[13];
+pwd->b[4]  = pwt->b[1];
+pwd->b[6]  = pwt->b[5];
+pwd->b[9]  = pws->b[11];
+pwd->b[13] = pws->b[3];
+pwd->b[1]  = pwt->b[11];
+pwd->b[5]  = pwt->b[3];
+pwd->b[11] = pws->b[15];
+pwd->b[3]  = pwt->b[15];
+pwd->b[15] = pws->b[7];
+pwd->b[7]  = pwt->b[7];
+#else
 pwd->b[15] = pws->b[14];
 pwd->b[13] = pws->b[10];
 pwd->b[11] = pws->b[6];
@@ -2129,8 +2147,19 @@ void helper_msa_pckev_df(CPUMIPSState *env, uint32_t df, 
uint32_t wd,
 pwd->b[4]  = pwt->b[8];
 pwd->b[8]  = pws->b[0];
 pwd->b[0]  = pwt->b[0];
+#endif
 break;
 case DF_HALF:
+#if defined(HOST_WORDS_BIGENDIAN)
+pwd->h[4] = pws->h[5];
+pwd->h[6] = pws->h[1];
+pwd->h[0] = pwt->h[5];
+pwd->h[2] = pwt->h[1];
+pwd->h[5] = pws->h[7];
+pwd->h[1] = pwt->h[7];
+pwd->h[7] = pws->h[3];
+pwd->h[3] = pwt->h[3];
+#else
 pwd->h[7] = pws->h[6];
 pwd->h[5] = pws->h[2];
 pwd->h[3] = pwt->h[6];
@@ -2139,12 +2168,20 @@ void helper_msa_pckev_df(CPUMIPSState *env, uint32_t 
df, uint32_t wd,
 pwd->h[2] = pwt->h[4];
 pwd->h[4] = pws->h[0];
 pwd->h[0] = pwt->h[0];
+#endif
 break;
 case DF_WORD:
+#if defined(HOST_WORDS_BIGENDIAN)
+pwd->w[2] = pws->w[3];
+pwd->w[0] = pwt->w[3];
+pwd->w[3] = pws->w[1];
+pwd->w[1] = pwt->w[1];
+#else
 pwd->w[3] = pws->w[2];
 pwd->w[1] = pwt->w[2];
 pwd->w[2] = pws->w[0];
 pwd->w[0] = pwt->w[0];
+#endif
 break;
 case DF_DOUBLE:
 pwd->d[1] = pws->d[0];
@@ -2164,6 +2201,24 @@ void helper_msa_pckod_df(CPUMIPSState *env, uint32_t df, 
uint32_t wd,
 
 switch (df) {
 case DF_BYTE:
+#if defined(HOST_WORDS_BIGENDIAN)
+pwd->b[7]  = pws->b[6];
+pwd->b[5]  = pws->b[2];
+pwd->b[3]  = pws->b[14];
+pwd->b[1]  = pws->b[10];
+pwd->b[15] = pwt->b[6];
+pwd->b[13] = pwt->b[2];
+pwd->b[11] = pwt->b[14];
+pwd->b[9]  = pwt->b[10];
+pwd->b[6]  = pws->b[4];
+pwd->b[2]  = pws->b[12];
+pwd->b[14] = pwt->b[4];
+pwd->b[10] = pwt->b[12];
+pwd->b[4]  = pws->b[0];
+pwd->b[12] = pwt->b[0];
+pwd->b[0]  = pws->b[8];
+pwd->b[8]  = pwt->b[8];
+#else
 pwd->b[0]  = pwt->b[1];
 pwd->b[2]  = pwt->b[5];
 pwd->b[4]  = pwt->b[9];
@@ -2180,8 +2235,19 @@ void helper_msa_pckod_df(CPUMIPSState *env, uint32_t df, 
uint32_t wd,
 pwd->b[11] = pws->b[7];
 pwd->b[7]  = pwt->b[15];
 pwd->b[15] = pws->b[15];
+#endif
 break;
 case DF_HALF:
+#if defined(HOST_WORDS_BIGENDIAN)
+pwd->h[3] = pws->h[2];
+pwd->h[1] = pws->h[6];
+pwd->h[7] = pwt->h[2];
+pwd->h[5] = pwt->h[6];
+pwd->h[2] = pws->h[0];
+pwd->h[6] = pwt->h[0];
+pwd->h[0] = pws->h[4];
+pwd->h[4] = pwt->h[4];
+#else
 pwd->h[0] = pwt->h[1];
 pwd->h[2] = pwt->h[5];
 pwd->h[4] = pws->h[1];
@@ -2190,12 +2256,20 @@ void helper_msa_pckod_df(CPUMIPSState *env, uint32_t 
df, uint32_t wd,
 pwd->h[5] = pws->h[3];
 pwd->h[3] = pwt->h[7];
 pwd->h[7] = pws->h[7];
+#endif
 break;
 case DF_WORD:
+#if defined(HOST_WORDS_BIGENDIAN)
+pwd->w[1] = pws->w[0];
+pwd->w[3] = pwt->w[0];
+pwd->w[0] = pws->w[2];
+pwd->w[2] = pwt->w[2];
+#else
 pwd->w[0] = pwt->w[1];
 pwd->w[2] = pws->w[1];
 pwd->w[1] = pwt->w[3];
 pwd->w[3] = pws->w[3];
+#endif
 break;
 case DF_DOUBLE:
 pwd->d[0] = pwt->d[1];
-- 
2.7.4




[Qemu-devel] [PATCH for 4.1 v4 1/5] target/mips: Add 'fall through' comments for handling nanoMips' SHXS, SWXS

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

This was found by GCC 8.3 static analysis.

Signed-off-by: Aleksandar Markovic 
---
 target/mips/translate.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index f96f141..2be5e2d 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -20136,12 +20136,14 @@ static void gen_p_lsx(DisasContext *ctx, int rd, int 
rs, int rt)
 switch (extract32(ctx->opcode, 7, 4)) {
 case NM_SHXS:
 check_nms(ctx);
+/* fall through */
 case NM_LHXS:
 case NM_LHUXS:
 tcg_gen_shli_tl(t0, t0, 1);
 break;
 case NM_SWXS:
 check_nms(ctx);
+/* fall through */
 case NM_LWXS:
 case NM_LWC1XS:
 case NM_SWC1XS:
-- 
2.7.4




[Qemu-devel] [PATCH for 4.1 v4 2/5] target/mips: Add missing 'break' for a case of MTHC0 handling

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

This was found by GCC 8.3 static analysis.

Fixes: 5fb2dcd1792

Reported-by: Stefan Weil 
Reviewed-by: Philippe Mathieu-Daudé 
Tested-by: Philippe Mathieu-Daudé 
Signed-off-by: Aleksandar Markovic 
---
 target/mips/translate.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index 2be5e2d..59d4acd 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -6745,6 +6745,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int 
reg, int sel)
 default:
 goto cp0_unimplemented;
 }
+break;
 case CP0_REGISTER_17:
 switch (sel) {
 case 0:
-- 
2.7.4




[Qemu-devel] [PATCH for 4.1 v4 4/5] target/mips: Add missing 'break' for certain cases of MTTR handling

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

This was found by GCC 8.3 static analysis.

Fixes: ead9360e2fb

Reported-by: Stefan Weil 
Reviewed-by: Philippe Mathieu-Daudé 
Tested-by: Philippe Mathieu-Daudé 
Signed-off-by: Aleksandar Markovic 
---
 target/mips/translate.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index b1cf5f0..ca62800 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -10055,6 +10055,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext 
*ctx, int rd, int rt,
 gen_mtc0(ctx, t0, rd, sel);
 break;
 }
+break;
 case 12:
 switch (sel) {
 case 0:
@@ -10064,6 +10065,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext 
*ctx, int rd, int rt,
 gen_mtc0(ctx, t0, rd, sel);
 break;
 }
+break;
 case 13:
 switch (sel) {
 case 0:
-- 
2.7.4




[Qemu-devel] [PATCH for 4.1 v3 5/5] target/mips: Fix emulation of MSA pack instructions on big endian hosts

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

Fix emulation of MSA pack instructions on big endian hosts.

Signed-off-by: Aleksandar Markovic 
---
 target/mips/msa_helper.c | 66 
 1 file changed, 66 deletions(-)

diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c
index a383c40..4098842 100644
--- a/target/mips/msa_helper.c
+++ b/target/mips/msa_helper.c
@@ -2113,39 +2113,6 @@ void helper_msa_pckev_df(CPUMIPSState *env, uint32_t df, 
uint32_t wd,
 
 switch (df) {
 case DF_BYTE:
-pwd->b[15] = pws->b[14];
-pwd->b[13] = pws->b[10];
-pwd->b[11] = pws->b[6];
-pwd->b[9]  = pws->b[2];
-pwd->b[7]  = pwt->b[14];
-pwd->b[5]  = pwt->b[10];
-pwd->b[3]  = pwt->b[6];
-pwd->b[1]  = pwt->b[2];
-pwd->b[14] = pws->b[12];
-pwd->b[10] = pws->b[4];
-pwd->b[6]  = pwt->b[12];
-pwd->b[2]  = pwt->b[4];
-pwd->b[12] = pws->b[8];
-pwd->b[4]  = pwt->b[8];
-pwd->b[8]  = pws->b[0];
-pwd->b[0]  = pwt->b[0];
-break;
-case DF_HALF:
-pwd->h[7] = pws->h[6];
-pwd->h[5] = pws->h[2];
-pwd->h[3] = pwt->h[6];
-pwd->h[1] = pwt->h[2];
-pwd->h[6] = pws->h[4];
-pwd->h[2] = pwt->h[4];
-pwd->h[4] = pws->h[0];
-pwd->h[0] = pwt->h[0];
-break;
-case DF_WORD:
-pwd->w[3] = pws->w[2];
-pwd->w[1] = pwt->w[2];
-pwd->w[2] = pws->w[0];
-pwd->w[0] = pwt->w[0];
-break;
 case DF_DOUBLE:
 pwd->d[1] = pws->d[0];
 pwd->d[0] = pwt->d[0];
@@ -2164,39 +2131,6 @@ void helper_msa_pckod_df(CPUMIPSState *env, uint32_t df, 
uint32_t wd,
 
 switch (df) {
 case DF_BYTE:
-pwd->b[0]  = pwt->b[1];
-pwd->b[2]  = pwt->b[5];
-pwd->b[4]  = pwt->b[9];
-pwd->b[6]  = pwt->b[13];
-pwd->b[8]  = pws->b[1];
-pwd->b[10] = pws->b[5];
-pwd->b[12] = pws->b[9];
-pwd->b[14] = pws->b[13];
-pwd->b[1]  = pwt->b[3];
-pwd->b[5]  = pwt->b[11];
-pwd->b[9]  = pws->b[3];
-pwd->b[13] = pws->b[11];
-pwd->b[3]  = pwt->b[7];
-pwd->b[11] = pws->b[7];
-pwd->b[7]  = pwt->b[15];
-pwd->b[15] = pws->b[15];
-break;
-case DF_HALF:
-pwd->h[0] = pwt->h[1];
-pwd->h[2] = pwt->h[5];
-pwd->h[4] = pws->h[1];
-pwd->h[6] = pws->h[5];
-pwd->h[1] = pwt->h[3];
-pwd->h[5] = pws->h[3];
-pwd->h[3] = pwt->h[7];
-pwd->h[7] = pws->h[7];
-break;
-case DF_WORD:
-pwd->w[0] = pwt->w[1];
-pwd->w[2] = pws->w[1];
-pwd->w[1] = pwt->w[3];
-pwd->w[3] = pws->w[3];
-break;
 case DF_DOUBLE:
 pwd->d[0] = pwt->d[1];
 pwd->d[1] = pws->d[1];
-- 
2.7.4




[Qemu-devel] [PATCH for 4.1 v3 4/5] target/mips: Add missing 'break' for certain cases of MTTR handling

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

This was found by GCC 8.3 static analysis.

Fixes: ead9360e2fb

Reported-by: Stefan Weil 
Reviewed-by: Philippe Mathieu-Daudé 
Tested-by: Philippe Mathieu-Daudé 
Signed-off-by: Aleksandar Markovic 
---
 target/mips/translate.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index b1cf5f0..ca62800 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -10055,6 +10055,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext 
*ctx, int rd, int rt,
 gen_mtc0(ctx, t0, rd, sel);
 break;
 }
+break;
 case 12:
 switch (sel) {
 case 0:
@@ -10064,6 +10065,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext 
*ctx, int rd, int rt,
 gen_mtc0(ctx, t0, rd, sel);
 break;
 }
+break;
 case 13:
 switch (sel) {
 case 0:
-- 
2.7.4




[Qemu-devel] [PATCH for 4.1 v3 0/5] target/mips: Fixes for 4.1 rc1

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

At the moment, this includes fixes for problems in switch statements
found by GCC 8.3 improved code analysis features, and one big endian
host fix.

v2->v3:

  - fix handling of MSA pack instructions on big endian host

v1->v2:

  - excluded the patch on "ucontext" that will go into linux user queue

Aleksandar Markovic (5):
  target/mips: Add 'fall through' comments for handling nanoMips' SHXS,
SWXS
  target/mips: Add missing 'break' for a case of MTHC0 handling
  target/mips: Add missing 'break' for certain cases of MFTR handling
  target/mips: Add missing 'break' for certain cases of MTTR handling
  target/mips: Fix emulation of MSA pack instructions on big endian
hosts

 target/mips/msa_helper.c | 66 
 target/mips/translate.c  |  7 +
 2 files changed, 7 insertions(+), 66 deletions(-)

-- 
2.7.4




[Qemu-devel] [PATCH for 4.1 v3 3/5] target/mips: Add missing 'break' for certain cases of MFTR handling

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

This was found by GCC 8.3 static analysis.

Fixes: ead9360e2fb

Reported-by: Stefan Weil 
Reviewed-by: Philippe Mathieu-Daudé 
Tested-by: Philippe Mathieu-Daudé 
Signed-off-by: Aleksandar Markovic 
---
 target/mips/translate.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index 59d4acd..b1cf5f0 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -9826,6 +9826,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext 
*ctx, int rt, int rd,
 gen_mfc0(ctx, t0, rt, sel);
 break;
 }
+break;
 case 12:
 switch (sel) {
 case 0:
@@ -9835,6 +9836,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext 
*ctx, int rt, int rd,
 gen_mfc0(ctx, t0, rt, sel);
 break;
 }
+break;
 case 13:
 switch (sel) {
 case 0:
-- 
2.7.4




[Qemu-devel] [PATCH for 4.1 v3 1/5] target/mips: Add 'fall through' comments for handling nanoMips' SHXS, SWXS

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

This was found by GCC 8.3 static analysis.

Signed-off-by: Aleksandar Markovic 
---
 target/mips/translate.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index f96f141..2be5e2d 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -20136,12 +20136,14 @@ static void gen_p_lsx(DisasContext *ctx, int rd, int 
rs, int rt)
 switch (extract32(ctx->opcode, 7, 4)) {
 case NM_SHXS:
 check_nms(ctx);
+/* fall through */
 case NM_LHXS:
 case NM_LHUXS:
 tcg_gen_shli_tl(t0, t0, 1);
 break;
 case NM_SWXS:
 check_nms(ctx);
+/* fall through */
 case NM_LWXS:
 case NM_LWC1XS:
 case NM_SWC1XS:
-- 
2.7.4




[Qemu-devel] [PATCH for 4.1 v3 2/5] target/mips: Add missing 'break' for a case of MTHC0 handling

2019-07-15 Thread Aleksandar Markovic
From: Aleksandar Markovic 

This was found by GCC 8.3 static analysis.

Fixes: 5fb2dcd1792

Reported-by: Stefan Weil 
Reviewed-by: Philippe Mathieu-Daudé 
Tested-by: Philippe Mathieu-Daudé 
Signed-off-by: Aleksandar Markovic 
---
 target/mips/translate.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index 2be5e2d..59d4acd 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -6745,6 +6745,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int 
reg, int sel)
 default:
 goto cp0_unimplemented;
 }
+break;
 case CP0_REGISTER_17:
 switch (sel) {
 case 0:
-- 
2.7.4




Re: [Qemu-devel] [PATCH v3 0/3] qapi: block-dirty-bitmap-remove transaction action

2019-07-15 Thread John Snow



On 7/8/19 6:04 PM, John Snow wrote:
> Hi, this is a proposal based off of Vladimir's patchset:
> [Qemu-devel] [PATCH 0/4] qapi: block-dirty-bitmap-remove transaction action
> 
> ===
> V3:
> ===
> 
> 001/3:[] [--] 'blockdev: reduce aio_context locked sections in bitmap 
> add/remove'
> 002/3:[0024] [FC] 'qapi: implement block-dirty-bitmap-remove transaction 
> action'
> 003/3:[] [--] 'iotests: test bitmap moving inside 254'
> 
> - Changed "squelch_persistence" to "skip_store"
> - Use Max's suggestion for return expr
> 
> ===
> V2:
> ===
> 
> It replaces patches two and three with a modified patch (now patch 2)
> that foregoes the need for a hide()/unhide() bitmap API. I think it's
> suitable as a smaller alternative, but I'm not sure if it covers all
> of the use cases of the original series.
> 
> Patches 1 and 3 (formerly 4) included as-is.
> 
> John Snow (1):
>   qapi: implement block-dirty-bitmap-remove transaction action
> 
> Vladimir Sementsov-Ogievskiy (2):
>   blockdev: reduce aio_context locked sections in bitmap add/remove
>   iotests: test bitmap moving inside 254
> 
>  block.c|   2 +-
>  block/dirty-bitmap.c   |  15 +++--
>  blockdev.c | 105 ++---
>  include/block/dirty-bitmap.h   |   2 +-
>  migration/block-dirty-bitmap.c |   2 +-
>  qapi/transaction.json  |   2 +
>  tests/qemu-iotests/254 |  30 +-
>  tests/qemu-iotests/254.out |  82 +
>  8 files changed, 206 insertions(+), 34 deletions(-)
> 

Thanks, applied to my bitmaps tree:

https://github.com/jnsnow/qemu/commits/bitmaps
https://github.com/jnsnow/qemu.git

--js


(Vladimir: if this isn't amenable to you, it's going in for 4.2, so we
have until the next freeze to change it. Let me know, OK?)



Re: [Qemu-devel] [BUG] nanoMIPS support problem related to extract2 support for i386 TCG target

2019-07-15 Thread Aleksandar Markovic
On Sat, Jul 13, 2019 at 9:21 AM Alex Bennée  wrote:
>
> Please see the fix:
>
>   Subject: [PATCH for-4.1] tcg: Fix constant folding of INDEX_op_extract2_i32
>   Date: Tue,  9 Jul 2019 14:19:00 +0200
>   Message-Id: <20190709121900.25644-1-richard.hender...@linaro.org>
>

Thanks, this fixed the behavior.

Sincerely,
Aleksandar

>
> >
> > Yours,
> > Aleksandar
>
>
> --
> Alex Bennée
>



[Qemu-devel] [PATCH v5 20/20] hmp: call the asynchronous QMP screendump to fix outdated/glitches

2019-07-15 Thread Marc-André Lureau
In order to fix the bad screendumps (same as rhbz#1230527), call into
the asynchonous version of the QMP command.

Signed-off-by: Marc-André Lureau 
---
 hmp-commands.hx  |  3 ++-
 include/ui/console.h |  5 ++---
 monitor/hmp-cmds.c   |  6 ++
 ui/console.c | 24 +---
 4 files changed, 7 insertions(+), 31 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index bfa5681dd2..fa559d6a4e 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -278,7 +278,8 @@ ETEXI
 .params = "filename [device [head]]",
 .help   = "save screen from head 'head' of display device 'device' 
"
   "into PPM image 'filename'",
-.cmd= hmp_screendump,
+.async_cmd  = hmp_screendump_async,
+.async  = true,
 },
 
 STEXI
diff --git a/include/ui/console.h b/include/ui/console.h
index a1935557cc..d0a2a2066f 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -6,6 +6,7 @@
 #include "qemu/notify.h"
 #include "qemu/error-report.h"
 #include "qapi/qapi-types-ui.h"
+#include "qapi/qmp/dispatch.h"
 
 #ifdef CONFIG_OPENGL
 # include 
@@ -74,9 +75,7 @@ typedef struct MouseTransformInfo {
 } MouseTransformInfo;
 
 void hmp_mouse_set(Monitor *mon, const QDict *qdict);
-void hmp_screendump_sync(const char *filename,
- bool has_device, const char *device,
- bool has_head, int64_t head, Error **errp);
+void hmp_screendump_async(Monitor *mon, const QDict *qdict, QmpReturn *qret);
 
 /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
constants) */
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 50a25a1ddc..e2af0e6307 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -2334,15 +2334,13 @@ err_out:
 goto out;
 }
 
-void hmp_screendump(Monitor *mon, const QDict *qdict)
+void hmp_screendump_async(Monitor *mon, const QDict *qdict, QmpReturn *qret)
 {
 const char *filename = qdict_get_str(qdict, "filename");
 const char *id = qdict_get_try_str(qdict, "device");
 int64_t head = qdict_get_try_int(qdict, "head", 0);
-Error *err = NULL;
 
-hmp_screendump_sync(filename, id != NULL, id, id != NULL, head, );
-hmp_handle_error(mon, );
+qmp_screendump(filename, id != NULL, id, id != NULL, head, qret);
 }
 
 void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
diff --git a/ui/console.c b/ui/console.c
index 29c850c31c..7436b153b9 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -280,7 +280,7 @@ static void qmp_screendump_finish(QemuConsole *con, struct 
qmp_screendump *dump)
 goto cleanup;
 }
 
-cur_mon = qmp_return_get_monitor(dump->ret);
+cur_mon = qmp_return_get_monitor(dump->ret, true);
 surface = qemu_console_surface(con);
 if (!surface) {
 error_setg(, "no surface");
@@ -430,28 +430,6 @@ static QemuConsole *get_console(bool has_device, const 
char *device,
 return con;
 }
 
-void hmp_screendump_sync(const char *filename,
- bool has_device, const char *device,
- bool has_head, int64_t head, Error **errp)
-{
-DisplaySurface *surface;
-QemuConsole *con = get_console(has_device, device, has_head, head, errp);
-
-if (!con) {
-return;
-}
-/* This may not complete the drawing with Spice, you may have
- * glitches or outdated dumps, use qmp instead! */
-graphic_hw_update(con);
-surface = qemu_console_surface(con);
-if (!surface) {
-error_setg(errp, "no surface");
-return;
-}
-
-ppm_save(filename, surface, errp);
-}
-
 void qmp_screendump(const char *filename,
 bool has_device, const char *device,
 bool has_head, int64_t head,
-- 
2.22.0.428.g6d5b264208




[Qemu-devel] [PATCH v5 18/20] monitor: start making qmp_human_monitor_command() asynchronous

2019-07-15 Thread Marc-André Lureau
This prepares the work for HMP commands to be asynchronous.

Start making QMP human-monitor-command asynchronous, although
QmpReturn is used synchronously on error or after
handle_hmp_command().

Signed-off-by: Marc-André Lureau 
---
 monitor/misc.c | 14 --
 qapi/misc.json |  3 ++-
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/monitor/misc.c b/monitor/misc.c
index a23c1b8ba4..0645667e1b 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -115,8 +115,8 @@ static QLIST_HEAD(, MonFdset) mon_fdsets;
 
 static HMPCommand hmp_info_cmds[];
 
-char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
-int64_t cpu_index, Error **errp)
+void qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
+   int64_t cpu_index, QmpReturn *qret)
 {
 char *output = NULL;
 Monitor *old_mon;
@@ -130,15 +130,15 @@ char *qmp_human_monitor_command(const char *command_line, 
bool has_cpu_index,
 if (has_cpu_index) {
 int ret = monitor_set_cpu(cpu_index);
 if (ret < 0) {
-cur_mon = old_mon;
-error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
+Error *err = NULL;
+error_setg(, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
"a CPU number");
+qmp_return_error(qret, err);
 goto out;
 }
 }
 
 handle_hmp_command(, command_line);
-cur_mon = old_mon;
 
 qemu_mutex_lock(_lock);
 if (qstring_get_length(hmp.common.outbuf) > 0) {
@@ -148,9 +148,11 @@ char *qmp_human_monitor_command(const char *command_line, 
bool has_cpu_index,
 }
 qemu_mutex_unlock(_lock);
 
+qmp_human_monitor_command_return(qret, output);
+
 out:
+cur_mon = old_mon;
 monitor_data_destroy();
-return output;
 }
 
 /**
diff --git a/qapi/misc.json b/qapi/misc.json
index a7fba7230c..8c6ca46b8b 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -1047,7 +1047,8 @@
 ##
 { 'command': 'human-monitor-command',
   'data': {'command-line': 'str', '*cpu-index': 'int'},
-  'returns': 'str' }
+  'returns': 'str',
+  'async': true }
 
 ##
 # @change:
-- 
2.22.0.428.g6d5b264208




[Qemu-devel] [PATCH v5 19/20] monitor: teach HMP about asynchronous commands

2019-07-15 Thread Marc-André Lureau
Similar to how we handle both synchronous and asynchronous commands in
QMP, HMP gains a new async_cmd() that will allow the command to
complete asynchronously. For interactive reasons, and command
ordering, the HMP monitor is suspended until the asynchronous command
completes.

It is expected that HMP async commands will be implemented re-using
QMP async commands counterparts, so it reuses the QmpSession/QmpReturn
for context handling (instead of introducing HmpSession/HmpReturn and
having to convert from one to the other as we call QMP counterparts).

hmp_dispatch_return_cb() will handle printing the result to the
current monitor. It may have different ways to print the QmpReturn
result to the current monitor. Currently, only error reporting is
implemented.

QMP human-monitor-command is modified to deal with an async HMP
commands too. It creates a temporary session, and the return callback
will return asynchronously to the original QMP command and destroy the
temporary monitor when hmp->for_qmp_command is set.

Signed-off-by: Marc-André Lureau 
---
 include/monitor/monitor.h  |   2 +-
 monitor/hmp.c  | 110 +++--
 monitor/misc.c |  40 --
 monitor/monitor-internal.h |   9 ++-
 monitor/qmp.c  |  14 +++--
 5 files changed, 123 insertions(+), 52 deletions(-)

diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 6a2907a366..5968b52fe2 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -44,6 +44,6 @@ int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd);
 void monitor_fdset_dup_fd_remove(int dup_fd);
 int64_t monitor_fdset_dup_fd_find(int dup_fd);
 
-Monitor *qmp_return_get_monitor(QmpReturn *qret);
+Monitor *qmp_return_get_monitor(QmpReturn *qret, bool hmp);
 
 #endif /* MONITOR_H */
diff --git a/monitor/hmp.c b/monitor/hmp.c
index 5223661e82..b2b6dce8fb 100644
--- a/monitor/hmp.c
+++ b/monitor/hmp.c
@@ -26,11 +26,15 @@
 #include 
 #include "monitor-internal.h"
 #include "qapi/error.h"
+#include "qapi/qapi-commands-misc.h"
+#include "qapi/qmp/qerror.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qnum.h"
+#include "qapi/qmp/qstring.h"
 #include "qemu/config-file.h"
 #include "qemu/ctype.h"
 #include "qemu/cutils.h"
+#include "qemu/error-report.h"
 #include "qemu/log.h"
 #include "qemu/option.h"
 #include "qemu/units.h"
@@ -38,6 +42,8 @@
 #include "sysemu/sysemu.h"
 #include "trace.h"
 
+static bool handle_hmp_command(MonitorHMP *mon, const char *cmdline);
+
 static void monitor_command_cb(void *opaque, const char *cmdline,
void *readline_opaque)
 {
@@ -1056,7 +1062,7 @@ fail:
 return NULL;
 }
 
-void handle_hmp_command(MonitorHMP *mon, const char *cmdline)
+static bool handle_hmp_command(MonitorHMP *mon, const char *cmdline)
 {
 QDict *qdict;
 const HMPCommand *cmd;
@@ -1066,7 +1072,7 @@ void handle_hmp_command(MonitorHMP *mon, const char 
*cmdline)
 
 cmd = monitor_parse_command(mon, cmdline, , hmp_cmds);
 if (!cmd) {
-return;
+return false;
 }
 
 qdict = monitor_parse_arguments(>common, , cmd);
@@ -1076,11 +1082,19 @@ void handle_hmp_command(MonitorHMP *mon, const char 
*cmdline)
 }
 monitor_printf(>common, "Try \"help %.*s\" for more 
information\n",
(int)(cmdline - cmd_start), cmd_start);
-return;
+return false;
 }
 
-cmd->cmd(>common, qdict);
+if (cmd->async) {
+QmpReturn *qret = qmp_return_new(>qmp_session, NULL);
+monitor_suspend(>common);
+cmd->async_cmd(>common, qdict, qret);
+} else {
+cmd->cmd(>common, qdict);
+}
 qobject_unref(qdict);
+
+return cmd->async;
 }
 
 static void cmd_completion(MonitorHMP *mon, const char *name, const char *list)
@@ -1395,6 +1409,59 @@ static void monitor_readline_flush(void *opaque)
 monitor_flush(>common);
 }
 
+static void free_hmp_monitor(void *opaque)
+{
+MonitorHMP *hmp = opaque;
+
+qmp_session_destroy(>qmp_session);
+monitor_data_destroy(>common);
+g_free(hmp);
+}
+
+static AioContext *monitor_get_aio_context(void)
+{
+return iothread_get_aio_context(mon_iothread);
+}
+
+static void qmp_human_monitor_command_finish(MonitorHMP *hmp, QmpReturn *qret)
+{
+char *output;
+
+qemu_mutex_lock(>common.mon_lock);
+if (qstring_get_length(hmp->common.outbuf) > 0) {
+output = g_strdup(qstring_get_str(hmp->common.outbuf));
+} else {
+output = g_strdup("");
+}
+qemu_mutex_unlock(>common.mon_lock);
+
+qmp_human_monitor_command_return(qret, output);
+
+if (hmp->for_qmp_command) {
+aio_bh_schedule_oneshot(monitor_get_aio_context(),
+free_hmp_monitor, hmp);
+}
+}
+
+static void hmp_dispatch_return_cb(QmpSession *session, QDict *rsp)
+{
+MonitorHMP *hmp = container_of(session, MonitorHMP, qmp_session);
+QDict *err = qdict_get_qdict(rsp, 

[Qemu-devel] [PATCH v5 17/20] console: make screendump asynchronous

2019-07-15 Thread Marc-André Lureau
Make screendump asynchronous to provide correct screendumps.

For now, HMP doesn't have async support, so it has to remain
synchronous and potentially incorrect to avoid races (following
patches will add HMP asynchronous commands)

Fixes:
https://bugzilla.redhat.com/show_bug.cgi?id=1230527

Signed-off-by: Marc-André Lureau 
---
 include/ui/console.h |   3 ++
 monitor/hmp-cmds.c   |   2 +-
 qapi/ui.json |   3 +-
 ui/console.c | 103 +++
 4 files changed, 100 insertions(+), 11 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index 281f9c145b..a1935557cc 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -74,6 +74,9 @@ typedef struct MouseTransformInfo {
 } MouseTransformInfo;
 
 void hmp_mouse_set(Monitor *mon, const QDict *qdict);
+void hmp_screendump_sync(const char *filename,
+ bool has_device, const char *device,
+ bool has_head, int64_t head, Error **errp);
 
 /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
constants) */
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 5ca3ebe942..50a25a1ddc 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -2341,7 +2341,7 @@ void hmp_screendump(Monitor *mon, const QDict *qdict)
 int64_t head = qdict_get_try_int(qdict, "head", 0);
 Error *err = NULL;
 
-qmp_screendump(filename, id != NULL, id, id != NULL, head, );
+hmp_screendump_sync(filename, id != NULL, id, id != NULL, head, );
 hmp_handle_error(mon, );
 }
 
diff --git a/qapi/ui.json b/qapi/ui.json
index 59e412139a..cbb3979172 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -96,7 +96,8 @@
 #
 ##
 { 'command': 'screendump',
-  'data': {'filename': 'str', '*device': 'str', '*head': 'int'} }
+  'data': {'filename': 'str', '*device': 'str', '*head': 'int'},
+  'async': true }
 
 ##
 # == Spice
diff --git a/ui/console.c b/ui/console.c
index 3c941528d2..29c850c31c 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -33,6 +33,7 @@
 #include "chardev/char-fe.h"
 #include "trace.h"
 #include "exec/memory.h"
+#include "monitor/monitor.h"
 
 #define DEFAULT_BACKSCROLL 512
 #define CONSOLE_CURSOR_PERIOD 500
@@ -117,6 +118,12 @@ typedef enum {
 TEXT_CONSOLE_FIXED_SIZE
 } console_type_t;
 
+struct qmp_screendump {
+gchar *filename;
+QmpReturn *ret;
+QLIST_ENTRY(qmp_screendump) link;
+};
+
 struct QemuConsole {
 Object parent;
 
@@ -167,6 +174,8 @@ struct QemuConsole {
 uint8_t out_fifo_buf[16];
 QEMUTimer *kbd_timer;
 
+QLIST_HEAD(, qmp_screendump) qmp_screendumps;
+
 QTAILQ_ENTRY(QemuConsole) next;
 };
 
@@ -193,6 +202,8 @@ static void dpy_refresh(DisplayState *s);
 static DisplayState *get_alloc_displaystate(void);
 static void text_console_update_cursor_timer(void);
 static void text_console_update_cursor(void *opaque);
+static void ppm_save(const char *filename, DisplaySurface *ds,
+ Error **errp);
 
 static void gui_update(void *opaque)
 {
@@ -259,8 +270,48 @@ static void gui_setup_refresh(DisplayState *ds)
 ds->have_text = have_text;
 }
 
+static void qmp_screendump_finish(QemuConsole *con, struct qmp_screendump 
*dump)
+{
+Error *err = NULL;
+DisplaySurface *surface;
+Monitor *prev_mon = cur_mon;
+
+if (qmp_return_is_cancelled(dump->ret)) {
+goto cleanup;
+}
+
+cur_mon = qmp_return_get_monitor(dump->ret);
+surface = qemu_console_surface(con);
+if (!surface) {
+error_setg(, "no surface");
+} else {
+/*
+ * FIXME: async save with coroutine? it would have to copy or
+ * lock the surface.
+ */
+ppm_save(dump->filename, surface, );
+}
+
+if (err) {
+qmp_return_error(dump->ret, err);
+} else {
+qmp_screendump_return(dump->ret);
+}
+cur_mon = prev_mon;
+
+cleanup:
+g_free(dump->filename);
+QLIST_REMOVE(dump, link);
+g_free(dump);
+}
+
 void graphic_hw_update_done(QemuConsole *con)
 {
+struct qmp_screendump *dump, *next;
+
+QLIST_FOREACH_SAFE(dump, >qmp_screendumps, link, next) {
+qmp_screendump_finish(con, dump);
+}
 }
 
 void graphic_hw_update(QemuConsole *con)
@@ -356,30 +407,41 @@ write_err:
 goto out;
 }
 
-void qmp_screendump(const char *filename, bool has_device, const char *device,
-bool has_head, int64_t head, Error **errp)
+
+static QemuConsole *get_console(bool has_device, const char *device,
+bool has_head, int64_t head, Error **errp)
 {
-QemuConsole *con;
-DisplaySurface *surface;
+QemuConsole *con = NULL;
 
 if (has_device) {
 con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
  errp);
-if (!con) {
-return;
-}
 } else {
 if (has_head) {
 error_setg(errp, "'head' must be specified together with 
'device'");
-   

[Qemu-devel] [PATCH v5 16/20] console: add graphic_hw_update_done()

2019-07-15 Thread Marc-André Lureau
Add a function to be called when a graphic update is done.

Declare the QXL renderer as async: render_update_cookie_num counts the
number of outstanding updates, and graphic_hw_update_done() is called
when it reaches none.

Signed-off-by: Marc-André Lureau 
Reviewed-by: Gerd Hoffmann 
---
 hw/display/qxl-render.c | 9 +++--
 hw/display/qxl.c| 1 +
 include/ui/console.h| 2 ++
 ui/console.c| 9 +
 4 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
index 14ad2b352d..102fa0b7e9 100644
--- a/hw/display/qxl-render.c
+++ b/hw/display/qxl-render.c
@@ -108,7 +108,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice 
*qxl)
 qxl->guest_primary.surface.mem,
 MEMSLOT_GROUP_GUEST);
 if (!qxl->guest_primary.data) {
-return;
+goto end;
 }
 qxl_set_rect_to_surface(qxl, >dirty[0]);
 qxl->num_dirty_rects = 1;
@@ -136,7 +136,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice 
*qxl)
 }
 
 if (!qxl->guest_primary.data) {
-return;
+goto end;
 }
 for (i = 0; i < qxl->num_dirty_rects; i++) {
 if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
@@ -157,6 +157,11 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice 
*qxl)
qxl->dirty[i].bottom - qxl->dirty[i].top);
 }
 qxl->num_dirty_rects = 0;
+
+end:
+if (qxl->render_update_cookie_num == 0) {
+graphic_hw_update_done(qxl->ssd.dcl.con);
+}
 }
 
 /*
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 98c7410032..188399acd1 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -1178,6 +1178,7 @@ static const QXLInterface qxl_interface = {
 
 static const GraphicHwOps qxl_ops = {
 .gfx_update  = qxl_hw_update,
+.gfx_update_async = true,
 };
 
 static void qxl_enter_vga_mode(PCIQXLDevice *d)
diff --git a/include/ui/console.h b/include/ui/console.h
index f981696848..281f9c145b 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -365,6 +365,7 @@ static inline void console_write_ch(console_ch_t *dest, 
uint32_t ch)
 typedef struct GraphicHwOps {
 void (*invalidate)(void *opaque);
 void (*gfx_update)(void *opaque);
+bool gfx_update_async; /* if true, calls graphic_hw_update_done() */
 void (*text_update)(void *opaque, console_ch_t *text);
 void (*update_interval)(void *opaque, uint64_t interval);
 int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
@@ -380,6 +381,7 @@ void graphic_console_set_hwops(QemuConsole *con,
 void graphic_console_close(QemuConsole *con);
 
 void graphic_hw_update(QemuConsole *con);
+void graphic_hw_update_done(QemuConsole *con);
 void graphic_hw_invalidate(QemuConsole *con);
 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
 void graphic_hw_gl_block(QemuConsole *con, bool block);
diff --git a/ui/console.c b/ui/console.c
index 82d1ddac9c..3c941528d2 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -259,13 +259,22 @@ static void gui_setup_refresh(DisplayState *ds)
 ds->have_text = have_text;
 }
 
+void graphic_hw_update_done(QemuConsole *con)
+{
+}
+
 void graphic_hw_update(QemuConsole *con)
 {
+bool async = false;
 if (!con) {
 con = active_console;
 }
 if (con && con->hw_ops->gfx_update) {
 con->hw_ops->gfx_update(con->hw);
+async = con->hw_ops->gfx_update_async;
+}
+if (!async) {
+graphic_hw_update_done(con);
 }
 }
 
-- 
2.22.0.428.g6d5b264208




[Qemu-devel] [PATCH v5 15/20] monitor: add qmp_return_get_monitor()

2019-07-15 Thread Marc-André Lureau
If necessary, add an helper that can be used to retrieve the
associated monitor. This is useful for asynchronous commands that may
have to update cur_mon for various reasons.

Signed-off-by: Marc-André Lureau 
---
 include/monitor/monitor.h |  3 +++
 monitor/qmp.c | 11 +++
 2 files changed, 14 insertions(+)

diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index a81eeff5f8..6a2907a366 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -4,6 +4,7 @@
 #include "block/block.h"
 #include "qapi/qapi-types-misc.h"
 #include "qemu/readline.h"
+#include "qapi/qmp/dispatch.h"
 
 extern __thread Monitor *cur_mon;
 typedef struct MonitorHMP MonitorHMP;
@@ -43,4 +44,6 @@ int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd);
 void monitor_fdset_dup_fd_remove(int dup_fd);
 int64_t monitor_fdset_dup_fd_find(int dup_fd);
 
+Monitor *qmp_return_get_monitor(QmpReturn *qret);
+
 #endif /* MONITOR_H */
diff --git a/monitor/qmp.c b/monitor/qmp.c
index 056ad7b68b..df8b9d8d4f 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -390,3 +390,14 @@ void monitor_init_qmp(Chardev *chr, bool pretty)
 monitor_list_append(>common);
 }
 }
+
+Monitor *qmp_return_get_monitor(QmpReturn *qret)
+{
+MonitorQMP *mon;
+
+if (!qret->session) {
+return NULL;
+}
+mon = container_of(qret->session, MonitorQMP, session);
+return >common;
+}
-- 
2.22.0.428.g6d5b264208




[Qemu-devel] [PATCH v5 13/20] scripts: learn 'async' qapi commands

2019-07-15 Thread Marc-André Lureau
Commands with the 'async' key will be registered as async type (see
related commit), and will allow a synchronous (in scope callback) or
asynchronous return (out-of-scope when ready, in idle etc) by keeping
the given QmpReturn and calling qmp_return function later.

Ex:
  { 'command': 'foo-async,
'data': {'arg': 'str'},
'returns': 'Foo',
'async': true }

generates the following marshaller:

void qmp_marshal_foo_async(QDict *args, QmpReturn *qret)
{
Error *err = NULL;
Visitor *v;
q_obj_foo_async_arg arg = {0};

v = qmp_input_visitor_new(QOBJECT(args), true);
visit_start_struct(v, NULL, NULL, 0, );
if (err) {
goto out;
}
visit_type_q_obj_foo_async_arg_members(v, , );
if (!err) {
visit_check_struct(v, );
}
visit_end_struct(v, NULL);
if (err) {
goto out;
}

qmp_foo_async(arg.arg, qret);

out:
if (err) {
qmp_return_error(qret, err);
}
visit_free(v);
v = qapi_dealloc_visitor_new();
visit_start_struct(v, NULL, NULL, 0, NULL);
visit_type_q_obj_foo_async_arg_members(v, , NULL);
visit_end_struct(v, NULL);
visit_free(v);
}

and a return helper:

void qmp_foo_async_return(QmpReturn *qret, Foo *ret_in)
{
Error *err = NULL;
QObject *ret_out = NULL;

qmp_marshal_output_Foo(ret_in, _out, );

if (err) {
qmp_return_error(qret, err);
} else {
qmp_return(qret, ret_out);
}
}

The dispatched function may call the return helper within the calling
scope or delay the return. To return an error, it can call
qmp_return_error() directly instead.

Signed-off-by: Marc-André Lureau 
---
 scripts/qapi/commands.py| 151 
 scripts/qapi/common.py  |  15 ++-
 scripts/qapi/doc.py |   3 +-
 scripts/qapi/introspect.py  |   3 +-
 tests/qapi-schema/qapi-schema-test.json |   5 +
 tests/qapi-schema/qapi-schema-test.out  |   8 ++
 tests/qapi-schema/test-qapi.py  |   8 +-
 tests/test-qmp-cmds.c   |  60 ++
 8 files changed, 218 insertions(+), 35 deletions(-)

diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index b929e07be4..4c200c04ca 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -16,18 +16,36 @@ See the COPYING file in the top-level directory.
 from qapi.common import *
 
 
-def gen_command_decl(name, arg_type, boxed, ret_type):
-return mcgen('''
-%(c_type)s qmp_%(c_name)s(%(params)s);
+def gen_command_decl(name, arg_type, boxed, ret_type, success_response, asyn):
+if asyn:
+extra = "QmpReturn *qret"
+else:
+extra = 'Error **errp'
+
+if asyn:
+ret = mcgen('''
+void qmp_%(name)s(%(params)s);
 ''',
- c_type=(ret_type and ret_type.c_type()) or 'void',
- c_name=c_name(name),
- params=build_params(arg_type, boxed, 'Error **errp'))
+ name=c_name(name),
+ params=build_params(arg_type, boxed, extra))
+if success_response:
+ret += mcgen('''
+void qmp_%(name)s_return(QmpReturn *qret%(c_type)s);
+''',
+c_type=(", " + ret_type.c_type() if ret_type else ""),
+name=c_name(name))
 
+return ret
+else:
+return mcgen('''
+%(c_type)s qmp_%(c_name)s(%(params)s);
+''',
+ c_type=(ret_type and ret_type.c_type()) or 'void',
+ c_name=c_name(name),
+ params=build_params(arg_type, boxed, extra))
 
-def gen_call(name, arg_type, boxed, ret_type):
-ret = ''
 
+def gen_argstr(arg_type, boxed):
 argstr = ''
 if boxed:
 assert arg_type and not arg_type.is_empty()
@@ -39,6 +57,13 @@ def gen_call(name, arg_type, boxed, ret_type):
 argstr += 'arg.has_%s, ' % c_name(memb.name)
 argstr += 'arg.%s, ' % c_name(memb.name)
 
+return argstr
+
+
+def gen_call(name, arg_type, boxed, ret_type):
+ret = ''
+
+argstr = gen_argstr(arg_type, boxed)
 lhs = ''
 if ret_type:
 lhs = 'retval = '
@@ -60,6 +85,50 @@ def gen_call(name, arg_type, boxed, ret_type):
 return ret
 
 
+def gen_async_call(name, arg_type, boxed):
+argstr = gen_argstr(arg_type, boxed)
+
+push_indent()
+ret = mcgen('''
+
+qmp_%(c_name)s(%(args)sqret);
+''',
+c_name=c_name(name), args=argstr)
+
+pop_indent()
+return ret
+
+
+def gen_async_return(name, ret_type):
+if ret_type:
+return mcgen('''
+
+void qmp_%(c_name)s_return(QmpReturn *qret, %(ret_type)s ret_in)
+{
+Error *err = NULL;
+QObject *ret_out = NULL;
+
+qmp_marshal_output_%(ret_c_name)s(ret_in, _out, );
+
+if (err) {
+qmp_return_error(qret, err);
+} else {
+qmp_return(qret, ret_out);
+}
+}
+''',
+ c_name=c_name(name),
+ ret_type=ret_type.c_type(), 

[Qemu-devel] [PATCH v5 14/20] qmp: add qmp_return_is_cancelled()

2019-07-15 Thread Marc-André Lureau
If the client is gone, and the session finished, no need to
return. The async handler can use this information to avoid
unnecessary work and exit earlier.

Signed-off-by: Marc-André Lureau 
---
 include/qapi/qmp/dispatch.h |  8 
 qapi/qmp-dispatch.c | 10 ++
 tests/test-qmp-cmds.c   | 39 -
 3 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 6aef0abc70..6673902e95 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -91,6 +91,14 @@ void qmp_return_free(QmpReturn *qret);
 void qmp_return(QmpReturn *qret, QObject *rsp);
 void qmp_return_error(QmpReturn *qret, Error *err);
 
+/*
+ * @qmp_return_is_cancelled:
+ *
+ * Return true if the QmpReturn is cancelled, and free the QmpReturn
+ * in this case.
+ */
+bool qmp_return_is_cancelled(QmpReturn *qret);
+
 void qmp_register_command(QmpCommandList *cmds, const char *name,
   QmpCommandFunc *fn, QmpCommandOptions options);
 void qmp_register_async_command(QmpCommandList *cmds, const char *name,
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 1f493af67a..8653c17901 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -64,6 +64,16 @@ void qmp_return_free(QmpReturn *qret)
 }
 }
 
+bool qmp_return_is_cancelled(QmpReturn *qret)
+{
+if (!qret->session) {
+qmp_return_free(qret);
+return true;
+}
+
+return false;
+}
+
 static void qmp_return_orderly(QmpReturn *qret)
 {
 QmpSession *session = qret->session;
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index f567ac2fb0..d4c27f0be1 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -34,17 +34,29 @@ void qmp_cmd_success_response(Error **errp)
 {
 }
 
+static GMainLoop *loop;
+
 static gboolean cmd_async_idle(gpointer user_data)
 {
 QmpReturn *qret = user_data;
 
-qmp_cmd_async_return(qret, g_new0(Empty2, 1));
+if (!qret->session) {
+g_assert(qmp_return_is_cancelled(qret));
+g_main_loop_quit(loop);
+g_main_loop_unref(loop);
+loop = NULL;
+} else {
+qmp_cmd_async_return(qret, g_new0(Empty2, 1));
+}
 
 return G_SOURCE_REMOVE;
 }
 
 void qmp_cmd_async(const char *filename, QmpReturn *qret)
 {
+if (g_str_equal(filename, "cancel")) {
+qmp_session_destroy(qret->session);
+}
 g_idle_add(cmd_async_idle, qret);
 }
 
@@ -425,6 +437,30 @@ static void test_qmp_return_async(void)
 qobject_unref(req);
 }
 
+static void test_qmp_return_async_cancel(void)
+{
+QmpReturnAsync a = { { 0, }, };
+QDict *args = qdict_new();
+QDict *req = qdict_new();
+
+a.loop = g_main_loop_new(NULL, TRUE);
+qmp_session_init(, _commands,
+ NULL, dispatch_return_async);
+
+qdict_put_str(args, "filename", "cancel");
+qdict_put_str(req, "execute", "cmd-async");
+qdict_put(req, "arguments", args);
+qmp_dispatch(, QOBJECT(req), false);
+g_assert(a.loop);
+
+loop = a.loop;
+g_main_loop_run(loop);
+g_assert(!loop);
+
+qmp_session_destroy();
+qobject_unref(req);
+}
+
 int main(int argc, char **argv)
 {
 g_test_init(, , NULL);
@@ -439,6 +475,7 @@ int main(int argc, char **argv)
 g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial);
 g_test_add_func("/qmp/return_orderly", test_qmp_return_orderly);
 g_test_add_func("/qmp/return_async", test_qmp_return_async);
+g_test_add_func("/qmp/return_async_cancel", test_qmp_return_async_cancel);
 
 test_qmp_init_marshal(_commands);
 g_test_run();
-- 
2.22.0.428.g6d5b264208




[Qemu-devel] [PATCH v5 11/20] QmpSession: return orderly

2019-07-15 Thread Marc-André Lureau
QEMU will gain support for asynchronous commands, and may thus finish
commands in various order. However, the clients expect replies in
order. Let's enforce ordering of replies in QmpReturn: starting from
the older command, process each pending QmpReturn, and return until
reaching one that is unfinished.

Or if the command is OOB, it should return immediately.

Signed-off-by: Marc-André Lureau 
---
 include/qapi/qmp/dispatch.h |  2 ++
 qapi/qmp-dispatch.c | 61 ++---
 tests/test-qmp-cmds.c   | 33 
 3 files changed, 85 insertions(+), 11 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 7c9de9780d..92d6fd1afb 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -55,6 +55,8 @@ struct QmpSession {
 struct QmpReturn {
 QmpSession *session;
 QDict *rsp;
+bool oob;
+bool finished;
 QTAILQ_ENTRY(QmpReturn) entry;
 };
 
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 4699a6715b..546a6c9f7b 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -25,6 +25,7 @@ QmpReturn *qmp_return_new(QmpSession *session, const QObject 
*request)
 const QDict *req = qobject_to(QDict, request);
 QObject *id = req ? qdict_get(req, "id") : NULL;
 
+qret->oob = req ? qmp_is_oob(req) : false;
 qret->session = session;
 qret->rsp = qdict_new();
 if (id) {
@@ -39,6 +40,15 @@ QmpReturn *qmp_return_new(QmpSession *session, const QObject 
*request)
 return qret;
 }
 
+static void qmp_return_free_with_lock(QmpReturn *qret)
+{
+if (qret->session) {
+QTAILQ_REMOVE(>session->pending, qret, entry);
+}
+qobject_unref(qret->rsp);
+g_free(qret);
+}
+
 void qmp_return_free(QmpReturn *qret)
 {
 QmpSession *session = qret->session;
@@ -46,21 +56,53 @@ void qmp_return_free(QmpReturn *qret)
 if (session) {
 qemu_mutex_lock(>pending_lock);
 }
-QTAILQ_REMOVE(>pending, qret, entry);
+
+qmp_return_free_with_lock(qret);
+
 if (session) {
 qemu_mutex_unlock(>pending_lock);
 }
-qobject_unref(qret->rsp);
-g_free(qret);
+}
+
+static void qmp_return_orderly(QmpReturn *qret)
+{
+QmpSession *session = qret->session;
+QmpReturn *ret, *next;
+
+if (!session) {
+/* the session was destroyed before return, discard */
+qmp_return_free(qret);
+return;
+}
+if (qret->oob) {
+session->return_cb(session, qret->rsp);
+qmp_return_free(qret);
+return;
+}
+
+qret->finished = true;
+
+qemu_mutex_lock(>pending_lock);
+/*
+ * Process the list of pending and call return_cb until reaching
+ * an unfinished.
+ */
+QTAILQ_FOREACH_SAFE(ret, >pending, entry, next) {
+if (!ret->finished) {
+break;
+}
+session->return_cb(session, ret->rsp);
+ret->session = session;
+qmp_return_free_with_lock(ret);
+}
+
+qemu_mutex_unlock(>pending_lock);
 }
 
 void qmp_return(QmpReturn *qret, QObject *rsp)
 {
 qdict_put_obj(qret->rsp, "return", rsp ?: QOBJECT(qdict_new()));
-if (qret->session) {
-qret->session->return_cb(qret->session, qret->rsp);
-}
-qmp_return_free(qret);
+qmp_return_orderly(qret);
 }
 
 void qmp_return_error(QmpReturn *qret, Error *err)
@@ -70,10 +112,7 @@ void qmp_return_error(QmpReturn *qret, Error *err)
 qdict_put_str(qdict, "desc", error_get_pretty(err));
 qdict_put_obj(qret->rsp, "error", QOBJECT(qdict));
 error_free(err);
-if (qret->session) {
-qret->session->return_cb(qret->session, qret->rsp);
-}
-qmp_return_free(qret);
+qmp_return_orderly(qret);
 }
 
 static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob,
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index 8e46f88f6f..ece8726e96 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -333,6 +333,38 @@ static void test_dealloc_partial(void)
 qapi_free_UserDefTwo(ud2);
 }
 
+typedef struct QmpReturnOrderly {
+QmpSession session;
+int returns;
+} QmpReturnOrderly;
+
+static void dispatch_return_orderly(QmpSession *session, QDict *resp)
+{
+QmpReturnOrderly *o = container_of(session, QmpReturnOrderly, session);
+
+o->returns++;
+}
+
+static void test_qmp_return_orderly(void)
+{
+QDict *dict = qdict_new();
+QmpReturnOrderly o = { { 0 }, };
+QmpReturn *r1, *r2, *r3;
+
+qmp_session_init(, _commands, NULL, dispatch_return_orderly);
+r1 = qmp_return_new(, NULL);
+qdict_put_str(dict, "exec-oob", "test");
+r2 = qmp_return_new(, QOBJECT(dict));
+r3 = qmp_return_new(, NULL);
+qmp_return(r3, NULL);
+g_assert_cmpint(o.returns, ==, 0);
+qmp_return(r2, NULL);
+g_assert_cmpint(o.returns, ==, 1);
+qmp_return(r1, NULL);
+g_assert_cmpint(o.returns, ==, 3);
+qmp_session_destroy();
+qobject_unref(dict);
+}
 
 int main(int argc, char 

[Qemu-devel] [PATCH v5 12/20] qmp: introduce asynchronous command type

2019-07-15 Thread Marc-André Lureau
Add a new type of command, QmpCommandFuncAsync: those commands can
return later thanks to QmpReturn. This commit introduces the new type
and register function and teach qmp_dipatch() to call it without
qmp_return(). The async_fn callback will be responsible for calling
qmp_return(), either synchronously or asynchronously.

Signed-off-by: Marc-André Lureau 
---
 include/qapi/qmp/dispatch.h | 10 +-
 qapi/qmp-dispatch.c | 27 ---
 qapi/qmp-registry.c | 27 ---
 3 files changed, 49 insertions(+), 15 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 92d6fd1afb..6aef0abc70 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -21,6 +21,7 @@
 typedef struct QmpReturn QmpReturn;
 
 typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
+typedef void (QmpCommandAsyncFunc)(QDict *, QmpReturn *);
 
 typedef enum QmpCommandOptions
 {
@@ -28,12 +29,16 @@ typedef enum QmpCommandOptions
 QCO_NO_SUCCESS_RESP   =  (1U << 0),
 QCO_ALLOW_OOB =  (1U << 1),
 QCO_ALLOW_PRECONFIG   =  (1U << 2),
+QCO_ASYNC =  (1U << 3),
 } QmpCommandOptions;
 
 typedef struct QmpCommand
 {
 const char *name;
-QmpCommandFunc *fn;
+union {
+QmpCommandFunc *fn;
+QmpCommandAsyncFunc *async_fn;
+};
 QmpCommandOptions options;
 QTAILQ_ENTRY(QmpCommand) node;
 bool enabled;
@@ -88,6 +93,9 @@ void qmp_return_error(QmpReturn *qret, Error *err);
 
 void qmp_register_command(QmpCommandList *cmds, const char *name,
   QmpCommandFunc *fn, QmpCommandOptions options);
+void qmp_register_async_command(QmpCommandList *cmds, const char *name,
+QmpCommandAsyncFunc *fn,
+QmpCommandOptions options);
 const QmpCommand *qmp_find_command(const QmpCommandList *cmds,
const char *name);
 void qmp_session_init(QmpSession *session,
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 546a6c9f7b..1f493af67a 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -171,7 +171,7 @@ static QDict *qmp_dispatch_check_obj(const QObject 
*request, bool allow_oob,
 return dict;
 }
 
-static QObject *do_qmp_dispatch(const QmpCommandList *cmds, QObject *request,
+static QObject *do_qmp_dispatch(QmpSession *session, QObject *request,
 bool allow_oob, Error **errp)
 {
 Error *local_err = NULL;
@@ -193,7 +193,7 @@ static QObject *do_qmp_dispatch(const QmpCommandList *cmds, 
QObject *request,
 command = qdict_get_str(dict, "exec-oob");
 oob = true;
 }
-cmd = qmp_find_command(cmds, command);
+cmd = qmp_find_command(session->cmds, command);
 if (cmd == NULL) {
 error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
   "The command %s has not been found", command);
@@ -224,14 +224,19 @@ static QObject *do_qmp_dispatch(const QmpCommandList 
*cmds, QObject *request,
 qobject_ref(args);
 }
 
-cmd->fn(args, , _err);
-if (local_err) {
-error_propagate(errp, local_err);
-} else if (cmd->options & QCO_NO_SUCCESS_RESP) {
-g_assert(!ret);
-} else if (!ret) {
-/* TODO turn into assertion */
-ret = QOBJECT(qdict_new());
+
+if (cmd->options & QCO_ASYNC) {
+cmd->async_fn(args, qmp_return_new(session, request));
+} else {
+cmd->fn(args, , _err);
+if (local_err) {
+error_propagate(errp, local_err);
+} else if (cmd->options & QCO_NO_SUCCESS_RESP) {
+g_assert(!ret);
+} else if (!ret) {
+/* TODO turn into assertion */
+ret = QOBJECT(qdict_new());
+}
 }
 
 qobject_unref(args);
@@ -304,7 +309,7 @@ void qmp_dispatch(QmpSession *session, QObject *request, 
bool allow_oob)
 Error *err = NULL;
 QObject *ret;
 
-ret = do_qmp_dispatch(session->cmds, request, allow_oob, );
+ret = do_qmp_dispatch(session, request, allow_oob, );
 if (err) {
 qmp_return_error(qmp_return_new(session, request), err);
 } else if (ret) {
diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
index d0f9a1d3e3..0f3d521ce5 100644
--- a/qapi/qmp-registry.c
+++ b/qapi/qmp-registry.c
@@ -15,16 +15,37 @@
 #include "qemu/osdep.h"
 #include "qapi/qmp/dispatch.h"
 
-void qmp_register_command(QmpCommandList *cmds, const char *name,
-  QmpCommandFunc *fn, QmpCommandOptions options)
+
+static QmpCommand *qmp_command_new(QmpCommandList *cmds, const char *name,
+   QmpCommandOptions options)
 {
 QmpCommand *cmd = g_malloc0(sizeof(*cmd));
 
 cmd->name = name;
-cmd->fn = fn;
 cmd->enabled = true;
 cmd->options = options;
 QTAILQ_INSERT_TAIL(cmds, cmd, node);
+
+return cmd;
+}
+
+
+void qmp_register_command(QmpCommandList 

[Qemu-devel] [PATCH v5 10/20] QmpSession: keep a queue of pending commands

2019-07-15 Thread Marc-André Lureau
The following commit will introduce asynchronous commands. Let's keep
the session aware of the pending commands, so we can do interesting
things like order the replies, or cancel pending operations when the
client is gone.

The queue needs a lock, since QmpReturn may be called from any thread.

Signed-off-by: Marc-André Lureau 
---
 include/qapi/qmp/dispatch.h |  4 
 qapi/qmp-dispatch.c | 32 ++--
 2 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 6c0d21968e..7c9de9780d 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -16,6 +16,7 @@
 
 #include "qemu/queue.h"
 #include "qapi/qmp/json-parser.h"
+#include "qemu/thread.h"
 
 typedef struct QmpReturn QmpReturn;
 
@@ -47,11 +48,14 @@ struct QmpSession {
 const QmpCommandList *cmds;
 JSONMessageParser parser;
 QmpDispatchReturn *return_cb;
+QemuMutex pending_lock;
+QTAILQ_HEAD(, QmpReturn) pending;
 };
 
 struct QmpReturn {
 QmpSession *session;
 QDict *rsp;
+QTAILQ_ENTRY(QmpReturn) entry;
 };
 
 /**
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 5f75dc27bd..4699a6715b 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -32,11 +32,24 @@ QmpReturn *qmp_return_new(QmpSession *session, const 
QObject *request)
 qdict_put_obj(qret->rsp, "id", id);
 }
 
+qemu_mutex_lock(>pending_lock);
+QTAILQ_INSERT_TAIL(>pending, qret, entry);
+qemu_mutex_unlock(>pending_lock);
+
 return qret;
 }
 
 void qmp_return_free(QmpReturn *qret)
 {
+QmpSession *session = qret->session;
+
+if (session) {
+qemu_mutex_lock(>pending_lock);
+}
+QTAILQ_REMOVE(>pending, qret, entry);
+if (session) {
+qemu_mutex_unlock(>pending_lock);
+}
 qobject_unref(qret->rsp);
 g_free(qret);
 }
@@ -44,7 +57,9 @@ void qmp_return_free(QmpReturn *qret)
 void qmp_return(QmpReturn *qret, QObject *rsp)
 {
 qdict_put_obj(qret->rsp, "return", rsp ?: QOBJECT(qdict_new()));
-qret->session->return_cb(qret->session, qret->rsp);
+if (qret->session) {
+qret->session->return_cb(qret->session, qret->rsp);
+}
 qmp_return_free(qret);
 }
 
@@ -55,7 +70,9 @@ void qmp_return_error(QmpReturn *qret, Error *err)
 qdict_put_str(qdict, "desc", error_get_pretty(err));
 qdict_put_obj(qret->rsp, "error", QOBJECT(qdict));
 error_free(err);
-qret->session->return_cb(qret->session, qret->rsp);
+if (qret->session) {
+qret->session->return_cb(qret->session, qret->rsp);
+}
 qmp_return_free(qret);
 }
 
@@ -219,17 +236,28 @@ void qmp_session_init(QmpSession *session,
  session, NULL);
 session->cmds = cmds;
 session->return_cb = return_cb;
+qemu_mutex_init(>pending_lock);
+QTAILQ_INIT(>pending);
 }
 
 void qmp_session_destroy(QmpSession *session)
 {
+QmpReturn *ret, *next;
+
 if (!session->return_cb) {
 return;
 }
 
+qemu_mutex_lock(>pending_lock);
+QTAILQ_FOREACH_SAFE(ret, >pending, entry, next) {
+ret->session = NULL;
+QTAILQ_REMOVE(>pending, ret, entry);
+}
+qemu_mutex_unlock(>pending_lock);
 session->cmds = NULL;
 session->return_cb = NULL;
 json_message_parser_destroy(>parser);
+qemu_mutex_destroy(>pending_lock);
 }
 
 void qmp_dispatch(QmpSession *session, QObject *request, bool allow_oob)
-- 
2.22.0.428.g6d5b264208




[Qemu-devel] [PATCH v5 08/20] QmpSession: introduce QmpReturn

2019-07-15 Thread Marc-André Lureau
QmpReturn (and associated functions) is used during synchronous
dispatch return for now. It helps to factor out some code for
handling a reply context.

In the following patches, the QmpReturn will be the basis upon which
asynchronous reply will be handled: it will hold the context for a QMP
command reply.

Signed-off-by: Marc-André Lureau 
---
 include/qapi/qmp/dispatch.h | 34 -
 monitor/qmp.c   |  6 +--
 qapi/qmp-dispatch.c | 74 ++---
 3 files changed, 79 insertions(+), 35 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index b3ca6c9ff2..6c0d21968e 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -17,6 +17,8 @@
 #include "qemu/queue.h"
 #include "qapi/qmp/json-parser.h"
 
+typedef struct QmpReturn QmpReturn;
+
 typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
 
 typedef enum QmpCommandOptions
@@ -47,6 +49,37 @@ struct QmpSession {
 QmpDispatchReturn *return_cb;
 };
 
+struct QmpReturn {
+QmpSession *session;
+QDict *rsp;
+};
+
+/**
+ * qmp_return_new:
+ *
+ * Allocates and initializes a QmpReturn.
+ */
+QmpReturn *qmp_return_new(QmpSession *session, const QObject *req);
+
+/**
+ * qmp_return_free:
+ *
+ * Free a QmpReturn. This shouldn't be needed if you actually return
+ * with qmp_return{_error}.
+ */
+void qmp_return_free(QmpReturn *qret);
+
+/**
+ * qmp_return{_error}:
+ *
+ * Construct the command reply, and call the
+ * return_cb() associated with the session.
+ *
+ * Finally, free the QmpReturn.
+ */
+void qmp_return(QmpReturn *qret, QObject *rsp);
+void qmp_return_error(QmpReturn *qret, Error *err);
+
 void qmp_register_command(QmpCommandList *cmds, const char *name,
   QmpCommandFunc *fn, QmpCommandOptions options);
 const QmpCommand *qmp_find_command(const QmpCommandList *cmds,
@@ -67,7 +100,6 @@ void qmp_enable_command(QmpCommandList *cmds, const char 
*name);
 bool qmp_command_is_enabled(const QmpCommand *cmd);
 const char *qmp_command_name(const QmpCommand *cmd);
 bool qmp_has_success_response(const QmpCommand *cmd);
-QDict *qmp_error_response(Error *err);
 void qmp_dispatch(QmpSession *session, QObject *request,
   bool allow_oob);
 bool qmp_is_oob(const QDict *dict);
diff --git a/monitor/qmp.c b/monitor/qmp.c
index cd29494e28..056ad7b68b 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -179,7 +179,6 @@ static QMPRequest 
*monitor_qmp_requests_pop_any_with_lock(void)
 void monitor_qmp_bh_dispatcher(void *data)
 {
 QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock();
-QDict *rsp;
 bool need_resume;
 MonitorQMP *mon;
 
@@ -198,11 +197,10 @@ void monitor_qmp_bh_dispatcher(void *data)
 trace_monitor_qmp_cmd_in_band(qobject_get_try_str(id) ?: "");
 monitor_qmp_dispatch(mon, req_obj->req);
 } else {
+QmpSession *session = _obj->mon->session;
 assert(req_obj->err);
-rsp = qmp_error_response(req_obj->err);
+qmp_return_error(qmp_return_new(session, req_obj->req), req_obj->err);
 req_obj->err = NULL;
-qmp_send_response(req_obj->mon, rsp);
-qobject_unref(rsp);
 }
 
 if (need_resume) {
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index f2c376d005..405cb291b1 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -19,6 +19,46 @@
 #include "qapi/qmp/qbool.h"
 #include "sysemu/sysemu.h"
 
+QmpReturn *qmp_return_new(QmpSession *session, const QObject *request)
+{
+QmpReturn *qret = g_new0(QmpReturn, 1);
+const QDict *req = qobject_to(QDict, request);
+QObject *id = req ? qdict_get(req, "id") : NULL;
+
+qret->session = session;
+qret->rsp = qdict_new();
+if (id) {
+qobject_ref(id);
+qdict_put_obj(qret->rsp, "id", id);
+}
+
+return qret;
+}
+
+void qmp_return_free(QmpReturn *qret)
+{
+qobject_unref(qret->rsp);
+g_free(qret);
+}
+
+void qmp_return(QmpReturn *qret, QObject *rsp)
+{
+qdict_put_obj(qret->rsp, "return", rsp ?: QOBJECT(qdict_new()));
+qret->session->return_cb(qret->session, qret->rsp);
+qmp_return_free(qret);
+}
+
+void qmp_return_error(QmpReturn *qret, Error *err)
+{
+qdict_put_obj(qret->rsp, "error",
+  qobject_from_jsonf_nofail("{ 'class': %s, 'desc': %s }",
+  QapiErrorClass_str(error_get_class(err)),
+  error_get_pretty(err)));
+error_free(err);
+qret->session->return_cb(qret->session, qret->rsp);
+qmp_return_free(qret);
+}
+
 static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob,
  Error **errp)
 {
@@ -143,17 +183,6 @@ static QObject *do_qmp_dispatch(const QmpCommandList 
*cmds, QObject *request,
 return ret;
 }
 
-QDict *qmp_error_response(Error *err)
-{
-QDict *rsp;
-
-rsp = qdict_from_jsonf_nofail("{ 'error': { 'class': %s, 'desc': %s } }",
-   

[Qemu-devel] [PATCH v5 09/20] qmp: simplify qmp_return_error()

2019-07-15 Thread Marc-André Lureau
It's simple, probably more efficient, to hand-craft the dict.

Signed-off-by: Marc-André Lureau 
---
 qapi/qmp-dispatch.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 405cb291b1..5f75dc27bd 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -50,10 +50,10 @@ void qmp_return(QmpReturn *qret, QObject *rsp)
 
 void qmp_return_error(QmpReturn *qret, Error *err)
 {
-qdict_put_obj(qret->rsp, "error",
-  qobject_from_jsonf_nofail("{ 'class': %s, 'desc': %s }",
-  QapiErrorClass_str(error_get_class(err)),
-  error_get_pretty(err)));
+QDict *qdict = qdict_new();
+qdict_put_str(qdict, "class", QapiErrorClass_str(error_get_class(err)));
+qdict_put_str(qdict, "desc", error_get_pretty(err));
+qdict_put_obj(qret->rsp, "error", QOBJECT(qdict));
 error_free(err);
 qret->session->return_cb(qret->session, qret->rsp);
 qmp_return_free(qret);
-- 
2.22.0.428.g6d5b264208




[Qemu-devel] [PATCH v5 07/20] qga: simplify dispatch_return_cb

2019-07-15 Thread Marc-André Lureau
Fold send_response().

qobject_to_json() can't return NULL (it will crash if allocation
failed, either in memcpy() or abort from g_realloc()).

Signed-off-by: Marc-André Lureau 
---
 qga/main.c | 19 +++
 1 file changed, 3 insertions(+), 16 deletions(-)

diff --git a/qga/main.c b/qga/main.c
index b005550c70..66fe7ac3de 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -522,8 +522,9 @@ fail:
 #endif
 }
 
-static int send_response(GAState *s, const QDict *rsp)
+static void dispatch_return_cb(QmpSession *session, QDict *rsp)
 {
+GAState *s = container_of(session, GAState, session);
 const char *buf;
 QString *payload_qstr, *response_qstr;
 GIOStatus status;
@@ -531,9 +532,6 @@ static int send_response(GAState *s, const QDict *rsp)
 g_assert(rsp && s->channel);
 
 payload_qstr = qobject_to_json(QOBJECT(rsp));
-if (!payload_qstr) {
-return -EINVAL;
-}
 
 if (s->delimit_response) {
 s->delimit_response = false;
@@ -550,18 +548,7 @@ static int send_response(GAState *s, const QDict *rsp)
 status = ga_channel_write_all(s->channel, buf, strlen(buf));
 qobject_unref(response_qstr);
 if (status != G_IO_STATUS_NORMAL) {
-return -EIO;
-}
-
-return 0;
-}
-
-static void dispatch_return_cb(QmpSession *session, QDict *rsp)
-{
-GAState *s = container_of(session, GAState, session);
-int ret = send_response(s, rsp);
-if (ret < 0) {
-g_warning("error sending response: %s", strerror(-ret));
+g_warning("Failed sending response");
 }
 }
 
-- 
2.22.0.428.g6d5b264208




[Qemu-devel] [PATCH v5 06/20] monitor: use qmp session to parse json feed

2019-07-15 Thread Marc-André Lureau
Use the QmpSession json parser introduced in previous patch to
generalize the handling in both qemu & qemu-ga. Unfortunately, since
the introduction of OOB, it's not as common as it was before that. We
may want to move some of OOB logic in common qmp-dispatch.c/QmpSession
though.

The QEMU monitor has peculiar handling of the stream of commands, for
OOB command processing, which can be solved by overriding the json
emit callback.

Signed-off-by: Marc-André Lureau 
---
 include/qapi/qmp/dispatch.h|  1 +
 include/qapi/qmp/json-parser.h |  7 ---
 monitor/monitor-internal.h |  1 -
 monitor/qmp.c  | 13 +
 qapi/qmp-dispatch.c|  4 +++-
 qga/main.c |  2 +-
 qobject/json-streamer.c|  3 +--
 tests/test-qmp-cmds.c  | 11 ++-
 8 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index c84edff7d2..b3ca6c9ff2 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -53,6 +53,7 @@ const QmpCommand *qmp_find_command(const QmpCommandList *cmds,
const char *name);
 void qmp_session_init(QmpSession *session,
   const QmpCommandList *cmds,
+  JSONMessageEmit *emit,
   QmpDispatchReturn *return_cb);
 static inline void
 qmp_session_feed(QmpSession *session, const char *buf, size_t count)
diff --git a/include/qapi/qmp/json-parser.h b/include/qapi/qmp/json-parser.h
index 7345a9bd5c..6f168e8007 100644
--- a/include/qapi/qmp/json-parser.h
+++ b/include/qapi/qmp/json-parser.h
@@ -14,6 +14,8 @@
 #ifndef QAPI_QMP_JSON_PARSER_H
 #define QAPI_QMP_JSON_PARSER_H
 
+typedef void (JSONMessageEmit)(void *opaque, QObject *json, Error *err);
+
 typedef struct JSONLexer {
 int start_state, state;
 GString *token;
@@ -21,7 +23,7 @@ typedef struct JSONLexer {
 } JSONLexer;
 
 typedef struct JSONMessageParser {
-void (*emit)(void *opaque, QObject *json, Error *err);
+JSONMessageEmit *emit;
 void *opaque;
 va_list *ap;
 JSONLexer lexer;
@@ -32,8 +34,7 @@ typedef struct JSONMessageParser {
 } JSONMessageParser;
 
 void json_message_parser_init(JSONMessageParser *parser,
-  void (*emit)(void *opaque, QObject *json,
-   Error *err),
+  JSONMessageEmit *emit,
   void *opaque, va_list *ap);
 
 void json_message_parser_feed(JSONMessageParser *parser,
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index 65d587eafb..65cf668b20 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -125,7 +125,6 @@ struct MonitorHMP {
 
 typedef struct {
 Monitor common;
-JSONMessageParser parser;
 bool pretty;
 /*
  * When a client connects, we're in capabilities negotiation mode.
diff --git a/monitor/qmp.c b/monitor/qmp.c
index b215cb70f3..cd29494e28 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -217,7 +217,7 @@ void monitor_qmp_bh_dispatcher(void *data)
 
 static void handle_qmp_command(void *opaque, QObject *req, Error *err)
 {
-MonitorQMP *mon = opaque;
+MonitorQMP *mon = container_of(opaque, MonitorQMP, session);
 QObject *id = NULL;
 QDict *qdict;
 QMPRequest *req_obj;
@@ -279,7 +279,7 @@ static void monitor_qmp_read(void *opaque, const uint8_t 
*buf, int size)
 {
 MonitorQMP *mon = opaque;
 
-json_message_parser_feed(>parser, (const char *) buf, size);
+qmp_session_feed(>session, (const char *) buf, size);
 }
 
 static QDict *qmp_greeting(MonitorQMP *mon)
@@ -309,7 +309,9 @@ static void monitor_qmp_event(void *opaque, int event)
 switch (event) {
 case CHR_EVENT_OPENED:
 qmp_session_init(>session,
- _cap_negotiation_commands, dispatch_return_cb);
+ _cap_negotiation_commands,
+ handle_qmp_command,
+ dispatch_return_cb);
 monitor_qmp_caps_reset(mon);
 data = qmp_greeting(mon);
 qmp_send_response(mon, data);
@@ -325,9 +327,6 @@ static void monitor_qmp_event(void *opaque, int event)
  */
 monitor_qmp_cleanup_queues(mon);
 qmp_session_destroy(>session);
-json_message_parser_destroy(>parser);
-json_message_parser_init(>parser, handle_qmp_command,
- mon, NULL);
 mon_refcount--;
 monitor_fdsets_cleanup();
 break;
@@ -337,7 +336,6 @@ static void monitor_qmp_event(void *opaque, int event)
 void monitor_data_destroy_qmp(MonitorQMP *mon)
 {
 qmp_session_destroy(>session);
-json_message_parser_destroy(>parser);
 qemu_mutex_destroy(>qmp_queue_lock);
 monitor_qmp_cleanup_req_queue_locked(mon);
 g_queue_free(mon->qmp_requests);
@@ -373,7 +371,6 @@ void monitor_init_qmp(Chardev *chr, bool pretty)
 

[Qemu-devel] [PATCH v5 05/20] QmpSession: add json parser and use it in qga

2019-07-15 Thread Marc-André Lureau
Move JSON parser to QmpSession, and implement a simple handler to check
the parsed tokens and call qmp_dispatch(). This is enough for a simple
QMP client, like QGA.

The QEMU monitor has more complicated handling of dispatching which
will be addressed in a following patch to benefit from more common
code.

Signed-off-by: Marc-André Lureau 
---
 include/qapi/qmp/dispatch.h |  7 +++
 qapi/qmp-dispatch.c | 19 +++
 qga/main.c  | 31 +--
 3 files changed, 27 insertions(+), 30 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index d1ce631a93..c84edff7d2 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -15,6 +15,7 @@
 #define QAPI_QMP_DISPATCH_H
 
 #include "qemu/queue.h"
+#include "qapi/qmp/json-parser.h"
 
 typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
 
@@ -42,6 +43,7 @@ typedef void (QmpDispatchReturn) (QmpSession *session, QDict 
*rsp);
 
 struct QmpSession {
 const QmpCommandList *cmds;
+JSONMessageParser parser;
 QmpDispatchReturn *return_cb;
 };
 
@@ -52,6 +54,11 @@ const QmpCommand *qmp_find_command(const QmpCommandList 
*cmds,
 void qmp_session_init(QmpSession *session,
   const QmpCommandList *cmds,
   QmpDispatchReturn *return_cb);
+static inline void
+qmp_session_feed(QmpSession *session, const char *buf, size_t count)
+{
+json_message_parser_feed(>parser, buf, count);
+}
 void qmp_session_destroy(QmpSession *session);
 void qmp_disable_command(QmpCommandList *cmds, const char *name);
 void qmp_enable_command(QmpCommandList *cmds, const char *name);
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 37b058cf97..803ec626cd 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -163,6 +163,23 @@ bool qmp_is_oob(const QDict *dict)
 && !qdict_haskey(dict, "execute");
 }
 
+static void qmp_json_emit(void *opaque, QObject *obj, Error *err)
+{
+QmpSession *session = opaque;
+
+assert(!obj != !err);
+
+if (err) {
+QDict *rsp = qmp_error_response(err);
+session->return_cb(session, rsp);
+qobject_unref(rsp);
+} else {
+qmp_dispatch(session, obj, false);
+}
+
+qobject_unref(obj);
+}
+
 void qmp_session_init(QmpSession *session,
   const QmpCommandList *cmds,
   QmpDispatchReturn *return_cb)
@@ -170,6 +187,7 @@ void qmp_session_init(QmpSession *session,
 assert(return_cb);
 assert(!session->return_cb);
 
+json_message_parser_init(>parser, qmp_json_emit, session, NULL);
 session->cmds = cmds;
 session->return_cb = return_cb;
 }
@@ -182,6 +200,7 @@ void qmp_session_destroy(QmpSession *session)
 
 session->cmds = NULL;
 session->return_cb = NULL;
+json_message_parser_destroy(>parser);
 }
 
 void qmp_dispatch(QmpSession *session, QObject *request, bool allow_oob)
diff --git a/qga/main.c b/qga/main.c
index c291d06491..057368eb16 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -19,7 +19,6 @@
 #include 
 #endif
 #include "qemu-common.h"
-#include "qapi/qmp/json-parser.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qjson.h"
 #include "qapi/qmp/qstring.h"
@@ -75,7 +74,6 @@ typedef struct GAConfig GAConfig;
 
 struct GAState {
 QmpSession session;
-JSONMessageParser parser;
 GMainLoop *main_loop;
 GAChannel *channel;
 bool virtio; /* fastpath to check for virtio to deal with poll() quirks */
@@ -567,31 +565,6 @@ static void dispatch_return_cb(QmpSession *session, QDict 
*rsp)
 }
 }
 
-/* handle requests/control events coming in over the channel */
-static void process_event(void *opaque, QObject *obj, Error *err)
-{
-GAState *s = opaque;
-int ret;
-
-g_debug("process_event: called");
-assert(!obj != !err);
-
-if (err) {
-QDict *rsp = qmp_error_response(err);
-
-ret = send_response(s, rsp);
-if (ret < 0) {
-g_warning("error sending error response: %s", strerror(-ret));
-}
-qobject_unref(rsp);
-} else {
-g_debug("processing command");
-qmp_dispatch(>session, obj, false);
-}
-
-qobject_unref(obj);
-}
-
 /* false return signals GAChannel to close the current client connection */
 static gboolean channel_event_cb(GIOCondition condition, gpointer data)
 {
@@ -607,7 +580,7 @@ static gboolean channel_event_cb(GIOCondition condition, 
gpointer data)
 case G_IO_STATUS_NORMAL:
 buf[count] = 0;
 g_debug("read data, count: %d, data: %s", (int)count, buf);
-json_message_parser_feed(>parser, (char *)buf, (int)count);
+qmp_session_feed(>session, (char *)buf, (int)count);
 break;
 case G_IO_STATUS_EOF:
 g_debug("received EOF");
@@ -1346,7 +1319,6 @@ static GAState *initialize_agent(GAConfig *config, int 
socket_activation)
 s->command_state = ga_command_state_new();
 ga_command_state_init(s, 

[Qemu-devel] [PATCH v5 04/20] QmpSession: add a return callback

2019-07-15 Thread Marc-André Lureau
Introduce a return_cb to allow delaying finishing the dispatch
and sending the response asynchronously. For now, this is just
modifying qmp_dispatch() to call the callback synchronously.

Signed-off-by: Marc-André Lureau 
---
 include/qapi/qmp/dispatch.h | 10 --
 monitor/qmp.c   | 47 ++---
 qapi/qmp-dispatch.c | 22 +---
 qga/main.c  | 34 +++---
 tests/test-qmp-cmds.c   | 69 ++---
 5 files changed, 98 insertions(+), 84 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 3b53cfd788..d1ce631a93 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -38,16 +38,20 @@ typedef struct QmpCommand
 typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList;
 
 typedef struct QmpSession QmpSession;
+typedef void (QmpDispatchReturn) (QmpSession *session, QDict *rsp);
 
 struct QmpSession {
 const QmpCommandList *cmds;
+QmpDispatchReturn *return_cb;
 };
 
 void qmp_register_command(QmpCommandList *cmds, const char *name,
   QmpCommandFunc *fn, QmpCommandOptions options);
 const QmpCommand *qmp_find_command(const QmpCommandList *cmds,
const char *name);
-void qmp_session_init(QmpSession *session, const QmpCommandList *cmds);
+void qmp_session_init(QmpSession *session,
+  const QmpCommandList *cmds,
+  QmpDispatchReturn *return_cb);
 void qmp_session_destroy(QmpSession *session);
 void qmp_disable_command(QmpCommandList *cmds, const char *name);
 void qmp_enable_command(QmpCommandList *cmds, const char *name);
@@ -56,8 +60,8 @@ bool qmp_command_is_enabled(const QmpCommand *cmd);
 const char *qmp_command_name(const QmpCommand *cmd);
 bool qmp_has_success_response(const QmpCommand *cmd);
 QDict *qmp_error_response(Error *err);
-QDict *qmp_dispatch(QmpSession *session, QObject *request,
-bool allow_oob);
+void qmp_dispatch(QmpSession *session, QObject *request,
+  bool allow_oob);
 bool qmp_is_oob(const QDict *dict);
 
 typedef void (*qmp_cmd_callback_fn)(const QmpCommand *cmd, void *opaque);
diff --git a/monitor/qmp.c b/monitor/qmp.c
index dd72a0d8cf..b215cb70f3 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -96,45 +96,35 @@ void qmp_send_response(MonitorQMP *mon, const QDict *rsp)
 qobject_unref(json);
 }
 
-/*
- * Emit QMP response @rsp with ID @id to @mon.
- * Null @rsp can only happen for commands with QCO_NO_SUCCESS_RESP.
- * Nothing is emitted then.
- */
-static void monitor_qmp_respond(MonitorQMP *mon, QDict *rsp)
+static void dispatch_return_cb(QmpSession *session, QDict *rsp)
 {
-if (rsp) {
-qmp_send_response(mon, rsp);
+MonitorQMP *mon = container_of(session, MonitorQMP, session);
+
+if (mon->session.cmds == _cap_negotiation_commands) {
+QDict *error = qdict_get_qdict(rsp, "error");
+if (error
+&& !g_strcmp0(qdict_get_try_str(error, "class"),
+  QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) {
+/* Provide a more useful error message */
+qdict_del(error, "desc");
+qdict_put_str(error, "desc", "Expecting capabilities negotiation"
+  " with 'qmp_capabilities'");
+}
 }
+
+qmp_send_response(mon, rsp);
 }
 
 static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req)
 {
 Monitor *old_mon;
-QDict *rsp;
-QDict *error;
 
 old_mon = cur_mon;
 cur_mon = >common;
 
-rsp = qmp_dispatch(>session, req, qmp_oob_enabled(mon));
+qmp_dispatch(>session, req, qmp_oob_enabled(mon));
 
 cur_mon = old_mon;
-
-if (mon->session.cmds == _cap_negotiation_commands) {
-error = qdict_get_qdict(rsp, "error");
-if (error
-&& !g_strcmp0(qdict_get_try_str(error, "class"),
-QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) {
-/* Provide a more useful error message */
-qdict_del(error, "desc");
-qdict_put_str(error, "desc", "Expecting capabilities negotiation"
-  " with 'qmp_capabilities'");
-}
-}
-
-monitor_qmp_respond(mon, rsp);
-qobject_unref(rsp);
 }
 
 /*
@@ -211,7 +201,7 @@ void monitor_qmp_bh_dispatcher(void *data)
 assert(req_obj->err);
 rsp = qmp_error_response(req_obj->err);
 req_obj->err = NULL;
-monitor_qmp_respond(mon, rsp);
+qmp_send_response(req_obj->mon, rsp);
 qobject_unref(rsp);
 }
 
@@ -318,7 +308,8 @@ static void monitor_qmp_event(void *opaque, int event)
 
 switch (event) {
 case CHR_EVENT_OPENED:
-qmp_session_init(>session, _cap_negotiation_commands);
+qmp_session_init(>session,
+ _cap_negotiation_commands, dispatch_return_cb);
 monitor_qmp_caps_reset(mon);
 data = 

[Qemu-devel] [PATCH v5 03/20] qmp: add QmpSession

2019-07-15 Thread Marc-André Lureau
This structure will hold various data related to a QMP client session:
the list of commands, the parser, the callbacks, the pending
operations...

Signed-off-by: Marc-André Lureau 
---
 include/qapi/qmp/dispatch.h | 10 +-
 monitor/misc.c  |  6 +++---
 monitor/monitor-internal.h  |  2 +-
 monitor/monitor.c   |  2 +-
 monitor/qmp.c   |  8 +---
 qapi/qmp-dispatch.c | 15 ---
 qga/main.c  |  5 -
 tests/test-qmp-cmds.c   | 28 ++--
 8 files changed, 57 insertions(+), 19 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 5a9cf82472..3b53cfd788 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -37,10 +37,18 @@ typedef struct QmpCommand
 
 typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList;
 
+typedef struct QmpSession QmpSession;
+
+struct QmpSession {
+const QmpCommandList *cmds;
+};
+
 void qmp_register_command(QmpCommandList *cmds, const char *name,
   QmpCommandFunc *fn, QmpCommandOptions options);
 const QmpCommand *qmp_find_command(const QmpCommandList *cmds,
const char *name);
+void qmp_session_init(QmpSession *session, const QmpCommandList *cmds);
+void qmp_session_destroy(QmpSession *session);
 void qmp_disable_command(QmpCommandList *cmds, const char *name);
 void qmp_enable_command(QmpCommandList *cmds, const char *name);
 
@@ -48,7 +56,7 @@ bool qmp_command_is_enabled(const QmpCommand *cmd);
 const char *qmp_command_name(const QmpCommand *cmd);
 bool qmp_has_success_response(const QmpCommand *cmd);
 QDict *qmp_error_response(Error *err);
-QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
+QDict *qmp_dispatch(QmpSession *session, QObject *request,
 bool allow_oob);
 bool qmp_is_oob(const QDict *dict);
 
diff --git a/monitor/misc.c b/monitor/misc.c
index a0fc5111c5..a23c1b8ba4 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -253,7 +253,7 @@ CommandInfoList *qmp_query_commands(Error **errp)
 assert(monitor_is_qmp(cur_mon));
 mon = container_of(cur_mon, MonitorQMP, common);
 
-qmp_for_each_command(mon->commands, query_commands_cb, );
+qmp_for_each_command(mon->session.cmds, query_commands_cb, );
 
 return list;
 }
@@ -363,7 +363,7 @@ void qmp_qmp_capabilities(bool has_enable, 
QMPCapabilityList *enable,
 assert(monitor_is_qmp(cur_mon));
 mon = container_of(cur_mon, MonitorQMP, common);
 
-if (mon->commands == _commands) {
+if (mon->session.cmds == _commands) {
 error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
   "Capabilities negotiation is already complete, command "
   "ignored");
@@ -374,7 +374,7 @@ void qmp_qmp_capabilities(bool has_enable, 
QMPCapabilityList *enable,
 return;
 }
 
-mon->commands = _commands;
+mon->session.cmds = _commands;
 }
 
 /* Set the current CPU defined by the user. Callers must hold BQL. */
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index b0a028dbf8..65d587eafb 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -133,7 +133,7 @@ typedef struct {
  * qmp_capabilities succeeds, we go into command mode, and
  * @command becomes _commands.
  */
-const QmpCommandList *commands;
+QmpSession session;
 bool capab_offered[QMP_CAPABILITY__MAX]; /* capabilities offered */
 bool capab[QMP_CAPABILITY__MAX]; /* offered and accepted */
 /*
diff --git a/monitor/monitor.c b/monitor/monitor.c
index 3ef28171c0..9d918c9952 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -262,7 +262,7 @@ static void monitor_qapi_event_emit(QAPIEvent event, QDict 
*qdict)
 }
 
 qmp_mon = container_of(mon, MonitorQMP, common);
-if (qmp_mon->commands != _cap_negotiation_commands) {
+if (qmp_mon->session.cmds != _cap_negotiation_commands) {
 qmp_send_response(qmp_mon, qdict);
 }
 }
diff --git a/monitor/qmp.c b/monitor/qmp.c
index e1b196217d..dd72a0d8cf 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -117,11 +117,11 @@ static void monitor_qmp_dispatch(MonitorQMP *mon, QObject 
*req)
 old_mon = cur_mon;
 cur_mon = >common;
 
-rsp = qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon));
+rsp = qmp_dispatch(>session, req, qmp_oob_enabled(mon));
 
 cur_mon = old_mon;
 
-if (mon->commands == _cap_negotiation_commands) {
+if (mon->session.cmds == _cap_negotiation_commands) {
 error = qdict_get_qdict(rsp, "error");
 if (error
 && !g_strcmp0(qdict_get_try_str(error, "class"),
@@ -318,7 +318,7 @@ static void monitor_qmp_event(void *opaque, int event)
 
 switch (event) {
 case CHR_EVENT_OPENED:
-mon->commands = _cap_negotiation_commands;
+qmp_session_init(>session, _cap_negotiation_commands);
 

[Qemu-devel] [PATCH v5 02/20] json-lexer: make it safe to call destroy multiple times

2019-07-15 Thread Marc-André Lureau
We can easily avoid the burden of checking if the lexer was
initialized prior to calling destroy by the caller, let's do it.

This allows simplification in state tracking with the following patch,
"qmp: add QmpSession" can call qmp_session_destroy() multiple times,
which in turns calls json_lexer_destroy().

Signed-off-by: Marc-André Lureau 
---
 qobject/json-lexer.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c
index 632320d72d..fa7a2c43a8 100644
--- a/qobject/json-lexer.c
+++ b/qobject/json-lexer.c
@@ -361,5 +361,8 @@ void json_lexer_flush(JSONLexer *lexer)
 
 void json_lexer_destroy(JSONLexer *lexer)
 {
-g_string_free(lexer->token, true);
+if (lexer->token) {
+g_string_free(lexer->token, true);
+lexer->token = NULL;
+}
 }
-- 
2.22.0.428.g6d5b264208




[Qemu-devel] [PATCH v5 01/20] qmp: constify QmpCommand and list

2019-07-15 Thread Marc-André Lureau
Since 0b69f6f72ce47a37a749b056b6d5ec64c61f11e8 "qapi: remove
qmp_unregister_command()", the command list can be declared const.

Signed-off-by: Marc-André Lureau 
---
 include/qapi/qmp/dispatch.h | 9 +
 monitor/misc.c  | 2 +-
 monitor/monitor-internal.h  | 2 +-
 qapi/qmp-dispatch.c | 6 +++---
 qapi/qmp-registry.c | 6 +++---
 qga/commands.c  | 2 +-
 qga/main.c  | 6 +++---
 7 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 9aa426a398..5a9cf82472 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -39,7 +39,8 @@ typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) 
QmpCommandList;
 
 void qmp_register_command(QmpCommandList *cmds, const char *name,
   QmpCommandFunc *fn, QmpCommandOptions options);
-QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name);
+const QmpCommand *qmp_find_command(const QmpCommandList *cmds,
+   const char *name);
 void qmp_disable_command(QmpCommandList *cmds, const char *name);
 void qmp_enable_command(QmpCommandList *cmds, const char *name);
 
@@ -47,13 +48,13 @@ bool qmp_command_is_enabled(const QmpCommand *cmd);
 const char *qmp_command_name(const QmpCommand *cmd);
 bool qmp_has_success_response(const QmpCommand *cmd);
 QDict *qmp_error_response(Error *err);
-QDict *qmp_dispatch(QmpCommandList *cmds, QObject *request,
+QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
 bool allow_oob);
 bool qmp_is_oob(const QDict *dict);
 
-typedef void (*qmp_cmd_callback_fn)(QmpCommand *cmd, void *opaque);
+typedef void (*qmp_cmd_callback_fn)(const QmpCommand *cmd, void *opaque);
 
-void qmp_for_each_command(QmpCommandList *cmds, qmp_cmd_callback_fn fn,
+void qmp_for_each_command(const QmpCommandList *cmds, qmp_cmd_callback_fn fn,
   void *opaque);
 
 #endif
diff --git a/monitor/misc.c b/monitor/misc.c
index 00338c002a..a0fc5111c5 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -230,7 +230,7 @@ static void hmp_info_help(Monitor *mon, const QDict *qdict)
 help_cmd(mon, "info");
 }
 
-static void query_commands_cb(QmpCommand *cmd, void *opaque)
+static void query_commands_cb(const QmpCommand *cmd, void *opaque)
 {
 CommandInfoList *info, **list = opaque;
 
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index 7760b22ba3..b0a028dbf8 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -133,7 +133,7 @@ typedef struct {
  * qmp_capabilities succeeds, we go into command mode, and
  * @command becomes _commands.
  */
-QmpCommandList *commands;
+const QmpCommandList *commands;
 bool capab_offered[QMP_CAPABILITY__MAX]; /* capabilities offered */
 bool capab[QMP_CAPABILITY__MAX]; /* offered and accepted */
 /*
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index e2c366e09e..f9d43046aa 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -75,14 +75,14 @@ static QDict *qmp_dispatch_check_obj(const QObject 
*request, bool allow_oob,
 return dict;
 }
 
-static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
+static QObject *do_qmp_dispatch(const QmpCommandList *cmds, QObject *request,
 bool allow_oob, Error **errp)
 {
 Error *local_err = NULL;
 bool oob;
 const char *command;
 QDict *args, *dict;
-QmpCommand *cmd;
+const QmpCommand *cmd;
 QObject *ret = NULL;
 
 dict = qmp_dispatch_check_obj(request, allow_oob, errp);
@@ -163,7 +163,7 @@ bool qmp_is_oob(const QDict *dict)
 && !qdict_haskey(dict, "execute");
 }
 
-QDict *qmp_dispatch(QmpCommandList *cmds, QObject *request,
+QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
 bool allow_oob)
 {
 Error *err = NULL;
diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
index ca00f74795..d0f9a1d3e3 100644
--- a/qapi/qmp-registry.c
+++ b/qapi/qmp-registry.c
@@ -27,7 +27,7 @@ void qmp_register_command(QmpCommandList *cmds, const char 
*name,
 QTAILQ_INSERT_TAIL(cmds, cmd, node);
 }
 
-QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name)
+const QmpCommand *qmp_find_command(const QmpCommandList *cmds, const char 
*name)
 {
 QmpCommand *cmd;
 
@@ -77,10 +77,10 @@ bool qmp_has_success_response(const QmpCommand *cmd)
 return !(cmd->options & QCO_NO_SUCCESS_RESP);
 }
 
-void qmp_for_each_command(QmpCommandList *cmds, qmp_cmd_callback_fn fn,
+void qmp_for_each_command(const QmpCommandList *cmds, qmp_cmd_callback_fn fn,
   void *opaque)
 {
-QmpCommand *cmd;
+const QmpCommand *cmd;
 
 QTAILQ_FOREACH(cmd, cmds, node) {
 fn(cmd, opaque);
diff --git a/qga/commands.c b/qga/commands.c
index 0c7d1385c2..05e9ab6c3d 100644
--- a/qga/commands.c
+++ b/qga/commands.c
@@ -54,7 +54,7 

[Qemu-devel] [PATCH v5 00/20] monitor: add asynchronous command type

2019-07-15 Thread Marc-André Lureau
Hi,

HMP and QMP commands are handled synchronously in qemu today. But
there are benefits allowing the command handler to re-enter the main
loop if the command cannot be handled synchronously, or if it is
long-lasting. Some bugs such as rhbz#1230527 are difficult to solve
without it.

The common solution is to use a pair of command+event in this case.
But this approach has a number of issues:
- you can't "fix" an existing command: you need a new API, and ad-hoc
  documentation for that command+signal association, and old/broken
  command deprecation
- since the reply event is broadcasted and 'id' is used for matching the
  request, it may conflict with other clients request 'id' space
- it is arguably less efficient and elegant (weird API, useless return
  in most cases, broadcast reply, no cancelling on disconnect etc)

The following series implements an async command solution instead. By
introducing a session context and a command return handler, it can:
- defer the return, allowing the mainloop to reenter
- return only to the caller (instead of broadcast events for reply)
- optionnally allow cancellation when the client is gone
- track on-going qapi command(s) per client/session

and without introduction of new QMP APIs or client visible change.

Existing qemu commands can be gradually replaced by async:true
variants when needed, while carefully reviewing the concurrency
aspects. The async:true commands marshaller helpers are splitted in
half, the calling and return functions. The command is called with a
QmpReturn context, that can return immediately or later, using the
generated return helper, which allows for a step-by-step conversion.

The screendump command is converted to an async:true version to solve
rhbz#1230527. The command shows basic cancellation (this could be
extended if needed). It could be further improved to do asynchronous
IO writes as well.

v5:
- rebased

v4:
- rebased, mostly adapting to new OOB code
  (there was not much feedback in v3 for the async command part,
   but preliminary patches got merged!)
- drop the RFC status

v3:
- complete rework, dropping the asynchronous commands visibility from
  the protocol side entirely (until there is a real need for it)
- rebased, with a few preliminary cleanup patches
- teach asynchronous commands to HMP

v2:
- documentation fixes and improvements
- fix calling async commands sync without id
- fix bad hmp monitor assert
- add a few extra asserts
- add async with no-id failure and screendump test

Marc-André Lureau (20):
  qmp: constify QmpCommand and list
  json-lexer: make it safe to call destroy multiple times
  qmp: add QmpSession
  QmpSession: add a return callback
  QmpSession: add json parser and use it in qga
  monitor: use qmp session to parse json feed
  qga: simplify dispatch_return_cb
  QmpSession: introduce QmpReturn
  qmp: simplify qmp_return_error()
  QmpSession: keep a queue of pending commands
  QmpSession: return orderly
  qmp: introduce asynchronous command type
  scripts: learn 'async' qapi commands
  qmp: add qmp_return_is_cancelled()
  monitor: add qmp_return_get_monitor()
  console: add graphic_hw_update_done()
  console: make screendump asynchronous
  monitor: start making qmp_human_monitor_command() asynchronous
  monitor: teach HMP about asynchronous commands
  hmp: call the asynchronous QMP screendump to fix outdated/glitches

 hmp-commands.hx |   3 +-
 hw/display/qxl-render.c |   9 +-
 hw/display/qxl.c|   1 +
 include/monitor/monitor.h   |   3 +
 include/qapi/qmp/dispatch.h |  89 +-
 include/qapi/qmp/json-parser.h  |   7 +-
 include/ui/console.h|   4 +
 monitor/hmp-cmds.c  |   6 +-
 monitor/hmp.c   | 110 +++-
 monitor/misc.c  |  46 +
 monitor/monitor-internal.h  |  12 +-
 monitor/monitor.c   |   2 +-
 monitor/qmp.c   |  79 -
 qapi/misc.json  |   3 +-
 qapi/qmp-dispatch.c | 214 +++-
 qapi/qmp-registry.c |  33 +++-
 qapi/ui.json|   3 +-
 qga/commands.c  |   2 +-
 qga/main.c  |  51 ++
 qobject/json-lexer.c|   5 +-
 qobject/json-streamer.c |   3 +-
 scripts/qapi/commands.py| 151 ++---
 scripts/qapi/common.py  |  15 +-
 scripts/qapi/doc.py |   3 +-
 scripts/qapi/introspect.py  |   3 +-
 tests/qapi-schema/qapi-schema-test.json |   5 +
 tests/qapi-schema/qapi-schema-test.out  |   8 +
 tests/qapi-schema/test-qapi.py  |   8 +-
 tests/test-qmp-cmds.c   | 206 +++
 ui/console.c| 100 +--
 30 files changed, 

Re: [Qemu-devel] [PATCH v4 17/20] console: make screendump asynchronous

2019-07-15 Thread Marc-André Lureau
On Wed, Apr 10, 2019 at 12:49 PM Gerd Hoffmann  wrote:
>
> > +static void qmp_screendump_finish(QemuConsole *con, struct qmp_screendump 
> > *dump)
> > +{
> > +Error *err = NULL;
> > +DisplaySurface *surface;
> > +Monitor *prev_mon = cur_mon;
>
> Why this is needed?
>

ppm_save() calls qemu_open() which may lookup fd associated to the
monitor: monitor_fdset_get_fd().

Interestingly, it seems fdset are not coupled with the current
monitor, so it's probably unnecessary to update the monitor to the one
associated with the command invocation.

> > +/*
> > + * FIXME: async save with coroutine? it would have to copy or
> > + * lock the surface.
> > + */
> > +ppm_save(dump->filename, surface, );
>
> DisplaySurface is just a thin layer above pixman images these days.
> Pixman images are reference counted, so you can
> pixman_image_ref(surface->image) to make sure it doesn't disappear
> underneath you, then pass the pixman image to ppm_save.

ppm_save() is still synchronous. I suppose you suggested that for a
future async version. (note that in this case, ref the surface is
probably not sufficient, as it could be mutated while it is being
saved)

-- 
Marc-André Lureau



  1   2   3   4   >