Re: [Qemu-devel] [PULL 00/25] RISC-V Post-merge spec conformance and cleanup
On 20.03.2018 23:25, Michael Clark wrote: > The following changes since commit f1a63fcfcd92c88be8942b5ae71aef9749a4f135: > > Update version for v2.12.0-rc0 release (2018-03-20 19:04:22 +) > > are available in the git repository at: > > https://github.com/riscv/riscv-qemu.git tags/riscv-qemu-2.12-fixes > > for you to fetch changes up to e1a247183ac0816284dfda61423f7030b6686679: > > RISC-V: Remove erroneous comment from translate.c (2018-03-20 14:34:13 > -0700) > > > This is a series of spec conformance bug fixes and code cleanups > that we would like to get in before the QEMU 2.12 release. Hi Michael, for future PULL request, could you please send out all patches again that should be pulled, and not send the cover letter alone? I.e. do a "git format-patch --subject-prefix PULL ..." and then replace the contents of the cover letter with the output of "git request-pull". ... this is how all other maintainers are sending PULL requests (at least as far as I know) and this way everybody gets a very final chance to have a look at the patches in their final state (it does not happen very often that someone replies to such patches, but in some rare cases we already found problems this way). Thank you very much for your efforts, Thomas signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [Qemu-ppc] [PATCH] qemu: include generated files with <> and not ""
On 20.03.2018 13:05, Michael S. Tsirkin wrote: > On Tue, Mar 20, 2018 at 09:58:23AM +0100, Laurent Vivier wrote: >> Le 20/03/2018 à 02:54, Michael S. Tsirkin a écrit : >>> QEMU coding style at the moment asks for all non-system >>> include files to be used with #include "foo.h". >>> However this rule actually does not make sense and >>> creates issues for when the included file is generated. >> >> If you change that, we can have issue when a system include has the same >> name as our local include. With "", system header are taken first. > > Are you sure? I just tested and that is not the case with > either gcc or clang. > >>> In C, include "file" means look in current directory, >>> then on include search path. Current directory here >>> means the source file directory. >>> By comparison include means look on include search path. >> >> Not exactly, there is the notion of "system header" too. >> >> https://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html >> >> #include >> This variant is used for system header files. It searches for a file >> named file in a standard list of system directories. You can prepend >> directories to this list with the -I option (see Invocation). > > This is exactly what we do. > >> #include "file" >> This variant is used for header files of your own program. It searches >> for a file named file first in the directory containing the current >> file, then in the quote directories and then the same directories used >> for . You can prepend directories to the list of quote directories >> with the -iquote option. > > Since we do not use -iquote, "" just adds the current directory. So why don't we simply switch to use -iquote instead of -I for adding search paths for our own headers? We then would get a clean separation of QEMU headers from system headers. Thomas
Re: [Qemu-devel] [Qemu-arm] [PATCH v2 2/2] arm_gicv3_kvm: kvm_dist_get/put: skip the registers banked by GICR
On 2018/3/20 19:54, Peter Maydell wrote: > On 20 March 2018 at 11:36, Shannon Zhao wrote: >> >> >> On 2018/3/20 19:22, Peter Maydell wrote: >>> On 20 March 2018 at 07:26, Shannon Zhao wrote: While we skip the GIC_INTERNAL irqs, we don't change the register offset accordingly. This will overlap the GICR registers value and leave the last GIC_INTERNAL irq's registers out of update. Fix this by skipping the registers banked by GICR. >>> >>> I'm still not entirely sure what the underlying problem >>> you're trying to fix is... >>> >>> Do we fail to correctly migrate a VM without this change? >>> Does the code work on some host CPU/GIC implementations but >>> not others? Is this just improving efficiency by avoiding >>> doing some unnecessary work? >>> >> When we reboot a VM and before entering uefi or guest kernel, we expect >> all these registers staying at the initial state. But currently these >> registers of the last 32 irqs are not reset. For example, the PRIORITY >> of irq from 32 to 255 is 0 but the PRIORITY of irq from 256 to 287 is >> 0xa0(Linux kernel set the PRIORITY to 0xa0 by default). >> >> When migrating a VM, since we don't save and restore the registers of >> the last 32 irq, so the PRIORITY is 0 while we expecting 0xa0. >> And also it will overlap the PRIORITY of SGIs and PPIs. >> >> We don't fail to migrate a vm since currently we don't use the last 32 >> irqs in virt machine. But the bug is still there. > > Oh, I see, the number of registers we transfer is accounting > for the first N registers in the bank not being used, but the > first register offset to transfer wasn't. > > Can you still successfully migrate a VM from a QEMU version > without this bugfix to one with the bugfix ? > I've tested this case. I can migrate a VM between these two versions. Thanks, -- Shannon
Re: [Qemu-devel] make vm-test [was: [PATCH] maintainers: Add myself as a OpenBSD maintainer]
On Mon, 03/19 17:06, Eric Blake wrote: > On 02/16/2018 11:44 AM, Philippe Mathieu-Daudé wrote: > > On 02/16/2018 02:41 PM, Kamil Rytarowski wrote: > > > On 16.02.2018 18:30, Philippe Mathieu-Daudé wrote: > > > > But before announcing the host OS being supported again, I'd rather see > > > > reproducible build/tests logs, in a (public - if possible) continuous > > > > integration system. Else it is hard to notice when it get broken. > > > > > > > > > > This is already done for FreeBSD, NetBSD and OpenBSD. > > > > We have the ability to run those, but afaik no CI are using them. > > > > $ make vm-test > > vm-test: Test QEMU in preconfigured virtual machines > > > >vm-build-ubuntu.i386- Build QEMU in ubuntu i386 VM > >vm-build-freebsd- Build QEMU in FreeBSD VM > >vm-build-netbsd - Build QEMU in NetBSD VM > >vm-build-openbsd- Build QEMU in OpenBSD VM > > > > > > > > CC: Fam who can confirm this. > > Thanks for this; today was my first day trying the various vm-build- > targets. > > Question: is this expected behavior? > > $ make vm-build-ubuntu.i386 > VM-IMAGE ubuntu.i386 > ... > Image resized. > debconf: unable to initialize frontend: Dialog > debconf: (TERM is not set, so the dialog frontend is not usable.) > debconf: falling back to frontend: Readline > debconf: unable to initialize frontend: Readline > debconf: (This frontend requires a controlling tty.) > debconf: falling back to frontend: Teletype > dpkg-preconfigure: unable to re-open stdin: > Connection to 127.0.0.1 closed by remote host. > ... > Cloning into > '/home/eblake/qemu/vm-test-VoVkBv.tmp/data-5ba3c.tar.vroot/ui/keycodemapdb'... > sudo: unable to resolve host ubuntu-guest > make[1]: flex: Command not found > ... > make[1]: flex: Command not found > Could not access KVM kernel module: No such file or directory > qemu-system-i386: failed to initialize KVM: No such file or directory > qemu-system-i386: Back to tcg accelerator > > I'm wondering if the image initialized incorrectly, and as a result can't do > as much as it's supposed to do, or runs way slower than it needs to? The > command eventually completed with status 0, but failed to find a 32-bit > compile error in the rdma code, and the output log does not look like it > actually attempted to compile anything in qemu (unless it did compile it, > but the logs were not output to stdout/stderr). > > make vm-build-freebsd was a lot faster at completing for me (but shows that > we still have a lot of clang warnings about address of a packed struct > member). > Was it a clean repo? Did you try "rm -rf ~/.cache/qemu-vm"? This morning the command worked for me from a clean env (on RHEL 7, using a QEMU built from qemu.git), and I didn't see the errors/warnings you pasted. (BTW I don't understand how sudo has anything to do with the dummy host name.) Fam
Re: [Qemu-devel] [PATCH 1/8] migration: stop compressing page in migration thread
On Fri, Mar 16, 2018 at 04:05:14PM +0800, Xiao Guangrong wrote: > > Hi David, > > Thanks for your review. > > On 03/15/2018 06:25 PM, Dr. David Alan Gilbert wrote: > > > > migration/ram.c | 32 > > > > Hi, > >Do you have some performance numbers to show this helps? Were those > > taken on a normal system or were they taken with one of the compression > > accelerators (which I think the compression migration was designed for)? > > Yes, i have tested it on my desktop, i7-4790 + 16G, by locally live migrate > the VM which has 8 vCPUs + 6G memory and the max-bandwidth is limited to 350. > > During the migration, a workload which has 8 threads repeatedly written total > 6G memory in the VM. Before this patchset, its bandwidth is ~25 mbps, after > applying, the bandwidth is ~50 mbps. Hi, Guangrong, Not really review comments, but I got some questions. :) IIUC this patch will only change the behavior when last_sent_block changed. I see that the performance is doubled after the change, which is really promising. However I don't fully understand why it brings such a big difference considering that IMHO current code is sending dirty pages per-RAMBlock. I mean, IMHO last_sent_block should not change frequently? Or am I wrong? Another follow-up question would be: have you measured how long time needed to compress a 4k page, and how many time to send it? I think "sending the page" is not really meaningful considering that we just put a page into the buffer (which should be extremely fast since we don't really flush it every time), however I would be curious on how slow would compressing a page be. Thanks, > > BTW, Compression will use almost all valid bandwidth after all of our work > which i will post it out part by part. > -- Peter Xu
Re: [Qemu-devel] [PATCH v2 2/2] arm_gicv3_kvm: kvm_dist_get/put: skip the registers banked by GICR
On 2018/3/20 16:42, Auger Eric wrote: > Hi Shannon, > On 20/03/18 08:26, Shannon Zhao wrote: >> While we skip the GIC_INTERNAL irqs, we don't change the register offset >> accordingly. This will overlap the GICR registers value and leave the >> last GIC_INTERNAL irq's registers out of update. >> >> Fix this by skipping the registers banked by GICR. >> >> Signed-off-by: Shannon Zhao >> --- >> hw/intc/arm_gicv3_kvm.c | 38 ++ >> 1 file changed, 38 insertions(+) >> >> diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c >> index 3536795..d423cba 100644 >> --- a/hw/intc/arm_gicv3_kvm.c >> +++ b/hw/intc/arm_gicv3_kvm.c >> @@ -136,6 +136,12 @@ static void kvm_dist_get_priority(GICv3State *s, >> uint32_t offset, uint8_t *bmp) >> int irq; >> >> field = (uint32_t *)bmp; >> +/* For the KVM GICv3, affinity routing is always enabled, and the first >> 8 >> + * GICD_IPRIORITYR registers are always RAZ/WI. The corresponding >> + * functionality is replaced by GICR_IPRIORITYR. So it doesn't need >> to >> + * sync them. >> + */ >> +offset += (8 * sizeof(uint32_t)); >> for_each_dist_irq_reg(irq, s->num_irq, 8) { >> kvm_gicd_access(s, offset, ®, false); >> *field = reg; >> @@ -150,6 +156,12 @@ static void kvm_dist_put_priority(GICv3State *s, >> uint32_t offset, uint8_t *bmp) >> int irq; >> >> field = (uint32_t *)bmp; >> +/* For the KVM GICv3, affinity routing is always enabled, and the first >> 8 >> + * GICD_IPRIORITYR registers are always RAZ/WI. The corresponding >> + * functionality is replaced by GICR_IPRIORITYR. So it doesn't need >> to >> + * sync them. >> + */ >> +offset += (8 * sizeof(uint32_t)); >> for_each_dist_irq_reg(irq, s->num_irq, 8) { >> reg = *field; >> kvm_gicd_access(s, offset, ®, true); >> @@ -164,6 +176,12 @@ static void kvm_dist_get_edge_trigger(GICv3State *s, >> uint32_t offset, >> uint32_t reg; >> int irq; >> >> +/* For the KVM GICv3, affinity routing is always enabled, and the first >> 2 >> + * GICD_ICFGR registers are always RAZ/WI. The corresponding >> + * functionality is replaced by GICR_ICFGR. So it doesn't need to >> sync >> + * them. >> + */ >> +offset += (2 * sizeof(uint32_t)); >> for_each_dist_irq_reg(irq, s->num_irq, 2) { >> kvm_gicd_access(s, offset, ®, false); >> reg = half_unshuffle32(reg >> 1); >> @@ -181,6 +199,12 @@ static void kvm_dist_put_edge_trigger(GICv3State *s, >> uint32_t offset, >> uint32_t reg; >> int irq; >> >> +/* For the KVM GICv3, affinity routing is always enabled, and the first >> 2 >> + * GICD_ICFGR registers are always RAZ/WI. The corresponding >> + * functionality is replaced by GICR_ICFGR. So it doesn't need to >> sync >> + * them. >> + */ >> +offset += (2 * sizeof(uint32_t)); >> for_each_dist_irq_reg(irq, s->num_irq, 2) { >> reg = *gic_bmp_ptr32(bmp, irq); >> if (irq % 32 != 0) { >> @@ -222,6 +246,12 @@ static void kvm_dist_getbmp(GICv3State *s, uint32_t >> offset, uint32_t *bmp) >> uint32_t reg; >> int irq; >> >> +/* For the KVM GICv3, affinity routing is always enabled, and the >> + * GICD_IGROUPR0/GICD_ISENABLER0/GICD_ISPENDR0/GICD_ISACTIVER0 registers >> + * are always RAZ/WI. The corresponding functionality is replaced by the >> + * GICR registers. So it doesn't need to sync them. >> + */ >> +offset += (1 * sizeof(uint32_t)); >> for_each_dist_irq_reg(irq, s->num_irq, 1) { >> kvm_gicd_access(s, offset, ®, false); >> *gic_bmp_ptr32(bmp, irq) = reg; >> @@ -235,6 +265,14 @@ static void kvm_dist_putbmp(GICv3State *s, uint32_t >> offset, >> uint32_t reg; >> int irq; >> >> +/* For the KVM GICv3, affinity routing is always enabled, and the >> + * GICD_IGROUPR0/GICD_ISENABLER0/GICD_ISPENDR0/GICD_ISACTIVER0 registers >> + * are always RAZ/WI. The corresponding functionality is replaced by the >> + * GICR registers. So it doesn't need to sync them. >> + */ >> +offset += (1 * sizeof(uint32_t)); > I wonder we couldn't create a new for_each_dist_irq_reg() macro taking > the offset and clroffset and integrating that shift inside? > Peter, what's your opinion? >> +if (clroffset != 0) > nit style issue: brace needed here > OK > Besides Reviewed-by: Eric Auger > Thanks! > Thanks > > Eric > >> +clroffset += (1 * sizeof(uint32_t)); >> for_each_dist_irq_reg(irq, s->num_irq, 1) { >> /* If this bitmap is a set/clear register pair, first write to the >> * clear-reg to clear all bits before using the set-reg to write >> > > . > -- Shannon
[Qemu-devel] [Bug 1757363] [NEW] infinite loop due to improper deal with "eret" on mips32
Public bug reported: 1.qemu 2.9.1 release on the official web build with tcg 2.cmd: qemu-system-mips -kernel kernelfile 3. host: ubuntu 16.04.1 with linux kernel 4.6.2 x86_64 guest: mips bigendian 32bit (tplink firmware) detail: static inline void exception_return(CPUMIPSState *env) { debug_pre_eret(env); if (env->CP0_Status & (1 << CP0St_ERL)) { set_pc(env, env->CP0_ErrorEPC); env->CP0_Status &= ~(1 << CP0St_ERL); } else { set_pc(env, env->CP0_EPC); env->CP0_Status &= ~(1 << CP0St_EXL);> ISSUE } compute_hflags(env); debug_post_eret(env); } void helper_eret(CPUMIPSState *env) { exception_return(env); env->lladdr = 1; } In the Issue Line, there is no check CP0_Status whether int is disabled (should not enter int routine), that result in the cpu can not jump out the int routine. ** Affects: qemu Importance: Undecided Status: New -- You received this bug notification because you are a member of qemu- devel-ml, which is subscribed to QEMU. https://bugs.launchpad.net/bugs/1757363 Title: infinite loop due to improper deal with "eret" on mips32 Status in QEMU: New Bug description: 1.qemu 2.9.1 release on the official web build with tcg 2.cmd: qemu-system-mips -kernel kernelfile 3. host: ubuntu 16.04.1 with linux kernel 4.6.2 x86_64 guest: mips bigendian 32bit (tplink firmware) detail: static inline void exception_return(CPUMIPSState *env) { debug_pre_eret(env); if (env->CP0_Status & (1 << CP0St_ERL)) { set_pc(env, env->CP0_ErrorEPC); env->CP0_Status &= ~(1 << CP0St_ERL); } else { set_pc(env, env->CP0_EPC); env->CP0_Status &= ~(1 << CP0St_EXL);> ISSUE } compute_hflags(env); debug_post_eret(env); } void helper_eret(CPUMIPSState *env) { exception_return(env); env->lladdr = 1; } In the Issue Line, there is no check CP0_Status whether int is disabled (should not enter int routine), that result in the cpu can not jump out the int routine. To manage notifications about this bug go to: https://bugs.launchpad.net/qemu/+bug/1757363/+subscriptions
Re: [Qemu-devel] [PATCH 2/8] migration: stop allocating and freeing memory frequently
On Tue, Mar 13, 2018 at 03:57:33PM +0800, guangrong.x...@gmail.com wrote: > From: Xiao Guangrong > > Current code uses compress2()/uncompress() to compress/decompress > memory, these two function manager memory allocation and release > internally, that causes huge memory is allocated and freed very > frequently > > More worse, frequently returning memory to kernel will flush TLBs > and trigger invalidation callbacks on mmu-notification which > interacts with KVM MMU, that dramatically reduce the performance > of VM > > So, we maintain the memory by ourselves and reuse it for each > compression and decompression > > Signed-off-by: Xiao Guangrong > --- > migration/qemu-file.c | 34 ++-- > migration/qemu-file.h | 6 ++- > migration/ram.c | 142 > +- > 3 files changed, 140 insertions(+), 42 deletions(-) > > diff --git a/migration/qemu-file.c b/migration/qemu-file.c > index 2ab2bf362d..1ff33a1ffb 100644 > --- a/migration/qemu-file.c > +++ b/migration/qemu-file.c > @@ -658,6 +658,30 @@ uint64_t qemu_get_be64(QEMUFile *f) > return v; > } > > +/* return the size after compression, or negative value on error */ > +static int qemu_compress_data(z_stream *stream, uint8_t *dest, size_t > dest_len, > + const uint8_t *source, size_t source_len) > +{ > +int err; > + > +err = deflateReset(stream); I'm not familiar with zlib, but I saw this in manual: https://www.zlib.net/manual.html This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate the internal compression state. The stream will leave the compression level and any other attributes that may have been set unchanged. I thought it was deflateInit() who is slow? Can we avoid the reset as long as we make sure to deflateInit() before doing anything else? Meanwhile, is there any performance number for this single patch? Since I thought the old code is calling compress2() which contains deflateInit() and deflateEnd() too, just like what current patch do? It would be nice too if we can split the patch into two (decode, encode) if you want, but that's optional. Thanks, -- Peter Xu
Re: [Qemu-devel] [PATCH] make: improve check for stale generated files in source dir
Le 20/03/2018 à 15:23, Daniel P. Berrangé a écrit : > When doing a build with builddir != srcdir, if any generated files are > accidentally present in srcdir from a previous build, these can cause > unexpected failures. > > Currently there is a rule that checks for existance of config-host.mak, > but there have been cases where config-host.mak is absent, while other > generated files still exist. > > Update the check to look at every file listed in $(GENERATED_FILES). To > do this we must move the check further down after $(GENERATED_FILES) has > been populated. > > Signed-off-by: Daniel P. Berrangé > --- > Makefile | 29 +++-- > 1 file changed, 19 insertions(+), 10 deletions(-) Tested-by: Laurent Vivier I had a stale qemu-version.h and this change has correctly detected it. The problem was: $ make -C build/all ... ./qemu-nbd.c: In function ‘version’: ./qemu-nbd.c:133:7: error: expected ‘)’ before ‘QEMU_FULL_VERSION’ "%s " QEMU_FULL_VERSION "\n" ^ ./qemu-nbd.c:133:3: error: format ‘%s’ expects a matching ‘char *’ argument [-Werror=format=] "%s " QEMU_FULL_VERSION "\n" ~^ cc1: all warnings being treated as errors make: *** [./rules.mak:66: qemu-nbd.o] Error 1 make: *** Waiting for unfinished jobs make: Leaving directory './build/all' once the file removed, the build can be done. Thanks, Laurent
Re: [Qemu-devel] [PATCH for-2.12] rdma: Fix 32-bit compilation
On 21/03/2018 4:07, Fam Zheng wrote: > On Tue, 03/20 12:30, Marcel Apfelbaum wrote: >> Hi Eric, >> >> On 19/03/2018 23:53, Eric Blake wrote: >>> Use the correct printf formats, so that a 32-bit compile doesn't >>> spit out lots of warnings about %lx being incompatible with uint64_t. >>> Broken since initial commit ef6d4ccd. >>> >>> Signed-off-by: Eric Blake >>> --- >>> >>> I don't know if 'make vm-build-ubuntu.i368' would catch this (it failed >>> for me for other reasons); I found it via a 32-bit rawhide VM. >>> >> >> I couldn't run 'make vm-build-ubuntu.i368' either. (Stuck on "Booting from >> Hard Disk...") > > I tried this now and it works for me. Could you delete "$HOME/.cache/qemu-vm" > and do it again from a git tree, then pastbin the full log? > Hi Fam, I did that but it didn't help. Here is the log: https://da.gd/8wJHj I try to run the same command line, and it still stuck in the boot process. Problem is, the command line looks fine, may be another issue with my PC... I'll continue to debug it. Thanks for the help, Marcel > Fam >
Re: [Qemu-devel] [PATCH for-2.12] qcow2: Reset free_cluster_index when allocating a new refcount block
On Tue 20 Mar 2018 06:54:15 PM CET, Eric Blake wrote: >> When we try to allocate new clusters we first look for available ones >> starting from s->free_cluster_index and once we find them we increase >> their reference counts. Before we get to call update_refcount() to do >> this last step s->free_cluster_index is already pointing to the next >> cluster after the ones we are trying to allocate. >> > > During update_refcount() it may happen however that we also need to > > allocate a new refcount block in order to store the refcounts of > > these new clusters > > Your changes to test 121 covers this... > > > (and to complicate things further that may also require us to grow > > the refcount table). > > ...but not this. Is it worth also trying to cover this case in the > testsuite as well? I checked and the patch doesn't really fix that scenario. There's a different problem that I haven't debugged completely yet, because of two reasons: - One difference is that when we grow the refcount table we actually allocate a new one, so s->free_cluster_index points to the beginning of the image (where the previous table was) and any holes left during the process are allocated after that (depending on how much data we write though). - This scenario is harder to reach: in order to fill a 1-cluster refcount table the size of the image needs to be larger than (cluster_size³ / refcount_bits) bytes, that's 16TB with the default parameters. So although it can be reproduced easily if you reduce the cluster size I think it's very infrequent under normal conditions. But yes, it's a task left for the future. >> +/* If the caller needs to restart the search for free clusters, >> + * try the same ones first to see if they're still free. */ >> +if (ret == -EAGAIN) { >> +if (s->free_cluster_index > (start >> s->cluster_bits)) { >> +s->free_cluster_index = (start >> s->cluster_bits); >> +} > > Is there any harm in making this assignment unconditional, instead of > only doing it when free_cluster_index has grown larger than start? It can happen that it is smaller than 'start' if we were moving the refcount table to a new location, so we want to keep the lowest value. > [And unrelated, but it might be nice to do a followup cleanup to track > free_cluster_offset by bytes instead of having to shift > free_cluster_index everywhere] I've actually just seen that we already have free_byte_offset, we use that for compressed clusters, so it might be possible to use that one... I'll put that in my TODO list. Berto
Re: [Qemu-devel] [PULL 00/25] RISC-V Post-merge spec conformance and cleanup
Le 21/03/2018 à 08:05, Thomas Huth a écrit : > On 20.03.2018 23:25, Michael Clark wrote: >> The following changes since commit f1a63fcfcd92c88be8942b5ae71aef9749a4f135: >> >> Update version for v2.12.0-rc0 release (2018-03-20 19:04:22 +) >> >> are available in the git repository at: >> >> https://github.com/riscv/riscv-qemu.git tags/riscv-qemu-2.12-fixes >> >> for you to fetch changes up to e1a247183ac0816284dfda61423f7030b6686679: >> >> RISC-V: Remove erroneous comment from translate.c (2018-03-20 14:34:13 >> -0700) >> >> >> This is a series of spec conformance bug fixes and code cleanups >> that we would like to get in before the QEMU 2.12 release. > > Hi Michael, > > for future PULL request, could you please send out all patches again > that should be pulled, and not send the cover letter alone? I.e. do a > "git format-patch --subject-prefix PULL ..." and then replace the > contents of the cover letter with the output of "git request-pull". > > ... this is how all other maintainers are sending PULL requests (at > least as far as I know) and this way everybody gets a very final chance > to have a look at the patches in their final state (it does not happen > very often that someone replies to such patches, but in some rare cases > we already found problems this way). You can also use git-publish that is a very simple tool to manage patch series revision and to send pull request in an easy way. https://github.com/stefanha/git-publish Thanks, Laurent signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [PATCH for-2.12 05/12] luks: Turn another invalid assertion into check
On Tue, Mar 20, 2018 at 06:36:25PM +0100, Kevin Wolf wrote: > Commit e39e959e fixed an invalid assertion in the .bdrv_length > implementation, but left a similar assertion in place for > .bdrv_truncate. Instead of crashing when the user requests a too large > image size, fail gracefully. > > A file size of exactly INT64_MAX caused failure before, but is actually > legal. > > Signed-off-by: Kevin Wolf > --- > block/crypto.c | 6 +- > 1 file changed, 5 insertions(+), 1 deletion(-) Reviewed-by: Daniel P. Berrangé Regards, Daniel -- |: https://berrange.com -o-https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o-https://fstop138.berrange.com :| |: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH for-2.12 06/12] qemu-iotests: Test invalid resize on luks
On Tue, Mar 20, 2018 at 06:36:26PM +0100, Kevin Wolf wrote: > This tests that the .bdrv_truncate implementation for luks doesn't crash > for invalid image sizes. > > Signed-off-by: Kevin Wolf > --- > tests/qemu-iotests/210 | 37 + > 1 file changed, 37 insertions(+) Reviewed-by: Daniel P. Berrangé Regards, Daniel -- |: https://berrange.com -o-https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o-https://fstop138.berrange.com :| |: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH for-2.12 04/12] qemu-iotests: Enable 025 for luks
On Tue, Mar 20, 2018 at 06:36:24PM +0100, Kevin Wolf wrote: > We want to test resizing even for luks. The only change that is needed > is to explicitly zero out new space for luks because it's undefined. > > Signed-off-by: Kevin Wolf > --- > tests/qemu-iotests/025 | 9 - > 1 file changed, 8 insertions(+), 1 deletion(-) Reviewed-by: Daniel P. Berrangé Regards, Daniel -- |: https://berrange.com -o-https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o-https://fstop138.berrange.com :| |: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|
Re: [Qemu-devel] [PATCH for-2.12] rdma: Fix 32-bit compilation
On Wed, 03/21 11:20, Marcel Apfelbaum wrote: > On 21/03/2018 4:07, Fam Zheng wrote: > > On Tue, 03/20 12:30, Marcel Apfelbaum wrote: > >> Hi Eric, > >> > >> On 19/03/2018 23:53, Eric Blake wrote: > >>> Use the correct printf formats, so that a 32-bit compile doesn't > >>> spit out lots of warnings about %lx being incompatible with uint64_t. > >>> Broken since initial commit ef6d4ccd. > >>> > >>> Signed-off-by: Eric Blake > >>> --- > >>> > >>> I don't know if 'make vm-build-ubuntu.i368' would catch this (it failed > >>> for me for other reasons); I found it via a 32-bit rawhide VM. > >>> > >> > >> I couldn't run 'make vm-build-ubuntu.i368' either. (Stuck on "Booting from > >> Hard Disk...") > > > > I tried this now and it works for me. Could you delete > > "$HOME/.cache/qemu-vm" > > and do it again from a git tree, then pastbin the full log? > > > > Hi Fam, > I did that but it didn't help. > > Here is the log: https://da.gd/8wJHj > I try to run the same command line, and it still stuck in the boot process. > Problem is, the command line looks fine, may be another issue with my PC... > I'll continue to debug it. Maybe we are using different QEMU/seabios. What I used is built from qemu.git. The log has the QEMU arguments which you can try manually for debug. Fam
Re: [Qemu-devel] [PATCH 3/8] migration: support to detect compression and decompression errors
On Tue, Mar 13, 2018 at 03:57:34PM +0800, guangrong.x...@gmail.com wrote: > From: Xiao Guangrong > > Currently the page being compressed is allowed to be updated by > the VM on the source QEMU, correspondingly the destination QEMU > just ignores the decompression error. However, we completely miss > the chance to catch real errors, then the VM is corrupted silently > > To make the migration more robuster, we copy the page to a buffer > first to avoid it being written by VM, then detect and handle the > errors of both compression and decompression errors properly Not sure I missed anything important, but I'll just shoot my thoughts as questions (again)... Actually this is a more general question? Say, even without compression, we can be sending a page that is being modified. However, IMHO we don't need to worry that, since if that page is modified, we'll definitely send that page again, so the new page will replace the old. So on destination side, even if decompress() failed on a page it'll be fine IMHO. Though now we are copying the corrupted buffer. On that point, I fully agree that we should not - maybe we can just drop the page entirely? For non-compress pages, we can't detect that, so we'll copy the page even if corrupted. The special part for compression would be: would the deflate() fail if there is concurrent update to the buffer being compressed? And would that corrupt the whole compression stream, or it would only fail the deflate() call? Thanks, > > Signed-off-by: Xiao Guangrong > --- > migration/qemu-file.c | 4 ++-- > migration/ram.c | 29 +++-- > 2 files changed, 21 insertions(+), 12 deletions(-) > > diff --git a/migration/qemu-file.c b/migration/qemu-file.c > index 1ff33a1ffb..137bcc8bdc 100644 > --- a/migration/qemu-file.c > +++ b/migration/qemu-file.c > @@ -711,9 +711,9 @@ ssize_t qemu_put_compression_data(QEMUFile *f, z_stream > *stream, > blen = qemu_compress_data(stream, f->buf + f->buf_index + > sizeof(int32_t), >blen, p, size); > if (blen < 0) { > -error_report("Compress Failed!"); > -return 0; > +return -1; > } > + > qemu_put_be32(f, blen); > if (f->ops->writev_buffer) { > add_to_iovec(f, f->buf + f->buf_index, blen, false); > diff --git a/migration/ram.c b/migration/ram.c > index fff3f31e90..c47185d38c 100644 > --- a/migration/ram.c > +++ b/migration/ram.c > @@ -273,6 +273,7 @@ struct DecompressParam { > bool quit; > QemuMutex mutex; > QemuCond cond; > +QEMUFile *file; > void *des; > uint8_t *compbuf; > int len; > @@ -1051,11 +1052,13 @@ static int do_compress_ram_page(QEMUFile *f, z_stream > *stream, RAMBlock *block, > { > RAMState *rs = ram_state; > int bytes_sent, blen; > -uint8_t *p = block->host + (offset & TARGET_PAGE_MASK); > +uint8_t buf[TARGET_PAGE_SIZE], *p; > > +p = block->host + (offset & TARGET_PAGE_MASK); > bytes_sent = save_page_header(rs, f, block, offset | >RAM_SAVE_FLAG_COMPRESS_PAGE); > -blen = qemu_put_compression_data(f, stream, p, TARGET_PAGE_SIZE); > +memcpy(buf, p, TARGET_PAGE_SIZE); > +blen = qemu_put_compression_data(f, stream, buf, TARGET_PAGE_SIZE); > if (blen < 0) { > bytes_sent = 0; > qemu_file_set_error(migrate_get_current()->to_dst_file, blen); > @@ -2547,7 +2550,7 @@ static void *do_data_decompress(void *opaque) > DecompressParam *param = opaque; > unsigned long pagesize; > uint8_t *des; > -int len; > +int len, ret; > > qemu_mutex_lock(¶m->mutex); > while (!param->quit) { > @@ -2563,8 +2566,12 @@ static void *do_data_decompress(void *opaque) > * not a problem because the dirty page will be retransferred > * and uncompress() won't break the data in other pages. > */ > -qemu_uncompress(¶m->stream, des, pagesize, > -param->compbuf, len); > +ret = qemu_uncompress(¶m->stream, des, pagesize, > + param->compbuf, len); > +if (ret < 0) { > +error_report("decompress data failed"); > +qemu_file_set_error(param->file, ret); > +} > > qemu_mutex_lock(&decomp_done_lock); > param->done = true; > @@ -2581,12 +2588,12 @@ static void *do_data_decompress(void *opaque) > return NULL; > } > > -static void wait_for_decompress_done(void) > +static int wait_for_decompress_done(QEMUFile *f) > { > int idx, thread_count; > > if (!migrate_use_compression()) { > -return; > +return 0; > } > > thread_count = migrate_decompress_threads(); > @@ -2597,6 +2604,7 @@ static void wait_for_decompress_done(void) > } > } > qemu_mutex_unlock(&decomp_done_lock); > +return qemu_file_get_error(f); > } > > sta
Re: [Qemu-devel] [PATCH v2 0/4] tpm: Fix initialization of a few flags of CRB interface
Hi On Tue, Mar 20, 2018 at 9:52 PM, Stefan Berger wrote: > Fix the initialization of a few flags of the CRB interface. I tested the > changes > with UEFI and it works fine. SeaBIOS needs to have the latest patches applied. > >Stefan > > Stefan Berger (4): > tpm: CRB: Set tpmRegValidSts flag to '1' in device reset > tpm: CRB: set registers to 0 by default > tpm: CRB: reset locAssigned upon relinquishing locality > tpm: CRB: query backend for TPM established flag > > hw/tpm/tpm_crb.c | 14 -- > 1 file changed, 12 insertions(+), 2 deletions(-) Series: Reviewed-by: Marc-André Lureau For 2.12? thanks -- Marc-André Lureau
[Qemu-devel] [PATCH] scsi: turn "is this a SCSI device?" into a conditional hint
If the user does not have permissions to send ioctls to the device (due to SELinux or cgroups, for example), the output can look like qemu-kvm: -device scsi-block,drive=disk: cannot get SG_IO version number: Operation not permitted. Is this a SCSI device? but this is confusing because the ioctl was blocked _before_ the device even received the SG_GET_VERSION_NUM ioctl. Therefore, for EPERM errors the suggestion should be eliminated. To make that simpler, change the code to use error_append_hint. Reported-by: Ala Hino Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c| 7 --- hw/scsi/scsi-generic.c | 7 --- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 94043ed024..ccc245589a 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2637,9 +2637,10 @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) /* check we are using a driver managing SG_IO (version 3 and after) */ rc = blk_ioctl(s->qdev.conf.blk, SG_GET_VERSION_NUM, &sg_version); if (rc < 0) { -error_setg(errp, "cannot get SG_IO version number: %s. " - "Is this a SCSI device?", - strerror(-rc)); +error_setg(errp, "cannot get SG_IO version number: %s", strerror(-rc)); +if (rc != -EPERM) { +error_append_hint(errp, "Is this a SCSI device?"); +} return; } if (sg_version < 3) { diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 7414fe2d67..b3de5df324 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -500,9 +500,10 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp) /* check we are using a driver managing SG_IO (version 3 and after */ rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version); if (rc < 0) { -error_setg(errp, "cannot get SG_IO version number: %s. " - "Is this a SCSI device?", - strerror(-rc)); +error_setg(errp, "cannot get SG_IO version number: %s", strerror(-rc)); +if (rc != -EPERM) { +error_append_hint(errp, "Is this a SCSI device?"); +} return; } if (sg_version < 3) { -- 2.16.2
Re: [Qemu-devel] [PATCH v2 1/2] i386/kvm: add support for Hyper-V reenlightenment MSRs
On Tue, Mar 20, 2018 at 03:16:52PM -0300, Eduardo Habkost wrote: > On Mon, Mar 19, 2018 at 06:29:08PM +0100, Vitaly Kuznetsov wrote: > > Roman Kagan writes: > > > (This is also a problem with has_msr_hv_frequencies, and is in general a > > > long-standing issue of hv_* properties being done differently from the > > > rest of CPUID features.) > > > > Suggestions? (To be honest I don't really like us adding new hv_* > > property for every new Hyper-V feature we support. I doubt anyone needs > > 'partial' Hyper-V emulation. It would be nice to have a single versioned > > 'hv' feature implying everything. We may then forbid migrations to older > > hv versions. But I don't really know the history of why we decided to go > > with a separate hv_* for every feature we add). > > You will need "partial" emulation if you want to support > live-migration to/from a host where the KVM or QEMU don't support > all the features from the current host. > > Is this something the current Hyper-V code already supports, or > it's something known to be broken? There's at least one case I mentioned above where it's broken, but, as Paolo pointed out, the real Windows guests wouldn't notice because they didn't use the feature due to missing INVTSC. I myself haven't tested all possible combinations of hv_* flags and KVM versions, but from code inspection I don't immediately see anything else that's obviously broken in this regard. Roman.
Re: [Qemu-devel] [PATCH v2 1/2] i386/kvm: add support for Hyper-V reenlightenment MSRs
On 20/03/2018 19:16, Eduardo Habkost wrote: >> Suggestions? (To be honest I don't really like us adding new hv_* >> property for every new Hyper-V feature we support. I doubt anyone needs >> 'partial' Hyper-V emulation. It would be nice to have a single versioned >> 'hv' feature implying everything. We may then forbid migrations to older >> hv versions. But I don't really know the history of why we decided to go >> with a separate hv_* for every feature we add). > You will need "partial" emulation if you want to support > live-migration to/from a host where the KVM or QEMU don't support > all the features from the current host. > > Is this something the current Hyper-V code already supports, or > it's something known to be broken? Yes, it works. Essentially, multiple Hyper-V features are (just like multiple KVM features) needed to support old kernels. The difference is that new KVM features are added quite rarely, and most of them are enabled by default. The opposite is true of Hyper-V, on both counts. Paolo
Re: [Qemu-devel] Bug AioContext polling is not implemented on Windows with qemu-system-ppc.exe
On 20/03/2018 18:11, Howard Spoelstra wrote: > Hi, > > I just built qemu-system-ppc.exe for windows using a fully up-to-date Fedora > 27. > Command line for build: > > ./configure --cross-prefix=x86_64-w64-mingw32- > --target-list="ppc-softmmu ppc64-softmmu" --enable-gtk > --with-gtkabi=3.0 --enable-sdl --with-sdlabi=2.0 > > Command line to invoke Qemu: > C:\qemu-master>qemu-system-ppc.exe -L pc-bios -boot c -m 256 -M mac99 > -prom-env "boot-args=-v" -prom-env "auto-boot?=true" -prom-env > "vga-ndrv?=true" -drive > file=c:\Mac-disks\9.1.img,format=raw,media=disk -netdev > user,id=network01 -device > sungem,netdev=network01,mac=52:54:00:12:34:66 -sdl -device usb-kbd > -device usb-mouse > > Error: > Unexpected error in aio_context_set_poll_params() at util/aio-win32.c:413: > qemu-system-ppc.exe: AioContext polling is not implemented on Windows Can you get a backtrace on the Windows system? Perhaps by putting a breakpoint in aio_context_set_poll_params. Paolo
Re: [Qemu-devel] [PULL 00/25] RISC-V Post-merge spec conformance and cleanup
On 21/03/2018 08:05, Thomas Huth wrote: > On 20.03.2018 23:25, Michael Clark wrote: >> The following changes since commit f1a63fcfcd92c88be8942b5ae71aef9749a4f135: >> >> Update version for v2.12.0-rc0 release (2018-03-20 19:04:22 +) >> >> are available in the git repository at: >> >> https://github.com/riscv/riscv-qemu.git tags/riscv-qemu-2.12-fixes >> >> for you to fetch changes up to e1a247183ac0816284dfda61423f7030b6686679: >> >> RISC-V: Remove erroneous comment from translate.c (2018-03-20 14:34:13 >> -0700) >> >> >> This is a series of spec conformance bug fixes and code cleanups >> that we would like to get in before the QEMU 2.12 release. > > Hi Michael, > > for future PULL request, could you please send out all patches again > that should be pulled, and not send the cover letter alone? I.e. do a > "git format-patch --subject-prefix PULL ..." and then replace the > contents of the cover letter with the output of "git request-pull". > > ... this is how all other maintainers are sending PULL requests (at > least as far as I know) and this way everybody gets a very final chance > to have a look at the patches in their final state (it does not happen > very often that someone replies to such patches, but in some rare cases > we already found problems this way). In fact, I already explained on the mailing list that this patch: RISC-V: Hold rcu_read_lock when accessing memory is fixing the wrong place, so please remove it from the pull request too. Thanks, Paolo
Re: [Qemu-devel] [PATCH v3 1/2] i386/kvm: add support for Hyper-V reenlightenment MSRs
On Tue, Mar 20, 2018 at 03:32:27PM -0300, Eduardo Habkost wrote: > On Tue, Mar 20, 2018 at 06:34:59PM +0100, Vitaly Kuznetsov wrote: > > @@ -1747,6 +1760,15 @@ static int kvm_put_msrs(X86CPU *cpu, int level) > > if (cpu->hyperv_time) { > > kvm_msr_entry_add(cpu, HV_X64_MSR_REFERENCE_TSC, > >env->msr_hv_tsc); > > + > > +if (has_msr_hv_reenlightenment) { > > I see that the current code is inconsistent: some entries check > for has_msr_hv_*, other entries check cpu->hyperv_*. > > I suggest changing all of them (including this one) to check > cpu->hyperv_* instead. > > The difference between both approaches is that checking just > has_msr_hv_* would let a non-cooperating guest prevent itself > from being migrated to an older host by writing a non-zero value > to a MSR, even if hyperv support was not enabled in the VM > configuration at all. I don't think we want that. Agreed. We accumulated a number of these over time; it's mostly my fault, so I don't feel it's just to ask Vitaly to fix the existing ones, but let's not add new ones. Roman.
Re: [Qemu-devel] [PATCH v3 1/2] i386/kvm: add support for Hyper-V reenlightenment MSRs
On Tue, Mar 20, 2018 at 06:34:59PM +0100, Vitaly Kuznetsov wrote: > KVM recently gained support for Hyper-V Reenlightenment MSRs which are > required to make KVM-on-Hyper-V enable TSC page clocksource to its guests > when INVTSC is not passed to it (and it is not passed by default in Qemu > as it effectively blocks migration). > > Signed-off-by: Vitaly Kuznetsov > --- > Changes since v2: > - add hv-reenlightenment CPU property [Roman Kagan, Paolo Bonzini] > - add a comment to feature_word_info [Roman Kagan] > --- > target/i386/cpu.c | 4 +++- > target/i386/cpu.h | 4 > target/i386/hyperv-proto.h | 9 - > target/i386/kvm.c | 39 ++- > target/i386/machine.c | 24 > 5 files changed, 77 insertions(+), 3 deletions(-) > > diff --git a/target/i386/cpu.c b/target/i386/cpu.c > index 6bb4ce8719..02579f8234 100644 > --- a/target/i386/cpu.c > +++ b/target/i386/cpu.c > @@ -407,7 +407,8 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = > { > NULL /* hv_vpindex_access */, NULL /* hv_msr_reset_access */, > NULL /* hv_msr_stats_access */, NULL /* hv_reftsc_access */, > NULL /* hv_msr_idle_access */, NULL /* hv_msr_frequency_access > */, > -NULL, NULL, NULL, NULL, > +NULL /* hv_msr_debug_access */, NULL /* > hv_msr_reenlightenment_access */, > +NULL, NULL, > NULL, NULL, NULL, NULL, > NULL, NULL, NULL, NULL, > NULL, NULL, NULL, NULL, > @@ -4764,6 +4765,7 @@ static Property x86_cpu_properties[] = { > DEFINE_PROP_BOOL("hv-runtime", X86CPU, hyperv_runtime, false), > DEFINE_PROP_BOOL("hv-synic", X86CPU, hyperv_synic, false), > DEFINE_PROP_BOOL("hv-stimer", X86CPU, hyperv_stimer, false), > +DEFINE_PROP_BOOL("hv-reenlightenment", X86CPU, hyperv_reenlightenment, > false), > DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, true), > DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false), > DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true), > diff --git a/target/i386/cpu.h b/target/i386/cpu.h > index 2e2bab5ff3..98eed72937 100644 > --- a/target/i386/cpu.h > +++ b/target/i386/cpu.h > @@ -1174,6 +1174,9 @@ typedef struct CPUX86State { > uint64_t msr_hv_synic_sint[HV_SINT_COUNT]; > uint64_t msr_hv_stimer_config[HV_STIMER_COUNT]; > uint64_t msr_hv_stimer_count[HV_STIMER_COUNT]; > +uint64_t msr_hv_reenlightenment_control; > +uint64_t msr_hv_tsc_emulation_control; > +uint64_t msr_hv_tsc_emulation_status; > > uint64_t msr_rtit_ctrl; > uint64_t msr_rtit_status; > @@ -1296,6 +1299,7 @@ struct X86CPU { > bool hyperv_runtime; > bool hyperv_synic; > bool hyperv_stimer; > +bool hyperv_reenlightenment; > bool check_cpuid; > bool enforce_cpuid; > bool expose_kvm; > diff --git a/target/i386/hyperv-proto.h b/target/i386/hyperv-proto.h > index cb4d7f2b7a..93352ebd2a 100644 > --- a/target/i386/hyperv-proto.h > +++ b/target/i386/hyperv-proto.h > @@ -35,7 +35,7 @@ > #define HV_RESET_AVAILABLE (1u << 7) > #define HV_REFERENCE_TSC_AVAILABLE (1u << 9) > #define HV_ACCESS_FREQUENCY_MSRS (1u << 11) > - > +#define HV_ACCESS_REENLIGHTENMENTS_CONTROL (1u << 13) > > /* > * HV_CPUID_FEATURES.EDX bits > @@ -129,6 +129,13 @@ > #define HV_X64_MSR_CRASH_CTL0x4105 > #define HV_CRASH_CTL_NOTIFY (1ull << 63) > > +/* > + * Reenlightenment notification MSRs > + */ > +#define HV_X64_MSR_REENLIGHTENMENT_CONTROL 0x4106 > +#define HV_X64_MSR_TSC_EMULATION_CONTROL0x4107 > +#define HV_X64_MSR_TSC_EMULATION_STATUS 0x4108 > + > /* > * Hypercall status code > */ > diff --git a/target/i386/kvm.c b/target/i386/kvm.c > index d23fff12f5..7d9f9ca0b1 100644 > --- a/target/i386/kvm.c > +++ b/target/i386/kvm.c > @@ -90,6 +90,7 @@ static bool has_msr_hv_runtime; > static bool has_msr_hv_synic; > static bool has_msr_hv_stimer; > static bool has_msr_hv_frequencies; > +static bool has_msr_hv_reenlightenment; > static bool has_msr_xss; > static bool has_msr_spec_ctrl; > static bool has_msr_smi_count; > @@ -583,7 +584,8 @@ static bool hyperv_enabled(X86CPU *cpu) > cpu->hyperv_vpindex || > cpu->hyperv_runtime || > cpu->hyperv_synic || > -cpu->hyperv_stimer); > +cpu->hyperv_stimer || > +cpu->hyperv_reenlightenment); > } > > static int kvm_arch_set_tsc_khz(CPUState *cs) > @@ -654,6 +656,14 @@ static int hyperv_handle_properties(CPUState *cs) > env->features[FEAT_HYPERV_EDX] |= HV_FREQUENCY_MSRS_AVAILABLE; > } > } > +if (cpu->hyperv_reenlightenment) { > +if (!has_msr_hv_reenlightenment) { > +fprintf(stderr, > +"Hyper-V Reenlightenment is not supported by kernel\n"); > +return -ENOSYS
Re: [Qemu-devel] [PATCH v3 15/16] block/mirror: Add copy mode QAPI interface
On 2018-03-20 18:35, Eric Blake wrote: > On 02/28/2018 12:05 PM, Max Reitz wrote: >> This patch allows the user to specify whether to use active or only >> background mode for mirror block jobs. Currently, this setting will >> remain constant for the duration of the entire block job. >> >> Signed-off-by: Max Reitz >> --- >> qapi/block-core.json | 11 +-- >> include/block/block_int.h | 4 +++- >> block/mirror.c | 12 +++- >> blockdev.c | 9 - >> 4 files changed, 27 insertions(+), 9 deletions(-) >> >> diff --git a/qapi/block-core.json b/qapi/block-core.json >> index c73b769c27..1186c007ae 100644 >> --- a/qapi/block-core.json >> +++ b/qapi/block-core.json >> @@ -1573,6 +1573,9 @@ >> # written. Both will result in identical contents. >> # Default is true. (Since 2.4) >> # >> +# @copy-mode: when to copy data to the destination; defaults to >> 'background' >> +# (Since: 2.12) >> +# > > Are we still aiming for 2.12, or is this a feature which missed > softfreeze and should therefore be 2.13? The latter, I'll change it in v4. Max signature.asc Description: OpenPGP digital signature
[Qemu-devel] [PATCH] migration: fix pfd leak
Fix leak spotted by ASAN: Direct leak of 16 byte(s) in 1 object(s) allocated from: #0 0x7fe1abb80a38 in __interceptor_calloc (/lib64/libasan.so.4+0xdea38) #1 0x7fe1aaf1bf75 in g_malloc0 ../glib/gmem.c:124 #2 0x7fe1aaf1c249 in g_malloc0_n ../glib/gmem.c:355 #3 0x55f4841cfaa9 in postcopy_ram_fault_thread /home/elmarco/src/qemu/migration/postcopy-ram.c:596 #4 0x55f48479447b in qemu_thread_start /home/elmarco/src/qemu/util/qemu-thread-posix.c:504 #5 0x7fe1a043550a in start_thread (/lib64/libpthread.so.0+0x750a) Regression introduced with commit 00fa4fc85b00f1a8a810068d158a7a66e88658eb. Signed-off-by: Marc-André Lureau --- migration/postcopy-ram.c | 1 + 1 file changed, 1 insertion(+) diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index efd77939af..4a0b33b373 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -754,6 +754,7 @@ static void *postcopy_ram_fault_thread(void *opaque) } } trace_postcopy_ram_fault_thread_exit(); +g_free(pfd); return NULL; } -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 07/49] qapi: mcgen() shouldn't indent # lines
Skip preprocessor lines when adding indentation, since that would likely result in invalid code. Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index bc4ecd6c76..47efe79758 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -1931,8 +1931,8 @@ def cgen(code, **kwds): if indent_level: indent = genindent(indent_level) # re.subn() lacks flags support before Python 2.7, use re.compile() -raw = re.subn(re.compile(r'^.', re.MULTILINE), - indent + r'\g<0>', raw) +raw = re.subn(re.compile(r'^(?!(#|$))', re.MULTILINE), + indent, raw) raw = raw[0] return re.sub(re.escape(eatspace) + r' *', '', raw) -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 01/49] qapi/visit: remove useless prefix argument
Signed-off-by: Marc-André Lureau --- scripts/qapi/visit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index 5d72d8936c..3c5ea1289e 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -293,7 +293,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor): #include "qapi/qmp/qerror.h" #include "%(visit)s.h" ''', - visit=visit, prefix=self._prefix)) + visit=visit)) self._genh.preamble_add(mcgen(''' #include "qapi/qapi-builtin-visit.h" #include "%(types)s.h" -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 02/49] qapi/events: generate event enum in main module
The event generator produces an enum, and put it in the last visited module. It fits better in the main module, since it's the set of all visited events, from all modules. Signed-off-by: Marc-André Lureau --- scripts/qapi/events.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py index 3dc523cf39..3e448ae523 100644 --- a/scripts/qapi/events.py +++ b/scripts/qapi/events.py @@ -180,8 +180,9 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor): types=types)) def visit_end(self): -self._genh.add(gen_enum(self._enum_name, self._event_names)) -self._genc.add(gen_enum_lookup(self._enum_name, self._event_names)) +(genc, genh) = self._module[self._main_module] +genh.add(gen_enum(self._enum_name, self._event_names)) +genc.add(gen_enum_lookup(self._enum_name, self._event_names)) def visit_event(self, name, info, arg_type, boxed): self._genh.add(gen_event_send_decl(name, arg_type, boxed)) -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 05/49] qapi: leave the ifcond attribute undefined until check()
We commonly initialize attributes to None in .init(), then set their real value in .check(). Accessing the attribute before .check() yields None. If we're lucky, the code that accesses the attribute prematurely chokes on None. It won't for .ifcond, because None is a legitimate value. Leave the ifcond attribute undefined until check(). Suggested-by: Markus Armbruster Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster --- scripts/qapi/common.py | 21 + 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index d8ab3d8f7f..eb07d641ab 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -1026,13 +1026,19 @@ class QAPISchemaEntity(object): # such place). self.info = info self.doc = doc -self.ifcond = listify_cond(ifcond) +self._ifcond = ifcond # self.ifcond is set only after .check() def c_name(self): return c_name(self.name) def check(self, schema): -pass +if isinstance(self._ifcond, QAPISchemaType): +# inherit the condition from a type +typ = self._ifcond +typ.check(schema) +self.ifcond = typ.ifcond +else: +self.ifcond = listify_cond(self._ifcond) def is_implicit(self): return not self.info @@ -1169,6 +1175,7 @@ class QAPISchemaEnumType(QAPISchemaType): self.prefix = prefix def check(self, schema): +QAPISchemaType.check(self, schema) seen = {} for v in self.values: v.check_clash(self.info, seen) @@ -1201,8 +1208,10 @@ class QAPISchemaArrayType(QAPISchemaType): self.element_type = None def check(self, schema): +QAPISchemaType.check(self, schema) self.element_type = schema.lookup_type(self._element_type_name) assert self.element_type +self.element_type.check(schema) self.ifcond = self.element_type.ifcond def is_implicit(self): @@ -1245,6 +1254,7 @@ class QAPISchemaObjectType(QAPISchemaType): self.members = None def check(self, schema): +QAPISchemaType.check(self, schema) if self.members is False: # check for cycles raise QAPISemError(self.info, "Object %s contains itself" % self.name) @@ -1427,6 +1437,7 @@ class QAPISchemaAlternateType(QAPISchemaType): self.variants = variants def check(self, schema): +QAPISchemaType.check(self, schema) self.variants.tag_member.check(schema) # Not calling self.variants.check_clash(), because there's nothing # to clash with @@ -1470,6 +1481,7 @@ class QAPISchemaCommand(QAPISchemaEntity): self.allow_oob = allow_oob def check(self, schema): +QAPISchemaEntity.check(self, schema) if self._arg_type_name: self.arg_type = schema.lookup_type(self._arg_type_name) assert (isinstance(self.arg_type, QAPISchemaObjectType) or @@ -1504,6 +1516,7 @@ class QAPISchemaEvent(QAPISchemaEntity): self.boxed = boxed def check(self, schema): +QAPISchemaEntity.check(self, schema) if self._arg_type_name: self.arg_type = schema.lookup_type(self._arg_type_name) assert (isinstance(self.arg_type, QAPISchemaObjectType) or @@ -1633,7 +1646,7 @@ class QAPISchema(object): # But it's not tight: the disjunction need not imply it. We # may end up compiling useless wrapper types. # TODO kill simple unions or implement the disjunction -assert ifcond == typ.ifcond +assert ifcond == typ._ifcond else: self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond, None, members, None)) @@ -1679,7 +1692,7 @@ class QAPISchema(object): assert len(typ) == 1 typ = self._make_array_type(typ[0], info) typ = self._make_implicit_object_type( -typ, info, None, self.lookup_type(typ).ifcond, +typ, info, None, self.lookup_type(typ), 'wrapper', [self._make_member('data', typ, info)]) return QAPISchemaObjectTypeVariant(case, typ) -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 04/49] qapi: pass 'if' condition into QAPISchemaEntity objects
Built-in objects remain unconditional. Explicitly defined objects use the condition specified in the schema. Implicitly defined objects inherit their condition from their users. For most of them, there is exactly one user, so the condition to use is obvious. The exception is the wrapped type's generated for simple union variants, which can be shared by any number of simple unions. The tight condition would be the disjunction of the conditions of these simple unions. For now, use wrapped type's condition instead. Much simpler and good enough for now. Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster --- scripts/qapi/common.py | 97 -- 1 file changed, 65 insertions(+), 32 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 4f9e02b0b4..d8ab3d8f7f 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -1006,8 +1006,16 @@ def check_exprs(exprs): # Schema compiler frontend # +def listify_cond(ifcond): +if not ifcond: +return [] +if not isinstance(ifcond, list): +return [ifcond] +return ifcond + + class QAPISchemaEntity(object): -def __init__(self, name, info, doc): +def __init__(self, name, info, doc, ifcond=None): assert name is None or isinstance(name, str) self.name = name self.module = None @@ -1018,6 +1026,7 @@ class QAPISchemaEntity(object): # such place). self.info = info self.doc = doc +self.ifcond = listify_cond(ifcond) def c_name(self): return c_name(self.name) @@ -1150,8 +1159,8 @@ class QAPISchemaBuiltinType(QAPISchemaType): class QAPISchemaEnumType(QAPISchemaType): -def __init__(self, name, info, doc, values, prefix): -QAPISchemaType.__init__(self, name, info, doc) +def __init__(self, name, info, doc, ifcond, values, prefix): +QAPISchemaType.__init__(self, name, info, doc, ifcond) for v in values: assert isinstance(v, QAPISchemaMember) v.set_owner(name) @@ -1186,7 +1195,7 @@ class QAPISchemaEnumType(QAPISchemaType): class QAPISchemaArrayType(QAPISchemaType): def __init__(self, name, info, element_type): -QAPISchemaType.__init__(self, name, info, None) +QAPISchemaType.__init__(self, name, info, None, None) assert isinstance(element_type, str) self._element_type_name = element_type self.element_type = None @@ -1194,6 +1203,7 @@ class QAPISchemaArrayType(QAPISchemaType): def check(self, schema): self.element_type = schema.lookup_type(self._element_type_name) assert self.element_type +self.ifcond = self.element_type.ifcond def is_implicit(self): return True @@ -1215,11 +1225,12 @@ class QAPISchemaArrayType(QAPISchemaType): class QAPISchemaObjectType(QAPISchemaType): -def __init__(self, name, info, doc, base, local_members, variants): +def __init__(self, name, info, doc, ifcond, + base, local_members, variants): # struct has local_members, optional base, and no variants # flat union has base, variants, and no local_members # simple union has local_members, variants, and no base -QAPISchemaType.__init__(self, name, info, doc) +QAPISchemaType.__init__(self, name, info, doc, ifcond) assert base is None or isinstance(base, str) for m in local_members: assert isinstance(m, QAPISchemaObjectTypeMember) @@ -1407,8 +1418,8 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember): class QAPISchemaAlternateType(QAPISchemaType): -def __init__(self, name, info, doc, variants): -QAPISchemaType.__init__(self, name, info, doc) +def __init__(self, name, info, doc, ifcond, variants): +QAPISchemaType.__init__(self, name, info, doc, ifcond) assert isinstance(variants, QAPISchemaObjectTypeVariants) assert variants.tag_member variants.set_owner(name) @@ -1444,9 +1455,9 @@ class QAPISchemaAlternateType(QAPISchemaType): class QAPISchemaCommand(QAPISchemaEntity): -def __init__(self, name, info, doc, arg_type, ret_type, +def __init__(self, name, info, doc, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob): -QAPISchemaEntity.__init__(self, name, info, doc) +QAPISchemaEntity.__init__(self, name, info, doc, ifcond) assert not arg_type or isinstance(arg_type, str) assert not ret_type or isinstance(ret_type, str) self._arg_type_name = arg_type @@ -1485,8 +1496,8 @@ class QAPISchemaCommand(QAPISchemaEntity): class QAPISchemaEvent(QAPISchemaEntity): -def __init__(self, name, info, doc, arg_type, boxed): -QAPISchemaEntity.__init__(self, name, info, doc) +def __init__(self, name, info, doc, ifcond, arg_type, boxed): +QAPISchemaEntity.__init__(self, name, info, doc, ifcond)
[Qemu-devel] [PATCH v3 03/49] qapi: add 'if' to top-level expressions
Accept 'if' key in top-level elements, accepted as string or list of string type. The following patches will modify the test visitor to check the value is correctly saved, and generate #if/#endif code (as a single #if/endif line or a series for a list). Example of 'if' key: { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' }, 'if': 'defined(TEST_IF_STRUCT)' } The generated code is for now *unconditional*. Later patches generate the conditionals. A following patch for qapi-code-gen.txt will provide more complete documentation for 'if' usage. Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster --- scripts/qapi/common.py | 35 tests/test-qmp-cmds.c| 6 tests/Makefile.include | 6 tests/qapi-schema/bad-if-empty-list.err | 1 + tests/qapi-schema/bad-if-empty-list.exit | 1 + tests/qapi-schema/bad-if-empty-list.json | 3 ++ tests/qapi-schema/bad-if-empty-list.out | 0 tests/qapi-schema/bad-if-empty.err | 1 + tests/qapi-schema/bad-if-empty.exit | 1 + tests/qapi-schema/bad-if-empty.json | 3 ++ tests/qapi-schema/bad-if-empty.out | 0 tests/qapi-schema/bad-if-list.err| 1 + tests/qapi-schema/bad-if-list.exit | 1 + tests/qapi-schema/bad-if-list.json | 3 ++ tests/qapi-schema/bad-if-list.out| 0 tests/qapi-schema/bad-if.err | 1 + tests/qapi-schema/bad-if.exit| 1 + tests/qapi-schema/bad-if.json| 3 ++ tests/qapi-schema/bad-if.out | 0 tests/qapi-schema/qapi-schema-test.json | 20 ++ tests/qapi-schema/qapi-schema-test.out | 22 +++ 21 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 tests/qapi-schema/bad-if-empty-list.err create mode 100644 tests/qapi-schema/bad-if-empty-list.exit create mode 100644 tests/qapi-schema/bad-if-empty-list.json create mode 100644 tests/qapi-schema/bad-if-empty-list.out create mode 100644 tests/qapi-schema/bad-if-empty.err create mode 100644 tests/qapi-schema/bad-if-empty.exit create mode 100644 tests/qapi-schema/bad-if-empty.json create mode 100644 tests/qapi-schema/bad-if-empty.out create mode 100644 tests/qapi-schema/bad-if-list.err create mode 100644 tests/qapi-schema/bad-if-list.exit create mode 100644 tests/qapi-schema/bad-if-list.json create mode 100644 tests/qapi-schema/bad-if-list.out create mode 100644 tests/qapi-schema/bad-if.err create mode 100644 tests/qapi-schema/bad-if.exit create mode 100644 tests/qapi-schema/bad-if.json create mode 100644 tests/qapi-schema/bad-if.out diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 2c05e3c284..4f9e02b0b4 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -637,6 +637,27 @@ def add_name(name, info, meta, implicit=False): all_names[name] = meta +def check_if(expr, info): + +def check_if_str(ifcond, info): +if not isinstance(ifcond, str): +raise QAPISemError( +info, "'if' condition must be a string or a list of strings") +if ifcond == '': +raise QAPISemError(info, "'if' condition '' makes no sense") + +ifcond = expr.get('if') +if ifcond is None: +return +if isinstance(ifcond, list): +if ifcond == []: +raise QAPISemError(info, "'if' condition [] is useless") +for elt in ifcond: +check_if_str(elt, info) +else: +check_if_str(ifcond, info) + + def check_type(info, source, value, allow_array=False, allow_dict=False, allow_optional=False, allow_metas=[]): @@ -876,6 +897,8 @@ def check_keys(expr_elem, meta, required, optional=[]): raise QAPISemError(info, "'%s' of %s '%s' should only use true value" % (key, meta, name)) +if key == 'if': +check_if(expr, info) for key in required: if key not in expr: raise QAPISemError(info, "Key '%s' is missing from %s '%s'" @@ -904,28 +927,28 @@ def check_exprs(exprs): if 'enum' in expr: meta = 'enum' -check_keys(expr_elem, 'enum', ['data'], ['prefix']) +check_keys(expr_elem, 'enum', ['data'], ['if', 'prefix']) enum_types[expr[meta]] = expr elif 'union' in expr: meta = 'union' check_keys(expr_elem, 'union', ['data'], - ['base', 'discriminator']) + ['base', 'discriminator', 'if']) union_types[expr[meta]] = expr elif 'alternate' in expr: meta = 'alternate' -check_keys(expr_elem, 'alternate', ['data']) +check_keys(expr_elem, 'alternate', ['data'], ['if']) elif 'struct' in expr: meta = 'struct' -check_keys(expr_elem, 'struct', ['data'], ['base']) +check_keys(expr
[Qemu-devel] [PATCH v3 00/49] qapi: add #if pre-processor conditions to generated code
Hi, In order to clean-up some hacks in qapi (having to unregister commands at runtime), I proposed a "[PATCH v5 02/20] qapi.py: add a simple #ifdef condition" (see http://lists.gnu.org/archive/html/qemu-devel/2016-08/msg03106.html). However, we decided to drop that patch from the series and solve the problem later. The main issues were: - the syntax was awkward to the JSON schema and documentation - the evaluation of the condition was done in the qapi scripts, with very limited capability - each target/config would need different generated files. Instead, it could defer the #if evaluation to the C-preprocessor. With this series, top-level qapi JSON entity can take 'if' keys: { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' }, 'if': 'defined(TEST_IF_STRUCT)' } Members can be exploded as dictionnary with 'type'/'if' keys: { 'struct': 'TestIfStruct', 'data': { 'foo': 'int', 'bar': { 'type': 'int', 'if': 'defined(TEST_IF_STRUCT_BAR)'} } } Enum values can be exploded as dictionnary with 'type'/'if' keys: { 'enum': 'TestIfEnum', 'data': [ 'foo', { 'name' : 'bar', 'if': 'defined(TEST_IF_ENUM_BAR)' } ] } A benefit from having conditional schema is that introspection will reflect more accurately the capability of the server. Another benefit is that it may help to remove some dead code when disabling a functionality. Starting from patch "qapi: add conditions to VNC type/commands/events on the schema", the series demonstrates adding conditions. The schema is splitted in common and per-target parts starting from "RFC: qapi: learn to split schema by 'top-unit'" patch. This allows a target schema to use target-poisoned defines as conditions (such as TARGET_I386). There are a lot more things one can make conditional in the QAPI schema, like pci/kvm/xen/numa/vde/slirp/posix/win32/vsock/lzo etc etc, however I am still evaluating the implication of such changes both externally and internally, for those interested, I can share my wip branch. Comments welcome, v5: - adapt to the new 'modular' / single generator design, making splitting schema a bit more complicated than before, when it was only at build-sys level. See "RFC: qapi: learn to split schema by 'top-unit'" for the new apporach at splitting common and target parts. - replace the #if-wrapper decorator with a @contextmanager (if necessary, this could be replaced by explicit begin/end calls instead now) - better split of target events, introducing seperate limiter/emitter - add a 'RFC: make RTC_CHANGE per-target' to show how conditional could be used and exercice the 'per-unit' event limiter - +painful rebase - add some r-b tags v4: - added "qlit: use QType instead of int" patch - use a "default:" case in qobject_from_qlit() - added a test for invalid 'if': [''] - listify ifcond in constructors - added "qapi: leave the ifcond attribute undefined until check()" patch (could be squashed) - use a negative lookahead in "qapi: mcgen() shouldn't indent # lines" - fix extra empty line in "qapi-introspect: add preprocessor conditions to generated QLit" - added desugar/normalization passes, such as NAME -> { 'name': NAME } - splitted "qapi: change enum visitor to take QAPISchemaMember" - prettify test-qapi.py members output - added missing #if wrapping for enum members in generated introspection - clarified some error messages - added "qapi: rename allow_dict to allow_implicit" patch for clarity - added a seperate patch for "qapi: add a dictionnary form" for enum names - added a seperate patch for "qapi: add a dictionnary form" for struct members - squashed the patches adding #if to generated code (some types generate both enum and struct members for example, so a step-by-step is unnecessarily complicated to deal with) - squashed some tests with related patch - added "qapi: add an error in case a discriminator is conditionnal" - add back VNC-specific crypto 'des-rfb' when VNC is disabled - change the way unit filtering is done (so no -u means no filtering) - made target.json the top-level documentation schema - removed some blank lines in generated code output - improve documentation, add various tests - commit message improvements - misc pycodestyle/pep8 fixes - add r-b tags v3: - rebased (qlit is now merged upstream) - solve the per-target #ifdef problem by using a target.json and new qapi generated target files - update some commit messages based on Markus review - more schema error reporting - move the ifcond argument closer to info/doc - use mcgen() in gen_if()/gen_endif() - simplify "modify to_qlit() to take an optional suffix" - fix generated qlit indentation - fix temporary build break by merging #if types & visitors patch - fix some redundant condtionals generation - change enum visitor to take QAPISchemaMember - reject unknown dictionnary keys in { .., 'if': ..} - split qapi test visitor print() with trailing ',' trick v2: after Markus review - "qboject: add literal qobject type", splitted & many updates
[Qemu-devel] [PATCH v3 11/49] qapi/commands: add #if conditions to commands
Wrap generated code with #if/#endif using an 'ifcontext' on QAPIGenCSnippet objects. Signed-off-by: Marc-André Lureau --- scripts/qapi/commands.py | 19 ++- tests/test-qmp-cmds.c| 4 ++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index e2366b4801..40bb680b7c 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -237,7 +237,7 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor): QAPISchemaModularCVisitor.__init__( self, prefix, 'qapi-commands', ' * Schema-defined QAPI/QMP commands', __doc__) -self._regy = '' +self._regy = QAPIGenCSnippet() self._visited_ret_types = {} def _begin_module(self, name): @@ -273,19 +273,20 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor): void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds); ''', c_prefix=c_name(self._prefix, protect=False))) -genc.add(gen_registry(self._regy, self._prefix)) +genc.add(gen_registry(self._regy.get_content(), self._prefix)) def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob): if not gen: return -self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type)) -if ret_type and ret_type not in self._visited_ret_types[self._genc]: -self._visited_ret_types[self._genc].add(ret_type) -self._genc.add(gen_marshal_output(ret_type)) -self._genh.add(gen_marshal_decl(name)) -self._genc.add(gen_marshal(name, arg_type, boxed, ret_type)) -self._regy += gen_register_command(name, success_response, allow_oob) +with ifcontext(ifcond, self._genh, self._genc, self._regy): +self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type)) +if ret_type and ret_type not in self._visited_ret_types[self._genc]: +self._visited_ret_types[self._genc].add(ret_type) +self._genc.add(gen_marshal_output(ret_type)) +self._genh.add(gen_marshal_decl(name)) +self._genc.add(gen_marshal(name, arg_type, boxed, ret_type)) +self._regy.add(gen_register_command(name, success_response, allow_oob)) def gen_commands(schema, output_dir, prefix): diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c index c25fc2100a..e675722593 100644 --- a/tests/test-qmp-cmds.c +++ b/tests/test-qmp-cmds.c @@ -12,11 +12,11 @@ static QmpCommandList qmp_commands; -/* #if defined(TEST_IF_STRUCT) && defined(TEST_IF_CMD) */ +#if defined(TEST_IF_STRUCT) && defined(TEST_IF_CMD) void qmp_TestIfCmd(TestIfStruct *foo, Error **errp) { } -/* #endif */ +#endif void qmp_user_def_cmd(Error **errp) { -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 13/49] qapi-types: refactor variants handling
Generate variants objects outside gen_object(). This will allow to easily wrap gen_object() with ifcond_decorator in the following patch. gen_variants_objects() calls gen_object() for each variants, so it remains guarded for each generated variant object. self._gen_type_cleanup(name) is factored out in _gen_object(), helping generated code to be wrapped by the same condition in the following patch. Signed-off-by: Marc-André Lureau --- scripts/qapi/types.py | 38 +++--- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py index 298a80db62..3d9b0f9a07 100644 --- a/scripts/qapi/types.py +++ b/scripts/qapi/types.py @@ -55,23 +55,27 @@ def gen_struct_members(members): return ret -def gen_object(name, base, members, variants): -if name in objects_seen: -return '' -objects_seen.add(name) - +def gen_variants_objects(variants): ret = '' if variants: for v in variants.variants: if isinstance(v.type, QAPISchemaObjectType): +ret += gen_variants_objects(v.type.variants) ret += gen_object(v.type.name, v.type.base, v.type.local_members, v.type.variants) +return ret -ret += mcgen(''' + +def gen_object(name, base, members, variants): +if name in objects_seen: +return '' +objects_seen.add(name) + +ret = mcgen(''' struct %(c_name)s { ''', - c_name=c_name(name)) +c_name=c_name(name)) if base: if not base.is_implicit(): @@ -215,11 +219,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor): self._genh.add(gen_array(name, element_type)) self._gen_type_cleanup(name) -def visit_object_type(self, name, info, ifcond, base, members, variants): -# Nothing to do for the special empty builtin -if name == 'q_empty': -return -self._genh.preamble_add(gen_fwd_object_or_array(name)) +def _gen_object(self, name, info, ifcond, base, members, variants): self._genh.add(gen_object(name, base, members, variants)) if base and not base.is_implicit(): self._genh.add(gen_upcast(name, base)) @@ -229,11 +229,19 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor): # implicit types won't be directly allocated/freed self._gen_type_cleanup(name) +def visit_object_type(self, name, info, ifcond, base, members, variants): +# Nothing to do for the special empty builtin +if name == 'q_empty': +return +self._genh.preamble_add(gen_fwd_object_or_array(name)) +self._genh.add(gen_variants_objects(variants)) +self._gen_object(name, info, None, base, members, variants) + def visit_alternate_type(self, name, info, ifcond, variants): self._genh.preamble_add(gen_fwd_object_or_array(name)) -self._genh.add(gen_object(name, None, - [variants.tag_member], variants)) -self._gen_type_cleanup(name) +self._genh.add(gen_variants_objects(variants)) +self._gen_object(name, info, None, None, + [variants.tag_member], variants) def gen_types(schema, output_dir, prefix, opt_builtins): -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 09/49] qapi-introspect: modify to_qlit() to append ', ' on level > 0
The following patch is going to break list entries with #if/#endif, so they should have the trailing ',' as suffix. Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster --- scripts/qapi/introspect.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py index 6cb95cf53e..1a8eb9e33e 100644 --- a/scripts/qapi/introspect.py +++ b/scripts/qapi/introspect.py @@ -30,7 +30,7 @@ def to_qlit(obj, level=0, suppress_first_indent=False): for elt in obj] elts.append(indent(level + 1) + "{}") ret += 'QLIT_QLIST(((QLitObject[]) {\n' -ret += ',\n'.join(elts) + '\n' +ret += '\n'.join(elts) + '\n' ret += indent(level) + '}))' elif isinstance(obj, dict): elts = [] @@ -45,6 +45,8 @@ def to_qlit(obj, level=0, suppress_first_indent=False): ret += 'QLIT_QBOOL(%s)' % ('true' if obj else 'false') else: assert False# not implemented +if level > 0: +ret += ',' return ret -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 06/49] qapi: add 'ifcond' to visitor methods
Modify the test visitor to check correct passing of values. Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster --- scripts/qapi/commands.py | 2 +- scripts/qapi/common.py | 31 ++ scripts/qapi/doc.py| 10 - scripts/qapi/events.py | 2 +- scripts/qapi/introspect.py | 12 +- scripts/qapi/types.py | 8 +++ scripts/qapi/visit.py | 8 +++ tests/qapi-schema/qapi-schema-test.out | 9 tests/qapi-schema/test-qapi.py | 19 +++- 9 files changed, 61 insertions(+), 40 deletions(-) mode change 100644 => 100755 scripts/qapi/doc.py diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index 0c5da3a54d..e2366b4801 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -275,7 +275,7 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds); c_prefix=c_name(self._prefix, protect=False))) genc.add(gen_registry(self._regy, self._prefix)) -def visit_command(self, name, info, arg_type, ret_type, +def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob): if not gen: return diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index eb07d641ab..bc4ecd6c76 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -1067,26 +1067,26 @@ class QAPISchemaVisitor(object): def visit_builtin_type(self, name, info, json_type): pass -def visit_enum_type(self, name, info, values, prefix): +def visit_enum_type(self, name, info, ifcond, values, prefix): pass -def visit_array_type(self, name, info, element_type): +def visit_array_type(self, name, info, ifcond, element_type): pass -def visit_object_type(self, name, info, base, members, variants): +def visit_object_type(self, name, info, ifcond, base, members, variants): pass -def visit_object_type_flat(self, name, info, members, variants): +def visit_object_type_flat(self, name, info, ifcond, members, variants): pass -def visit_alternate_type(self, name, info, variants): +def visit_alternate_type(self, name, info, ifcond, variants): pass -def visit_command(self, name, info, arg_type, ret_type, +def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob): pass -def visit_event(self, name, info, arg_type, boxed): +def visit_event(self, name, info, ifcond, arg_type, boxed): pass @@ -1196,7 +1196,7 @@ class QAPISchemaEnumType(QAPISchemaType): return 'string' def visit(self, visitor): -visitor.visit_enum_type(self.name, self.info, +visitor.visit_enum_type(self.name, self.info, self.ifcond, self.member_names(), self.prefix) @@ -1230,7 +1230,8 @@ class QAPISchemaArrayType(QAPISchemaType): return 'array of ' + elt_doc_type def visit(self, visitor): -visitor.visit_array_type(self.name, self.info, self.element_type) +visitor.visit_array_type(self.name, self.info, self.ifcond, + self.element_type) class QAPISchemaObjectType(QAPISchemaType): @@ -1312,9 +1313,9 @@ class QAPISchemaObjectType(QAPISchemaType): return 'object' def visit(self, visitor): -visitor.visit_object_type(self.name, self.info, +visitor.visit_object_type(self.name, self.info, self.ifcond, self.base, self.local_members, self.variants) -visitor.visit_object_type_flat(self.name, self.info, +visitor.visit_object_type_flat(self.name, self.info, self.ifcond, self.members, self.variants) @@ -1459,7 +1460,8 @@ class QAPISchemaAlternateType(QAPISchemaType): return 'value' def visit(self, visitor): -visitor.visit_alternate_type(self.name, self.info, self.variants) +visitor.visit_alternate_type(self.name, self.info, self.ifcond, + self.variants) def is_empty(self): return False @@ -1501,7 +1503,7 @@ class QAPISchemaCommand(QAPISchemaEntity): assert isinstance(self.ret_type, QAPISchemaType) def visit(self, visitor): -visitor.visit_command(self.name, self.info, +visitor.visit_command(self.name, self.info, self.ifcond, self.arg_type, self.ret_type, self.gen, self.success_response, self.boxed, self.allow_oob) @@ -1533,7 +1535,8 @@ class QAPISchemaEvent(QAPISchemaEntity): raise QAPISemError(self.info, "Use of 'boxed' requires 'data'") def visit(self, visitor): -
[Qemu-devel] [PATCH v3 14/49] qapi-types: add #if conditions to types & visitors
Types & visitors are coupled and must be handled together to avoid temporary build regression. Wrap generated types/visitor code with #if/#endif using the context helpers. Signed-off-by: Marc-André Lureau --- scripts/qapi/types.py | 46 ++- scripts/qapi/visit.py | 33 ++- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py index 3d9b0f9a07..ce4c91206c 100644 --- a/scripts/qapi/types.py +++ b/scripts/qapi/types.py @@ -61,8 +61,10 @@ def gen_variants_objects(variants): for v in variants.variants: if isinstance(v.type, QAPISchemaObjectType): ret += gen_variants_objects(v.type.variants) +ret += gen_if(v.type.ifcond) ret += gen_object(v.type.name, v.type.base, v.type.local_members, v.type.variants) +ret += gen_endif(v.type.ifcond) return ret @@ -206,41 +208,49 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor): # gen_object() is recursive, ensure it doesn't visit the empty type objects_seen.add(schema.the_empty_object_type.name) -def _gen_type_cleanup(self, name): -self._genh.add(gen_type_cleanup_decl(name)) -self._genc.add(gen_type_cleanup(name)) +def _gen_type_cleanup(self, name, ifcond): +with ifcontext(ifcond, self._genh, self._genc): +self._genh.add(gen_type_cleanup_decl(name)) +self._genc.add(gen_type_cleanup(name)) def visit_enum_type(self, name, info, ifcond, values, prefix): -self._genh.preamble_add(gen_enum(name, values, prefix)) -self._genc.add(gen_enum_lookup(name, values, prefix)) +with ifcontext(ifcond, self._genh, self._genc): +self._genh.preamble_add(gen_enum(name, values, prefix)) +self._genc.add(gen_enum_lookup(name, values, prefix)) def visit_array_type(self, name, info, ifcond, element_type): -self._genh.preamble_add(gen_fwd_object_or_array(name)) -self._genh.add(gen_array(name, element_type)) -self._gen_type_cleanup(name) +with ifcontext(ifcond, self._genh): +self._genh.preamble_add(gen_fwd_object_or_array(name)) +self._genh.add(gen_array(name, element_type)) +self._gen_type_cleanup(name, ifcond) def _gen_object(self, name, info, ifcond, base, members, variants): -self._genh.add(gen_object(name, base, members, variants)) -if base and not base.is_implicit(): -self._genh.add(gen_upcast(name, base)) -# TODO Worth changing the visitor signature, so we could -# directly use rather than repeat type.is_implicit()? +with ifcontext(ifcond, self._genh): +self._genh.add(gen_object(name, base, members, variants)) +if base and not base.is_implicit(): +self._genh.add(gen_upcast(name, base)) +# TODO Worth changing the visitor signature, so we could +# directly use rather than repeat type.is_implicit()? if not name.startswith('q_'): # implicit types won't be directly allocated/freed -self._gen_type_cleanup(name) +self._gen_type_cleanup(name, ifcond) + +def _gen_fwd_object_or_array(self, name, ifcond): +with ifcontext(ifcond, self._genh): +self._genh.preamble_add(gen_fwd_object_or_array(name)) def visit_object_type(self, name, info, ifcond, base, members, variants): # Nothing to do for the special empty builtin if name == 'q_empty': return -self._genh.preamble_add(gen_fwd_object_or_array(name)) +self._gen_fwd_object_or_array(name, ifcond) self._genh.add(gen_variants_objects(variants)) -self._gen_object(name, info, None, base, members, variants) +self._gen_object(name, info, ifcond, base, members, variants) def visit_alternate_type(self, name, info, ifcond, variants): -self._genh.preamble_add(gen_fwd_object_or_array(name)) +self._gen_fwd_object_or_array(name, ifcond) self._genh.add(gen_variants_objects(variants)) -self._gen_object(name, info, None, None, +self._gen_object(name, info, ifcond, None, [variants.tag_member], variants) diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index 9ea2e04f81..e4a62ce030 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -302,29 +302,34 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor): types=types)) def visit_enum_type(self, name, info, ifcond, values, prefix): -self._genh.add(gen_visit_decl(name, scalar=True)) -self._genc.add(gen_visit_enum(name)) +with ifcontext(ifcond, self._genh, self._genc): +self._genh.add(gen_visit_decl(name, scalar=True)
[Qemu-devel] [PATCH v3 10/49] qapi-introspect: add preprocessor conditions to generated QLit
The generator will take (obj, condition) tuples to wrap generated QLit objects for 'obj' with #if/#endif conditions. This commit adds 'ifcond' condition to top-level QLit objects. See generated tests/test-qmp-introspect.c. Example diff after this patch: --- before 2018-01-08 11:55:24.757083654 +0100 +++ tests/test-qmp-introspect.c 2018-01-08 13:08:44.477641629 +0100 @@ -51,6 +51,8 @@ { "name", QLIT_QSTR("EVENT_F"), }, {} })), +#if defined(TEST_IF_CMD) +#if defined(TEST_IF_STRUCT) QLIT_QDICT(((QLitDictEntry[]) { { "arg-type", QLIT_QSTR("5"), }, { "meta-type", QLIT_QSTR("command"), }, @@ -58,12 +60,16 @@ { "ret-type", QLIT_QSTR("0"), }, {} })), +#endif /* defined(TEST_IF_STRUCT) */ +#endif /* defined(TEST_IF_CMD) */ Signed-off-by: Marc-André Lureau --- scripts/qapi/introspect.py | 31 +-- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py index 1a8eb9e33e..cb4825f134 100644 --- a/scripts/qapi/introspect.py +++ b/scripts/qapi/introspect.py @@ -18,6 +18,15 @@ def to_qlit(obj, level=0, suppress_first_indent=False): def indent(level): return level * 4 * ' ' +if isinstance(obj, tuple): +ifobj, ifcond = obj +ret = gen_if(ifcond) +ret += to_qlit(ifobj, level) +endif = gen_endif(ifcond) +if endif: +ret += '\n' + endif +return ret + ret = '' if not suppress_first_indent: ret += indent(level) @@ -26,7 +35,7 @@ def to_qlit(obj, level=0, suppress_first_indent=False): elif isinstance(obj, str): ret += 'QLIT_QSTR(' + to_c_string(obj) + ')' elif isinstance(obj, list): -elts = [to_qlit(elt, level + 1) +elts = [to_qlit(elt, level + 1).strip('\n') for elt in obj] elts.append(indent(level + 1) + "{}") ret += 'QLIT_QLIST(((QLitObject[]) {\n' @@ -131,12 +140,12 @@ const QLitObject %(c_name)s = %(c_string)s; return '[' + self._use_type(typ.element_type) + ']' return self._name(typ.name) -def _gen_qlit(self, name, mtype, obj): +def _gen_qlit(self, name, mtype, obj, ifcond): if mtype not in ('command', 'event', 'builtin', 'array'): name = self._name(name) obj['name'] = name obj['meta-type'] = mtype -self._qlits.append(obj) +self._qlits.append((obj, ifcond)) def _gen_member(self, member): ret = {'name': member.name, 'type': self._use_type(member.type)} @@ -152,26 +161,27 @@ const QLitObject %(c_name)s = %(c_string)s; return {'case': variant.name, 'type': self._use_type(variant.type)} def visit_builtin_type(self, name, info, json_type): -self._gen_qlit(name, 'builtin', {'json-type': json_type}) +self._gen_qlit(name, 'builtin', {'json-type': json_type}, []) def visit_enum_type(self, name, info, ifcond, values, prefix): -self._gen_qlit(name, 'enum', {'values': values}) +self._gen_qlit(name, 'enum', {'values': values}, ifcond) def visit_array_type(self, name, info, ifcond, element_type): element = self._use_type(element_type) -self._gen_qlit('[' + element + ']', 'array', {'element-type': element}) +self._gen_qlit('[' + element + ']', 'array', {'element-type': element}, + ifcond) def visit_object_type_flat(self, name, info, ifcond, members, variants): obj = {'members': [self._gen_member(m) for m in members]} if variants: obj.update(self._gen_variants(variants.tag_member.name, variants.variants)) -self._gen_qlit(name, 'object', obj) +self._gen_qlit(name, 'object', obj, ifcond) def visit_alternate_type(self, name, info, ifcond, variants): self._gen_qlit(name, 'alternate', {'members': [{'type': self._use_type(m.type)} -for m in variants.variants]}) +for m in variants.variants]}, ifcond) def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob): @@ -180,11 +190,12 @@ const QLitObject %(c_name)s = %(c_string)s; self._gen_qlit(name, 'command', {'arg-type': self._use_type(arg_type), 'ret-type': self._use_type(ret_type), -'allow-oob': allow_oob}) +'allow-oob': allow_oob}, ifcond) def visit_event(self, name, info, ifcond, arg_type, boxed): arg_type = arg_type or self._schema.the_empty_object_type -self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type)}) +self._gen_qlit(name, 'event', {'arg-type': self._
[Qemu-devel] [PATCH v3 08/49] qapi: add #if/#endif helpers
Add helpers to wrap generated code with #if/#endif lines. Add QAPIGenCSnippet class to write C snippet code, make QAPIGenC inherit from it, for full C files with copyright headers etc. Add a 'with' statement context manager that will be used to wrap generator visitor methods. The manager will check if code was generated before adding #if/#endif lines on QAPIGenCSnippet objects. Used in the following patches. Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py | 82 +++--- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 47efe79758..60c1d0a783 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -12,6 +12,7 @@ # See the COPYING file in the top-level directory. from __future__ import print_function +from contextlib import contextmanager import errno import os import re @@ -1964,6 +1965,40 @@ def guardend(name): name=guardname(name)) +def gen_if(ifcond): +ret = '' +for ifc in ifcond: +ret += mcgen(''' +#if %(cond)s +''', cond=ifc) +return ret + + +def gen_endif(ifcond): +ret = '' +for ifc in reversed(ifcond): +ret += mcgen(''' +#endif /* %(cond)s */ +''', cond=ifc) +return ret + + +def wrap_ifcond(ifcond, before, after): +if ifcond is None or before == after: +return after + +assert after.startswith(before) +out = before +added = after[len(before):] +if added[0] == '\n': +out += '\n' +added = added[1:] +out += gen_if(ifcond) +out += added +out += gen_endif(ifcond) +return out + + def gen_enum_lookup(name, values, prefix=None): ret = mcgen(''' @@ -2054,6 +2089,7 @@ class QAPIGen(object): def __init__(self): self._preamble = '' self._body = '' +self._ifcond = None def preamble_add(self, text): self._preamble += text @@ -2061,6 +2097,23 @@ class QAPIGen(object): def add(self, text): self._body += text +def start_if(self, ifcond): +self._ifcond = ifcond +self._start_if_body = self._body +self._start_if_preamble = self._preamble + +def _wrap_ifcond(self): +pass + +def end_if(self): +self._wrap_ifcond() +self._ifcond = None + +def get_content(self, fname=None): +assert self._ifcond is None +return (self._top(fname) + self._preamble + self._body ++ self._bottom(fname)) + def _top(self, fname): return '' @@ -2078,8 +2131,7 @@ class QAPIGen(object): raise fd = os.open(pathname, os.O_RDWR | os.O_CREAT, 0o666) f = os.fdopen(fd, 'r+') -text = (self._top(fname) + self._preamble + self._body -+ self._bottom(fname)) +text = self.get_content(fname) oldtext = f.read(len(text) + 1) if text != oldtext: f.seek(0) @@ -2088,10 +2140,32 @@ class QAPIGen(object): f.close() -class QAPIGenC(QAPIGen): +@contextmanager +def ifcontext(ifcond, *args): +saved = [] +for arg in args: +arg.start_if(ifcond) +yield +for arg in args: +arg.end_if() -def __init__(self, blurb, pydoc): + +class QAPIGenCSnippet(QAPIGen): + +def __init__(self): QAPIGen.__init__(self) + +def _wrap_ifcond(self): +self._body = wrap_ifcond(self._ifcond, + self._start_if_body, self._body) +self._preamble = wrap_ifcond(self._ifcond, + self._start_if_preamble, self._preamble) + + +class QAPIGenC(QAPIGenCSnippet): + +def __init__(self, blurb, pydoc): +QAPIGenCSnippet.__init__(self) self._blurb = blurb self._copyright = '\n * '.join(re.findall(r'^Copyright .*', pydoc, re.MULTILINE)) -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 17/49] qapi: change enum visitor to take QAPISchemaMember
This will allow to add and access more properties associated with enum values/members, like the associated 'if' condition. We may want to have a specialized type QAPISchemaEnumMember, for now this will do. Suggested-by: Markus Armbruster Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py | 12 ++-- scripts/qapi/events.py | 2 +- scripts/qapi/introspect.py | 3 ++- tests/qapi-schema/test-qapi.py | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index ea5cdfe3be..4d19146064 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -1198,7 +1198,7 @@ class QAPISchemaEnumType(QAPISchemaType): def visit(self, visitor): visitor.visit_enum_type(self.name, self.info, self.ifcond, -self.member_names(), self.prefix) +self.members, self.prefix) class QAPISchemaArrayType(QAPISchemaType): @@ -2007,11 +2007,11 @@ const QEnumLookup %(c_name)s_lookup = { ''', c_name=c_name(name)) for m in members: -index = c_enum_const(name, m, prefix) +index = c_enum_const(name, m.name, prefix) ret += mcgen(''' -[%(index)s] = "%(value)s", +[%(index)s] = "%(name)s", ''', - index=index, value=m) + index=index, name=m.name) ret += mcgen(''' }, @@ -2024,7 +2024,7 @@ const QEnumLookup %(c_name)s_lookup = { def gen_enum(name, members, prefix=None): # append automatically generated _MAX value -enum_members = members + ['_MAX'] +enum_members = members + [QAPISchemaMember('_MAX')] ret = mcgen(''' @@ -2036,7 +2036,7 @@ typedef enum %(c_name)s { ret += mcgen(''' %(c_enum)s, ''', - c_enum=c_enum_const(name, m, prefix)) + c_enum=c_enum_const(name, m.name, prefix)) ret += mcgen(''' } %(c_name)s; diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py index dae03e3d88..233c27a6c8 100644 --- a/scripts/qapi/events.py +++ b/scripts/qapi/events.py @@ -188,7 +188,7 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor): with ifcontext(ifcond, self._genh, self._genc): self._genh.add(gen_event_send_decl(name, arg_type, boxed)) self._genc.add(gen_event_send(name, arg_type, boxed, self._enum_name)) -self._event_names.append(name) +self._event_names.append(QAPISchemaMember(name)) def gen_events(schema, output_dir, prefix): diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py index 66f7fd00a9..d62fca84de 100644 --- a/scripts/qapi/introspect.py +++ b/scripts/qapi/introspect.py @@ -164,7 +164,8 @@ const QLitObject %(c_name)s = %(c_string)s; self._gen_qlit(name, 'builtin', {'json-type': json_type}, []) def visit_enum_type(self, name, info, ifcond, members, prefix): -self._gen_qlit(name, 'enum', {'values': members}, ifcond) +self._gen_qlit(name, 'enum', + {'values': [m.name for m in members]}, ifcond) def visit_array_type(self, name, info, ifcond, element_type): element = self._use_type(element_type) diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py index f4b8feb9bc..3623deae62 100644 --- a/tests/qapi-schema/test-qapi.py +++ b/tests/qapi-schema/test-qapi.py @@ -24,7 +24,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor): print('include %s' % name) def visit_enum_type(self, name, info, ifcond, members, prefix): -print('enum %s %s' % (name, members)) +print('enum %s %s' % (name, [m.name for m in members])) if prefix: print('prefix %s' % prefix) self._print_if(ifcond) -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 19/49] qapi: factor out check_known_keys()
The following patches are going to need similar checks from various code path. This refactoring will report all conflicting keys (instead of the first one encountered). Modify unknown-expr-key to check plural form. Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py | 27 ++--- tests/qapi-schema/alternate-base.err| 2 +- tests/qapi-schema/double-type.err | 2 +- tests/qapi-schema/enum-missing-data.err | 2 +- tests/qapi-schema/unknown-expr-key.err | 2 +- tests/qapi-schema/unknown-expr-key.json | 2 +- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 4d19146064..fdbb5f1823 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -879,6 +879,24 @@ def check_struct(expr, info): allow_metas=['struct']) +def check_known_keys(info, source, keys, required, optional): + +def pprint(elems): +return ', '.join("'" + e + "'" for e in sorted(elems)) + +missing = set(required) - set(keys) +if missing: +raise QAPISemError(info, "%s must have %s key%s" + % (source, pprint(missing), + 's' if len(missing) > 1 else '')) +allowed = set(required + optional) +unknown = set(keys) - allowed +if unknown: +raise QAPISemError(info, "%s has unknown key%s %s (allowed: %s)" + % (source, 's' if len(unknown) > 1 else '', + pprint(unknown), pprint(allowed))) + + def check_keys(expr_elem, meta, required, optional=[]): expr = expr_elem['expr'] info = expr_elem['info'] @@ -886,10 +904,9 @@ def check_keys(expr_elem, meta, required, optional=[]): if not isinstance(name, str): raise QAPISemError(info, "'%s' key must have a string value" % meta) required = required + [meta] +source = "%s '%s'" % (meta, name) +check_known_keys(info, source, expr, required, optional) for (key, value) in expr.items(): -if key not in required and key not in optional: -raise QAPISemError(info, "Unknown key '%s' in %s '%s'" - % (key, meta, name)) if (key == 'gen' or key == 'success-response') and value is not False: raise QAPISemError(info, "'%s' of %s '%s' should only use false value" @@ -900,10 +917,6 @@ def check_keys(expr_elem, meta, required, optional=[]): % (key, meta, name)) if key == 'if': check_if(expr, info) -for key in required: -if key not in expr: -raise QAPISemError(info, "Key '%s' is missing from %s '%s'" - % (key, meta, name)) def check_exprs(exprs): diff --git a/tests/qapi-schema/alternate-base.err b/tests/qapi-schema/alternate-base.err index 30d8a34373..2b09c4c7a3 100644 --- a/tests/qapi-schema/alternate-base.err +++ b/tests/qapi-schema/alternate-base.err @@ -1 +1 @@ -tests/qapi-schema/alternate-base.json:4: Unknown key 'base' in alternate 'Alt' +tests/qapi-schema/alternate-base.json:4: alternate 'Alt' has unknown key 'base' (allowed: 'alternate', 'data', 'if') diff --git a/tests/qapi-schema/double-type.err b/tests/qapi-schema/double-type.err index f9613c6d6b..a8c5637659 100644 --- a/tests/qapi-schema/double-type.err +++ b/tests/qapi-schema/double-type.err @@ -1 +1 @@ -tests/qapi-schema/double-type.json:2: Unknown key 'command' in struct 'bar' +tests/qapi-schema/double-type.json:2: struct 'bar' has unknown key 'command' (allowed: 'base', 'data', 'if', 'struct') diff --git a/tests/qapi-schema/enum-missing-data.err b/tests/qapi-schema/enum-missing-data.err index ba4873ae69..68e286badc 100644 --- a/tests/qapi-schema/enum-missing-data.err +++ b/tests/qapi-schema/enum-missing-data.err @@ -1 +1 @@ -tests/qapi-schema/enum-missing-data.json:2: Key 'data' is missing from enum 'MyEnum' +tests/qapi-schema/enum-missing-data.json:2: enum 'MyEnum' must have 'data' key diff --git a/tests/qapi-schema/unknown-expr-key.err b/tests/qapi-schema/unknown-expr-key.err index 12f5ed5b43..d9f4e41cac 100644 --- a/tests/qapi-schema/unknown-expr-key.err +++ b/tests/qapi-schema/unknown-expr-key.err @@ -1 +1 @@ -tests/qapi-schema/unknown-expr-key.json:2: Unknown key 'bogus' in struct 'bar' +tests/qapi-schema/unknown-expr-key.json:2: struct 'bar' has unknown keys 'bogus', 'foo' (allowed: 'base', 'data', 'if', 'struct') diff --git a/tests/qapi-schema/unknown-expr-key.json b/tests/qapi-schema/unknown-expr-key.json index 3b2be00cc4..5bcb8efd1d 100644 --- a/tests/qapi-schema/unknown-expr-key.json +++ b/tests/qapi-schema/unknown-expr-key.json @@ -1,2 +1,2 @@ # we reject an expression with unknown top-level keys -{ 'struct': 'bar', 'data': { 'string': 'str'}, 'bogus': { } } +{ 'struct': 'bar', 'data': { 'string': 'str'}, 'bogus': { }, 'foo': { } } -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 12/49] qapi/events: add #if conditions to events
Wrap generated code with #if/#endif using an 'ifcontext' on QAPIGenCSnippet objects. Signed-off-by: Marc-André Lureau --- scripts/qapi/events.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py index 26ae00f6f7..dae03e3d88 100644 --- a/scripts/qapi/events.py +++ b/scripts/qapi/events.py @@ -185,8 +185,9 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor): genc.add(gen_enum_lookup(self._enum_name, self._event_names)) def visit_event(self, name, info, ifcond, arg_type, boxed): -self._genh.add(gen_event_send_decl(name, arg_type, boxed)) -self._genc.add(gen_event_send(name, arg_type, boxed, self._enum_name)) +with ifcontext(ifcond, self._genh, self._genc): +self._genh.add(gen_event_send_decl(name, arg_type, boxed)) +self._genc.add(gen_event_send(name, arg_type, boxed, self._enum_name)) self._event_names.append(name) -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 23/49] qapi: rename allow_dict to allow_implicit
This makes it a bit clearer what is the intent of the dictionnary for the check_type() function, since there was some confusion on a previous iteration of this series. Suggested-by: Markus Armbruster Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 22ea286191..9eb2b0cc37 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -660,7 +660,7 @@ def check_if(expr, info): def check_type(info, source, value, allow_array=False, - allow_dict=False, allow_optional=False, + allow_implicit=False, allow_optional=False, allow_metas=[]): global all_names @@ -687,7 +687,7 @@ def check_type(info, source, value, allow_array=False, (source, all_names[value], value)) return -if not allow_dict: +if not allow_implicit: raise QAPISemError(info, "%s should be a type name" % source) if not isinstance(value, OrderedDict): @@ -717,7 +717,7 @@ def check_command(expr, info): if boxed: args_meta += ['union', 'alternate'] check_type(info, "'data' for command '%s'" % name, - expr.get('data'), allow_dict=not boxed, allow_optional=True, + expr.get('data'), allow_implicit=not boxed, allow_optional=True, allow_metas=args_meta) returns_meta = ['union', 'struct'] if name in returns_whitelist: @@ -735,7 +735,7 @@ def check_event(expr, info): if boxed: meta += ['union', 'alternate'] check_type(info, "'data' for event '%s'" % name, - expr.get('data'), allow_dict=not boxed, allow_optional=True, + expr.get('data'), allow_implicit=not boxed, allow_optional=True, allow_metas=meta) @@ -763,7 +763,7 @@ def check_union(expr, info): else: # The object must have a string or dictionary 'base'. check_type(info, "'base' for union '%s'" % name, - base, allow_dict=True, allow_optional=True, + base, allow_implicit=True, allow_optional=True, allow_metas=['struct']) if not base: raise QAPISemError(info, "Flat union '%s' must have a base" @@ -894,7 +894,7 @@ def check_struct(expr, info): members = expr['data'] check_type(info, "'data' for struct '%s'" % name, members, - allow_dict=True, allow_optional=True) + allow_implicit=True, allow_optional=True) check_type(info, "'base' for struct '%s'" % name, expr.get('base'), allow_metas=['struct']) -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 18/49] tests: modify visit_enum_type() in test-qapi to print members
Use a common self._print_members() to print enum members details. Signed-off-by: Marc-André Lureau --- tests/qapi-schema/comments.out | 14 ++- tests/qapi-schema/doc-bad-section.out| 13 ++- tests/qapi-schema/doc-good.out | 17 ++-- tests/qapi-schema/empty.out | 9 - tests/qapi-schema/event-case.out | 9 - tests/qapi-schema/ident-with-escape.out | 9 - tests/qapi-schema/include-relpath.out| 14 ++- tests/qapi-schema/include-repetition.out | 14 ++- tests/qapi-schema/include-simple.out | 14 ++- tests/qapi-schema/indented-expr.out | 9 - tests/qapi-schema/qapi-schema-test.out | 49 +++- tests/qapi-schema/test-qapi.py | 18 ++--- 12 files changed, 158 insertions(+), 31 deletions(-) diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out index 8d2f1ce8a2..d1abc4b5a1 100644 --- a/tests/qapi-schema/comments.out +++ b/tests/qapi-schema/comments.out @@ -1,5 +1,15 @@ object q_empty -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool'] +enum QType prefix QTYPE +member none +member qnull +member qnum +member qstring +member qdict +member qlist +member qbool module comments.json -enum Status ['good', 'bad', 'ugly'] +enum Status +member good +member bad +member ugly diff --git a/tests/qapi-schema/doc-bad-section.out b/tests/qapi-schema/doc-bad-section.out index cd28721568..db8014eed0 100644 --- a/tests/qapi-schema/doc-bad-section.out +++ b/tests/qapi-schema/doc-bad-section.out @@ -1,8 +1,17 @@ object q_empty -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool'] +enum QType prefix QTYPE +member none +member qnull +member qnum +member qstring +member qdict +member qlist +member qbool module doc-bad-section.json -enum Enum ['one', 'two'] +enum Enum +member one +member two doc symbol=Enum body= == Produces *invalid* texinfo diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out index 430b5a87db..3cd5c094aa 100644 --- a/tests/qapi-schema/doc-good.out +++ b/tests/qapi-schema/doc-good.out @@ -1,8 +1,17 @@ object q_empty -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool'] +enum QType prefix QTYPE +member none +member qnull +member qnum +member qstring +member qdict +member qlist +member qbool module doc-good.json -enum Enum ['one', 'two'] +enum Enum +member one +member two object Base member base1: Enum optional=False object Variant1 @@ -17,7 +26,9 @@ object q_obj_Variant1-wrapper member data: Variant1 optional=False object q_obj_Variant2-wrapper member data: Variant2 optional=False -enum SugaredUnionKind ['one', 'two'] +enum SugaredUnionKind +member one +member two object SugaredUnion member type: SugaredUnionKind optional=False tag type diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out index 0ec234eec4..5483cb7bc6 100644 --- a/tests/qapi-schema/empty.out +++ b/tests/qapi-schema/empty.out @@ -1,3 +1,10 @@ object q_empty -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool'] +enum QType prefix QTYPE +member none +member qnull +member qnum +member qstring +member qdict +member qlist +member qbool diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out index 88c0964917..f69d4ffe4e 100644 --- a/tests/qapi-schema/event-case.out +++ b/tests/qapi-schema/event-case.out @@ -1,6 +1,13 @@ object q_empty -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool'] +enum QType prefix QTYPE +member none +member qnull +member qnum +member qstring +member qdict +member qlist +member qbool module event-case.json event oops None boxed=False diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out index ee3b34e623..41b90fb944 100644 --- a/tests/qapi-schema/ident-with-escape.out +++ b/tests/qapi-schema/ident-with-escape.out @@ -1,6 +1,13 @@ object q_empty -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool'] +enum QType prefix QTYPE +member none +member qnull +member qnum +member qstring +member qdict +member qlist +member qbool module ident-with-escape.json object q_obj_fooA-arg member bar1: str optional=False diff --git a/tests/qapi-schema/include-relpath.out b/tests/qapi-schema/include-relpath.out index ebbabd7a18..783ccfc855 100644 --- a/tests/qapi-schema/include-relpath.out +++ b/tests/qapi-schema/include-relpath.out @@ -1,9 +1,19 @@ object q_empty -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool'] +enum QType prefix QTYPE +member none +member qnull +member qnum +member qstring +member qdict +member qlist +
[Qemu-devel] [PATCH v3 21/49] qapi: add 'if' to enum members
QAPISchemaMember gains .ifcond for enum members: inherited classes, such as QAPISchemaObjectTypeMember, will thus have an ifcond member after this (those different types will also use the .ifcond to store the condition and generate conditional code in the following patches). Generated code is not changed by this patch, but with "qapi: add #if conditions to generated code" patch. Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py | 10 +++--- tests/Makefile.include | 1 + tests/qapi-schema/enum-dict-member-unknown.err | 2 +- tests/qapi-schema/enum-if-invalid.err | 1 + tests/qapi-schema/enum-if-invalid.exit | 1 + tests/qapi-schema/enum-if-invalid.json | 3 +++ tests/qapi-schema/enum-if-invalid.out | 0 tests/qapi-schema/qapi-schema-test.json| 5 +++-- tests/qapi-schema/qapi-schema-test.out | 2 ++ tests/qapi-schema/test-qapi.py | 1 + 10 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 tests/qapi-schema/enum-if-invalid.err create mode 100644 tests/qapi-schema/enum-if-invalid.exit create mode 100644 tests/qapi-schema/enum-if-invalid.json create mode 100644 tests/qapi-schema/enum-if-invalid.out diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 6aece364f1..22ea286191 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -883,7 +883,8 @@ def check_enum(expr, info): for member in members: source = "Dictionary member of enum '%s'" % name -check_known_keys(info, source, member, ['name'], []) +check_known_keys(info, source, member, ['name'], ['if']) +check_if(member, info) check_name(info, "Member of enum '%s'" % name, member['name'], enum_member=True) @@ -1362,9 +1363,10 @@ class QAPISchemaObjectType(QAPISchemaType): class QAPISchemaMember(object): role = 'member' -def __init__(self, name): +def __init__(self, name, ifcond=None): assert isinstance(name, str) self.name = name +self.ifcond = listify_cond(ifcond) self.owner = None def set_owner(self, name): @@ -1661,9 +1663,11 @@ class QAPISchema(object): for v in values: if isinstance(v, dict): name = v['name'] +ifcond = v.get('if') else: name = v -enum.append(QAPISchemaMember(name)) +ifcond = None +enum.append(QAPISchemaMember(name, ifcond)) return enum def _make_implicit_enum_type(self, name, info, ifcond, values): diff --git a/tests/Makefile.include b/tests/Makefile.include index 444c3fd33e..19873ea887 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -481,6 +481,7 @@ qapi-schema += enum-bad-name.json qapi-schema += enum-bad-prefix.json qapi-schema += enum-clash-member.json qapi-schema += enum-dict-member-unknown.json +qapi-schema += enum-if-invalid.json qapi-schema += enum-int-member.json qapi-schema += enum-member-case.json qapi-schema += enum-missing-data.json diff --git a/tests/qapi-schema/enum-dict-member-unknown.err b/tests/qapi-schema/enum-dict-member-unknown.err index 7ed48beb2e..3699c89167 100644 --- a/tests/qapi-schema/enum-dict-member-unknown.err +++ b/tests/qapi-schema/enum-dict-member-unknown.err @@ -1 +1 @@ -tests/qapi-schema/enum-dict-member-unknown.json:2: Dictionary member of enum 'MyEnum' has unknown key 'bad-key' (allowed: 'name') +tests/qapi-schema/enum-dict-member-unknown.json:2: Dictionary member of enum 'MyEnum' has unknown key 'bad-key' (allowed: 'if', 'name') diff --git a/tests/qapi-schema/enum-if-invalid.err b/tests/qapi-schema/enum-if-invalid.err new file mode 100644 index 00..54c3cf887b --- /dev/null +++ b/tests/qapi-schema/enum-if-invalid.err @@ -0,0 +1 @@ +tests/qapi-schema/enum-if-invalid.json:2: 'if' condition must be a string or a list of strings diff --git a/tests/qapi-schema/enum-if-invalid.exit b/tests/qapi-schema/enum-if-invalid.exit new file mode 100644 index 00..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/enum-if-invalid.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/enum-if-invalid.json b/tests/qapi-schema/enum-if-invalid.json new file mode 100644 index 00..60bd0ef1d7 --- /dev/null +++ b/tests/qapi-schema/enum-if-invalid.json @@ -0,0 +1,3 @@ +# check invalid 'if' type +{ 'enum': 'TestIfEnum', 'data': + [ 'foo', { 'name' : 'bar', 'if': { 'val': 'foo' } } ] } diff --git a/tests/qapi-schema/enum-if-invalid.out b/tests/qapi-schema/enum-if-invalid.out new file mode 100644 index 00..e69de29bb2 diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index b997b2d43d..6a1d3b6337 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -194,7 +194,8 @@ { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' }, 'if': 'd
[Qemu-devel] [PATCH v3 15/49] qapi: do not define enumeration value explicitely
The C standard has the initial value at 0 and the subsequent values incremented by 1. No need to set this explicitely. This will prevent from artificial "gaps" when compiling out some enum values and having unnecessarily large MAX values & enums arrays. Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py | 7 ++- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 60c1d0a783..68a567f53f 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -2032,14 +2032,11 @@ typedef enum %(c_name)s { ''', c_name=c_name(name)) -i = 0 for value in enum_values: ret += mcgen(''' -%(c_enum)s = %(i)d, +%(c_enum)s, ''', - c_enum=c_enum_const(name, value, prefix), - i=i) -i += 1 + c_enum=c_enum_const(name, value, prefix)) ret += mcgen(''' } %(c_name)s; -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 20/49] qapi: add a dictionnary form with 'name' key for enum members
Desugar the enum NAME form to { 'name': NAME }. This will allow to add new enum members, such as 'if' in the following patch. Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py| 49 --- tests/Makefile.include| 3 +- tests/qapi-schema/enum-bad-member.err | 1 + ...-dict-member.exit => enum-bad-member.exit} | 0 tests/qapi-schema/enum-bad-member.json| 2 + ...um-dict-member.out => enum-bad-member.out} | 0 .../qapi-schema/enum-dict-member-unknown.err | 1 + .../qapi-schema/enum-dict-member-unknown.exit | 1 + .../qapi-schema/enum-dict-member-unknown.json | 2 + .../qapi-schema/enum-dict-member-unknown.out | 0 tests/qapi-schema/enum-dict-member.err| 1 - tests/qapi-schema/enum-dict-member.json | 2 - tests/qapi-schema/enum-missing-data.err | 2 +- 13 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 tests/qapi-schema/enum-bad-member.err rename tests/qapi-schema/{enum-dict-member.exit => enum-bad-member.exit} (100%) create mode 100644 tests/qapi-schema/enum-bad-member.json rename tests/qapi-schema/{enum-dict-member.out => enum-bad-member.out} (100%) create mode 100644 tests/qapi-schema/enum-dict-member-unknown.err create mode 100644 tests/qapi-schema/enum-dict-member-unknown.exit create mode 100644 tests/qapi-schema/enum-dict-member-unknown.json create mode 100644 tests/qapi-schema/enum-dict-member-unknown.out delete mode 100644 tests/qapi-schema/enum-dict-member.err delete mode 100644 tests/qapi-schema/enum-dict-member.json diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index fdbb5f1823..6aece364f1 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -739,6 +739,10 @@ def check_event(expr, info): allow_metas=meta) +def enum_get_names(expr): +return [e['name'] for e in expr['data']] + + def check_union(expr, info): name = expr['union'] base = expr.get('base') @@ -798,7 +802,7 @@ def check_union(expr, info): # If the discriminator names an enum type, then all members # of 'data' must also be members of the enum type. if enum_define: -if key not in enum_define['data']: +if key not in enum_get_names(enum_define): raise QAPISemError(info, "Discriminator value '%s' is not found in " "enum '%s'" @@ -806,7 +810,7 @@ def check_union(expr, info): # If discriminator is user-defined, ensure all values are covered if enum_define: -for value in enum_define['data']: +for value in enum_get_names(enum_define): if value not in members.keys(): raise QAPISemError(info, "Union '%s' data missing '%s' branch" % (name, value)) @@ -837,10 +841,10 @@ def check_alternate(expr, info): if qtype == 'QTYPE_QSTRING': enum_expr = enum_types.get(value) if enum_expr: -for v in enum_expr['data']: +for v in enum_get_names(enum_expr): if v in ['on', 'off']: conflicting.add('QTYPE_QBOOL') -if re.match(r'[-+0-9.]', v): # lazy, could be tightened +if re.match(r'[-+0-9.]', v): # lazy, could be tightened conflicting.add('QTYPE_QNUM') else: conflicting.add('QTYPE_QNUM') @@ -853,19 +857,34 @@ def check_alternate(expr, info): types_seen[qt] = key -def check_enum(expr, info): +def normalize_enum(expr, info): name = expr['enum'] members = expr.get('data') -prefix = expr.get('prefix') if not isinstance(members, list): raise QAPISemError(info, "Enum '%s' requires an array for 'data'" % name) + +# translate short member form to dict form +for i, member in enumerate(members): +if not isinstance(member, dict): +member = {'name': member} +members[i] = member + + +def check_enum(expr, info): +name = expr['enum'] +members = expr.get('data') +prefix = expr.get('prefix') + if prefix is not None and not isinstance(prefix, str): raise QAPISemError(info, "Enum '%s' requires a string for 'prefix'" % name) + for member in members: -check_name(info, "Member of enum '%s'" % name, member, +source = "Dictionary member of enum '%s'" % name +check_known_keys(info, source, member, ['name'], []) +check_name(info, "Member of enum '%s'" % name, member['name'], enum_member=True) @@ -926,6 +945,13 @@ def check_exprs(exprs): for builtin in builtin_types.keys(): all_names[builtin] = 'built-in' +# Normalize exprs +for expr_elem in exprs: +expr = expr_elem['expr'] +info =
[Qemu-devel] [PATCH v3 26/49] qapi: add an error in case a discriminator is conditionnal
Making a discriminator conditonal doesn't make much sense. Instead, the union could be made conditional. Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py | 11 +-- tests/Makefile.include | 1 + .../flat-union-invalid-if-discriminator.err | 1 + .../flat-union-invalid-if-discriminator.exit| 1 + .../flat-union-invalid-if-discriminator.json| 17 + .../flat-union-invalid-if-discriminator.out | 0 6 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 tests/qapi-schema/flat-union-invalid-if-discriminator.err create mode 100644 tests/qapi-schema/flat-union-invalid-if-discriminator.exit create mode 100644 tests/qapi-schema/flat-union-invalid-if-discriminator.json create mode 100644 tests/qapi-schema/flat-union-invalid-if-discriminator.out diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index bbcb417a47..d75dfbf97a 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -576,7 +576,8 @@ def find_alternate_member_qtype(qapi_type): # Return the discriminator enum define if discriminator is specified as an # enum type, otherwise return None. -def discriminator_find_enum_define(expr): +def discriminator_find_enum_define(expr, info): +name = expr['union'] base = expr.get('base') discriminator = expr.get('discriminator') @@ -591,6 +592,11 @@ def discriminator_find_enum_define(expr): if not discriminator_member: return None +if discriminator_member.get('if'): +raise QAPISemError(info, 'The discriminator %s.%s for union %s ' + 'must not be conditional' % + (base, discriminator, name)) + return enum_types.get(discriminator_member['type']) @@ -1024,7 +1030,8 @@ def check_exprs(exprs): if 'include' in expr: continue -if 'union' in expr and not discriminator_find_enum_define(expr): +info = expr_elem['info'] +if 'union' in expr and not discriminator_find_enum_define(expr, info): name = '%sKind' % expr['union'] elif 'alternate' in expr: name = '%sKind' % expr['alternate'] diff --git a/tests/Makefile.include b/tests/Makefile.include index 7a46c1620d..e7429de9df 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -505,6 +505,7 @@ qapi-schema += flat-union-inline.json qapi-schema += flat-union-int-branch.json qapi-schema += flat-union-invalid-branch-key.json qapi-schema += flat-union-invalid-discriminator.json +qapi-schema += flat-union-invalid-if-discriminator.json qapi-schema += flat-union-no-base.json qapi-schema += flat-union-optional-discriminator.json qapi-schema += flat-union-string-discriminator.json diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.err b/tests/qapi-schema/flat-union-invalid-if-discriminator.err new file mode 100644 index 00..0c94c9860d --- /dev/null +++ b/tests/qapi-schema/flat-union-invalid-if-discriminator.err @@ -0,0 +1 @@ +tests/qapi-schema/flat-union-invalid-if-discriminator.json:13: The discriminator TestBase.enum1 for union TestUnion must not be conditional diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.exit b/tests/qapi-schema/flat-union-invalid-if-discriminator.exit new file mode 100644 index 00..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/flat-union-invalid-if-discriminator.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.json b/tests/qapi-schema/flat-union-invalid-if-discriminator.json new file mode 100644 index 00..618ec36396 --- /dev/null +++ b/tests/qapi-schema/flat-union-invalid-if-discriminator.json @@ -0,0 +1,17 @@ +{ 'enum': 'TestEnum', + 'data': [ 'value1', 'value2' ] } + +{ 'struct': 'TestBase', + 'data': { 'enum1': { 'type': 'TestEnum', 'if': 'FOO' } } } + +{ 'struct': 'TestTypeA', + 'data': { 'string': 'str' } } + +{ 'struct': 'TestTypeB', + 'data': { 'integer': 'int' } } + +{ 'union': 'TestUnion', + 'base': 'TestBase', + 'discriminator': 'enum1', + 'data': { 'value1': 'TestTypeA', +'value2': 'TestTypeB' } } diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.out b/tests/qapi-schema/flat-union-invalid-if-discriminator.out new file mode 100644 index 00..e69de29bb2 -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 27/49] qapi: add 'if' on union members
Add 'if' key to union members: { 'union': 'TestIfUnion', 'data': 'mem': { 'type': 'str', 'if': 'COND'} } Generated code is not changed by this patch but with "qapi: add #if conditions to generated code". Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py | 17 + tests/qapi-schema/qapi-schema-test.json | 7 ++- tests/qapi-schema/qapi-schema-test.out | 10 ++ tests/qapi-schema/test-qapi.py | 1 + 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index d75dfbf97a..224e911085 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -811,7 +811,7 @@ def check_union(expr, info): for (key, value) in members.items(): source = "Member of union '%s'" % name check_name(info, source, key) -check_known_keys(info, source, value, ['type'], []) +check_known_keys(info, source, value, ['type'], ['if']) typ = value['type'] # Each value must name a known type @@ -1492,8 +1492,8 @@ class QAPISchemaObjectTypeVariants(object): class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember): role = 'branch' -def __init__(self, name, typ): -QAPISchemaObjectTypeMember.__init__(self, name, typ, False) +def __init__(self, name, typ, ifcond=None): +QAPISchemaObjectTypeMember.__init__(self, name, typ, False, ifcond) class QAPISchemaAlternateType(QAPISchemaType): @@ -1767,14 +1767,14 @@ class QAPISchema(object): def _make_variant(self, case, typ): return QAPISchemaObjectTypeVariant(case, typ) -def _make_simple_variant(self, case, typ, info): +def _make_simple_variant(self, case, typ, ifcond, info): if isinstance(typ, list): assert len(typ) == 1 typ = self._make_array_type(typ[0], info) typ = self._make_implicit_object_type( typ, info, None, self.lookup_type(typ), 'wrapper', [self._make_member('data', typ, None, info)]) -return QAPISchemaObjectTypeVariant(case, typ) +return QAPISchemaObjectTypeVariant(case, typ, ifcond) def _def_union_type(self, expr, info, doc): name = expr['union'] @@ -1792,10 +1792,11 @@ class QAPISchema(object): for (key, value) in data.items()] members = [] else: -variants = [self._make_simple_variant(key, value['type'], info) +variants = [self._make_simple_variant(key, value['type'], + value.get('if'), info) for (key, value) in data.items()] -typ = self._make_implicit_enum_type(name, info, ifcond, -[v.name for v in variants]) +enum = [{'name': v.name, 'if': v.ifcond} for v in variants] +typ = self._make_implicit_enum_type(name, info, ifcond, enum) tag_member = QAPISchemaObjectTypeMember('type', typ, False) members = [tag_member] self._def_entity( diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index e29c9f0769..b4b8a0a2cc 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -200,9 +200,14 @@ [ 'foo', { 'name' : 'bar', 'if': 'defined(TEST_IF_ENUM_BAR)' } ], 'if': 'defined(TEST_IF_ENUM)' } -{ 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' }, +{ 'union': 'TestIfUnion', 'data': + { 'foo': 'TestStruct', +'union_bar': { 'type': 'str', 'if': 'defined(TEST_IF_UNION_BAR)'} }, 'if': 'defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)' } +{ 'command': 'TestIfUnionCmd', 'data': { 'union_cmd_arg': 'TestIfUnion' }, + 'if': 'defined(TEST_IF_UNION)' } + { 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' }, 'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index e1e41acd52..8dbcd6f24b 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -272,12 +272,22 @@ object q_obj_TestStruct-wrapper member data: TestStruct optional=False enum TestIfUnionKind member foo +member union_bar +if ['defined(TEST_IF_UNION_BAR)'] if ['defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)'] object TestIfUnion member type: TestIfUnionKind optional=False tag type case foo: q_obj_TestStruct-wrapper +case union_bar: q_obj_str-wrapper +if ['defined(TEST_IF_UNION_BAR)'] if ['defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)'] +object q_obj_TestIfUnionCmd-arg +member union_cmd_arg: TestIfUnion optional=False +if ['defined(TEST_IF_UNION)'] +command TestIfUnionCmd q_obj_TestIfUnionCmd-arg -> None + gen=True success_response=True boxed=False +if ['defined(TEST_IF_UNION)'] al
[Qemu-devel] [PATCH v3 16/49] qapi: rename QAPISchemaEnumType.values to .members
Rename QAPISchemaEnumType.values and related variables to members. Makes sense ever since commit 93bda4dd4 changed .values from list of string to list of QAPISchemaMember. Obvious no-op. Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py | 36 +- scripts/qapi/doc.py| 2 +- scripts/qapi/introspect.py | 4 ++-- scripts/qapi/types.py | 6 +++--- scripts/qapi/visit.py | 2 +- tests/qapi-schema/test-qapi.py | 4 ++-- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 68a567f53f..ea5cdfe3be 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -1068,7 +1068,7 @@ class QAPISchemaVisitor(object): def visit_builtin_type(self, name, info, json_type): pass -def visit_enum_type(self, name, info, ifcond, values, prefix): +def visit_enum_type(self, name, info, ifcond, members, prefix): pass def visit_array_type(self, name, info, ifcond, element_type): @@ -1166,22 +1166,22 @@ class QAPISchemaBuiltinType(QAPISchemaType): class QAPISchemaEnumType(QAPISchemaType): -def __init__(self, name, info, doc, ifcond, values, prefix): +def __init__(self, name, info, doc, ifcond, members, prefix): QAPISchemaType.__init__(self, name, info, doc, ifcond) -for v in values: -assert isinstance(v, QAPISchemaMember) -v.set_owner(name) +for m in members: +assert isinstance(m, QAPISchemaMember) +m.set_owner(name) assert prefix is None or isinstance(prefix, str) -self.values = values +self.members = members self.prefix = prefix def check(self, schema): QAPISchemaType.check(self, schema) seen = {} -for v in self.values: -v.check_clash(self.info, seen) +for m in self.members: +m.check_clash(self.info, seen) if self.doc: -self.doc.connect_member(v) +self.doc.connect_member(m) def is_implicit(self): # See QAPISchema._make_implicit_enum_type() and ._def_predefineds() @@ -1191,7 +1191,7 @@ class QAPISchemaEnumType(QAPISchemaType): return c_name(self.name) def member_names(self): -return [v.name for v in self.values] +return [m.name for m in self.members] def json_type(self): return 'string' @@ -1999,19 +1999,19 @@ def wrap_ifcond(ifcond, before, after): return out -def gen_enum_lookup(name, values, prefix=None): +def gen_enum_lookup(name, members, prefix=None): ret = mcgen(''' const QEnumLookup %(c_name)s_lookup = { .array = (const char *const[]) { ''', c_name=c_name(name)) -for value in values: -index = c_enum_const(name, value, prefix) +for m in members: +index = c_enum_const(name, m, prefix) ret += mcgen(''' [%(index)s] = "%(value)s", ''', - index=index, value=value) + index=index, value=m) ret += mcgen(''' }, @@ -2022,9 +2022,9 @@ const QEnumLookup %(c_name)s_lookup = { return ret -def gen_enum(name, values, prefix=None): +def gen_enum(name, members, prefix=None): # append automatically generated _MAX value -enum_values = values + ['_MAX'] +enum_members = members + ['_MAX'] ret = mcgen(''' @@ -2032,11 +2032,11 @@ typedef enum %(c_name)s { ''', c_name=c_name(name)) -for value in enum_values: +for m in enum_members: ret += mcgen(''' %(c_enum)s, ''', - c_enum=c_enum_const(name, value, prefix)) + c_enum=c_enum_const(name, m, prefix)) ret += mcgen(''' } %(c_name)s; diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py index d5cfd2336b..6c2bf98e1d 100755 --- a/scripts/qapi/doc.py +++ b/scripts/qapi/doc.py @@ -204,7 +204,7 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor): def write(self, output_dir): self._gen.write(output_dir, self._prefix + 'qapi-doc.texi') -def visit_enum_type(self, name, info, ifcond, values, prefix): +def visit_enum_type(self, name, info, ifcond, members, prefix): doc = self.cur_doc self._gen.add(TYPE_FMT(type='Enum', name=doc.symbol, diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py index cb4825f134..66f7fd00a9 100644 --- a/scripts/qapi/introspect.py +++ b/scripts/qapi/introspect.py @@ -163,8 +163,8 @@ const QLitObject %(c_name)s = %(c_string)s; def visit_builtin_type(self, name, info, json_type): self._gen_qlit(name, 'builtin', {'json-type': json_type}, []) -def visit_enum_type(self, name, info, ifcond, values, prefix): -self._gen_qlit(name, 'enum', {'values': values}, ifcond) +def visit_enum_type(self, name, info, ifcond, members, prefix): +
[Qemu-devel] [PATCH v3 25/49] qapi: add 'if' to implicit struct members
Generated code is not changed by this patch, but with "qapi: add #if conditions to generated code" patch. Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py | 14 +++--- tests/qapi-schema/qapi-schema-test.json | 12 +--- tests/qapi-schema/qapi-schema-test.out | 5 + 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 3f46ed5530..bbcb417a47 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -713,7 +713,7 @@ def check_type(info, source, value, allow_array=False, # Todo: allow dictionaries to represent default values of # an optional argument. member_source = "Member '%s' of %s" % (key, source) -check_known_keys(info, member_source, arg, ['type'], []) +check_known_keys(info, member_source, arg, ['type'], ['if']) check_type(info, member_source, arg['type'], allow_array=True, allow_metas=['built-in', 'union', 'alternate', 'struct', 'enum']) @@ -1426,8 +1426,8 @@ class QAPISchemaMember(object): class QAPISchemaObjectTypeMember(QAPISchemaMember): -def __init__(self, name, typ, optional): -QAPISchemaMember.__init__(self, name) +def __init__(self, name, typ, optional, ifcond=None): +QAPISchemaMember.__init__(self, name, ifcond) assert isinstance(typ, str) assert isinstance(optional, bool) self._type_name = typ @@ -1734,7 +1734,7 @@ class QAPISchema(object): name, info, doc, ifcond, self._make_enum_members(data), prefix)) -def _make_member(self, name, typ, info): +def _make_member(self, name, typ, ifcond, info): optional = False if name.startswith('*'): name = name[1:] @@ -1742,10 +1742,10 @@ class QAPISchema(object): if isinstance(typ, list): assert len(typ) == 1 typ = self._make_array_type(typ[0], info) -return QAPISchemaObjectTypeMember(name, typ, optional) +return QAPISchemaObjectTypeMember(name, typ, optional, ifcond) def _make_members(self, data, info): -return [self._make_member(key, value['type'], info) +return [self._make_member(key, value['type'], value.get('if'), info) for (key, value) in data.items()] def _def_struct_type(self, expr, info, doc): @@ -1766,7 +1766,7 @@ class QAPISchema(object): typ = self._make_array_type(typ[0], info) typ = self._make_implicit_object_type( typ, info, None, self.lookup_type(typ), -'wrapper', [self._make_member('data', typ, info)]) +'wrapper', [self._make_member('data', typ, None, info)]) return QAPISchemaObjectTypeVariant(case, typ) def _def_union_type(self, expr, info, doc): diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 71023fb277..e29c9f0769 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -191,7 +191,9 @@ # test 'if' condition handling -{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' }, +{ 'struct': 'TestIfStruct', 'data': + { 'foo': 'int', +'bar': { 'type': 'int', 'if': 'defined(TEST_IF_STRUCT_BAR)'} }, 'if': 'defined(TEST_IF_STRUCT)' } { 'enum': 'TestIfEnum', 'data': @@ -204,8 +206,12 @@ { 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' }, 'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' } -{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct', 'bar': 'TestIfEnum' }, +{ 'command': 'TestIfCmd', 'data': + { 'foo': 'TestIfStruct', +'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_CMD_BAR)' } }, 'if': ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)'] } -{ 'event': 'TestIfEvent', 'data': { 'foo': 'TestIfStruct' }, +{ 'event': 'TestIfEvent', 'data': + { 'foo': 'TestIfStruct', +'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_EVT_BAR)' } }, 'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index bcef80efeb..e1e41acd52 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -260,6 +260,8 @@ command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Unio gen=True success_response=True boxed=False object TestIfStruct member foo: int optional=False +member bar: int optional=False +if ['defined(TEST_IF_STRUCT_BAR)'] if ['defined(TEST_IF_STRUCT)'] enum TestIfEnum member foo @@ -284,12 +286,15 @@ alternate TestIfAlternate object q_obj_TestIfCmd-arg member foo: TestIfStruct optional=False member bar: TestIfEnum optional=False +if ['defined(TEST_IF_CMD_BAR)'] if ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)'] command TestIfCmd q_obj_Te
[Qemu-devel] [PATCH v3 32/49] qapi2texi: add 'If:' condition to enum values
Signed-off-by: Marc-André Lureau --- scripts/qapi/doc.py | 5 - tests/qapi-schema/doc-good.json | 4 +++- tests/qapi-schema/doc-good.out | 1 + tests/qapi-schema/doc-good.texi | 2 ++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py index 783b13303a..f629425f53 100755 --- a/scripts/qapi/doc.py +++ b/scripts/qapi/doc.py @@ -128,7 +128,10 @@ def texi_body(doc): def texi_enum_value(value): """Format a table of members item for an enumeration value""" -return '@item @code{%s}\n' % value.name +return '@item @code{%s}%s\n' % ( +value.name, +'\n@b{If:} @code{%s}\n' % +', '.join(value.ifcond) if value.ifcond else '') def texi_member(member, suffix=''): diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json index 984cd8ed06..c7fe08c530 100644 --- a/tests/qapi-schema/doc-good.json +++ b/tests/qapi-schema/doc-good.json @@ -55,7 +55,9 @@ # # @two is undocumented ## -{ 'enum': 'Enum', 'data': [ 'one', 'two' ], 'if': 'defined(IFCOND)' } +{ 'enum': 'Enum', 'data': + [ { 'name': 'one', 'if': 'defined(IFENUM)' }, 'two' ], + 'if': 'defined(IFCOND)' } ## # @Base: diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out index e4054e293c..d27d345de2 100644 --- a/tests/qapi-schema/doc-good.out +++ b/tests/qapi-schema/doc-good.out @@ -11,6 +11,7 @@ enum QType module doc-good.json enum Enum member one +if ['defined(IFENUM)'] member two if ['defined(IFCOND)'] object Base diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi index e42eace474..2446a1c702 100644 --- a/tests/qapi-schema/doc-good.texi +++ b/tests/qapi-schema/doc-good.texi @@ -83,6 +83,8 @@ Examples: @b{Values:} @table @asis @item @code{one} +@b{If:} @code{defined(IFENUM)} + The @emph{one} @{and only@} @item @code{two} Not documented -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 28/49] qapi: add 'if' to alternate members
Add 'if' key to alternate members: { 'alternate': 'TestIfAlternate', 'data': { 'alt': { 'type': 'TestStruct', 'if': 'COND' } } } Generated code is not changed by this patch but with "qapi: add #if conditions to generated code". Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py | 10 +- tests/qapi-schema/qapi-schema-test.json | 6 +- tests/qapi-schema/qapi-schema-test.out | 9 - 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 224e911085..c913c18d2d 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -848,7 +848,7 @@ def check_alternate(expr, info): for (key, value) in members.items(): check_name(info, "Member of alternate '%s'" % name, key) source = "Member '%s' of alternate '%s'" % (key, name) -check_known_keys(info, source, value, ['type'], []) +check_known_keys(info, source, value, ['type'], ['if']) typ = value['type'] # Ensure alternates have no type conflicts. @@ -1764,8 +1764,8 @@ class QAPISchema(object): self._make_members(data, info), None)) -def _make_variant(self, case, typ): -return QAPISchemaObjectTypeVariant(case, typ) +def _make_variant(self, case, typ, ifcond): +return QAPISchemaObjectTypeVariant(case, typ, ifcond) def _make_simple_variant(self, case, typ, ifcond, info): if isinstance(typ, list): @@ -1788,7 +1788,7 @@ class QAPISchema(object): name, info, doc, ifcond, 'base', self._make_members(base, info)) if tag_name: -variants = [self._make_variant(key, value['type']) +variants = [self._make_variant(key, value['type'], value.get('if')) for (key, value) in data.items()] members = [] else: @@ -1809,7 +1809,7 @@ class QAPISchema(object): name = expr['alternate'] data = expr['data'] ifcond = expr.get('if') -variants = [self._make_variant(key, value['type']) +variants = [self._make_variant(key, value['type'], value.get('if')) for (key, value) in data.items()] tag_member = QAPISchemaObjectTypeMember('type', 'QType', False) self._def_entity( diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index b4b8a0a2cc..cd33c084cb 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -208,9 +208,13 @@ { 'command': 'TestIfUnionCmd', 'data': { 'union_cmd_arg': 'TestIfUnion' }, 'if': 'defined(TEST_IF_UNION)' } -{ 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' }, +{ 'alternate': 'TestIfAlternate', 'data': + { 'foo': 'int', 'alt_bar': { 'type': 'TestStruct', 'if': 'defined(TEST_IF_ALT_BAR)'} }, 'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' } +{ 'command': 'TestIfAlternateCmd', 'data': { 'alt_cmd_arg': 'TestIfAlternate' }, + 'if': 'defined(TEST_IF_ALT)' } + { 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct', 'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_CMD_BAR)' } }, diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 8dbcd6f24b..657e487cbf 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -291,8 +291,15 @@ command TestIfUnionCmd q_obj_TestIfUnionCmd-arg -> None alternate TestIfAlternate tag type case foo: int -case bar: TestStruct +case alt_bar: TestStruct +if ['defined(TEST_IF_ALT_BAR)'] if ['defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)'] +object q_obj_TestIfAlternateCmd-arg +member alt_cmd_arg: TestIfAlternate optional=False +if ['defined(TEST_IF_ALT)'] +command TestIfAlternateCmd q_obj_TestIfAlternateCmd-arg -> None + gen=True success_response=True boxed=False +if ['defined(TEST_IF_ALT)'] object q_obj_TestIfCmd-arg member foo: TestIfStruct optional=False member bar: TestIfEnum optional=False -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 22/49] qapi-event: add 'if' condition to implicit event enum
Add condition to QAPIEvent enum members based on the event 'if'. Generated code is not changed by this patch, but with "qapi: add #if conditions to generated code" patch. There is no coverage of this change in qapi-schema-test.out since the event_names enum is an implicit type created by qapi-event.py. Signed-off-by: Marc-André Lureau --- scripts/qapi/events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py index 233c27a6c8..f02b65cf5a 100644 --- a/scripts/qapi/events.py +++ b/scripts/qapi/events.py @@ -188,7 +188,7 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor): with ifcontext(ifcond, self._genh, self._genc): self._genh.add(gen_event_send_decl(name, arg_type, boxed)) self._genc.add(gen_event_send(name, arg_type, boxed, self._enum_name)) -self._event_names.append(QAPISchemaMember(name)) +self._event_names.append(QAPISchemaMember(name, ifcond)) def gen_events(schema, output_dir, prefix): -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 43/49] qapi: make s390 commands depend on TARGET_S390X
Signed-off-by: Marc-André Lureau Acked-by: Cornelia Huck --- qapi/misc.json | 101 -- qapi/target.json| 106 include/sysemu/arch_init.h | 7 -- hw/s390x/s390-skeys.c | 2 +- monitor.c | 14 qmp.c | 14 stubs/arch-query-cpu-model-baseline.c | 13 --- stubs/arch-query-cpu-model-comparison.c | 13 --- target/s390x/cpu_models.c | 5 +- stubs/Makefile.objs | 2 - 10 files changed, 110 insertions(+), 167 deletions(-) delete mode 100644 stubs/arch-query-cpu-model-baseline.c delete mode 100644 stubs/arch-query-cpu-model-comparison.c diff --git a/qapi/misc.json b/qapi/misc.json index 690eeda41f..1753a81b1e 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -1821,27 +1821,6 @@ { 'command': 'query-dump-guest-memory-capability', 'returns': 'DumpGuestMemoryCapability' } -## -# @dump-skeys: -# -# Dump guest's storage keys -# -# @filename: the path to the file to dump to -# -# This command is only supported on s390 architecture. -# -# Since: 2.5 -# -# Example: -# -# -> { "execute": "dump-skeys", -# "arguments": { "filename": "/tmp/skeys" } } -# <- { "return": {} } -# -## -{ 'command': 'dump-skeys', - 'data': { 'filename': 'str' } } - ## # @object-add: # @@ -2208,46 +2187,6 @@ } } -## -# @query-cpu-model-comparison: -# -# Compares two CPU models, returning how they compare in a specific -# configuration. The results indicates how both models compare regarding -# runnability. This result can be used by tooling to make decisions if a -# certain CPU model will run in a certain configuration or if a compatible -# CPU model has to be created by baselining. -# -# Usually, a CPU model is compared against the maximum possible CPU model -# of a certain configuration (e.g. the "host" model for KVM). If that CPU -# model is identical or a subset, it will run in that configuration. -# -# The result returned by this command may be affected by: -# -# * QEMU version: CPU models may look different depending on the QEMU version. -# (Except for CPU models reported as "static" in query-cpu-definitions.) -# * machine-type: CPU model may look different depending on the machine-type. -# (Except for CPU models reported as "static" in query-cpu-definitions.) -# * machine options (including accelerator): in some architectures, CPU models -# may look different depending on machine and accelerator options. (Except for -# CPU models reported as "static" in query-cpu-definitions.) -# * "-cpu" arguments and global properties: arguments to the -cpu option and -# global properties may affect expansion of CPU models. Using -# query-cpu-model-expansion while using these is not advised. -# -# Some architectures may not support comparing CPU models. s390x supports -# comparing CPU models. -# -# Returns: a CpuModelBaselineInfo. Returns an error if comparing CPU models is -# not supported, if a model cannot be used, if a model contains -# an unknown cpu definition name, unknown properties or properties -# with wrong types. -# -# Since: 2.8.0 -## -{ 'command': 'query-cpu-model-comparison', - 'data': { 'modela': 'CpuModelInfo', 'modelb': 'CpuModelInfo' }, - 'returns': 'CpuModelCompareInfo' } - ## # @CpuModelBaselineInfo: # @@ -2260,46 +2199,6 @@ { 'struct': 'CpuModelBaselineInfo', 'data': { 'model': 'CpuModelInfo' } } -## -# @query-cpu-model-baseline: -# -# Baseline two CPU models, creating a compatible third model. The created -# model will always be a static, migration-safe CPU model (see "static" -# CPU model expansion for details). -# -# This interface can be used by tooling to create a compatible CPU model out -# two CPU models. The created CPU model will be identical to or a subset of -# both CPU models when comparing them. Therefore, the created CPU model is -# guaranteed to run where the given CPU models run. -# -# The result returned by this command may be affected by: -# -# * QEMU version: CPU models may look different depending on the QEMU version. -# (Except for CPU models reported as "static" in query-cpu-definitions.) -# * machine-type: CPU model may look different depending on the machine-type. -# (Except for CPU models reported as "static" in query-cpu-definitions.) -# * machine options (including accelerator): in some architectures, CPU models -# may look different depending on machine and accelerator options. (Except for -# CPU models reported as "static" in query-cpu-definitions.) -# * "-cpu" arguments and global properties: arguments to the -cpu option and -# global properties may affect expansion of CPU models. Using -# query-cpu-model-expansion while using these is not advised. -# -# Some architectures may not support baselining CPU models. s390x supports -# baselining CPU models. -# -# Returns: a C
[Qemu-devel] [PATCH v3 24/49] qapi: add a dictionary form with 'type' key for members
Wherever a struct/union/alternate/command/event member with NAME: TYPE form is accepted, desugar it to a NAME: { 'type': TYPE } form. This will allow to add new member details, such as 'if' in the following patch to introduce conditionals, or 'default' for default values etc. Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py| 57 --- tests/Makefile.include| 3 + tests/qapi-schema/alternate-invalid-dict.err | 1 + tests/qapi-schema/alternate-invalid-dict.exit | 1 + tests/qapi-schema/alternate-invalid-dict.json | 4 ++ tests/qapi-schema/alternate-invalid-dict.out | 0 tests/qapi-schema/event-nest-struct.err | 2 +- tests/qapi-schema/flat-union-inline.err | 2 +- tests/qapi-schema/nested-struct-data.err | 2 +- tests/qapi-schema/qapi-schema-test.json | 10 ++-- .../struct-member-invalid-dict.err| 1 + .../struct-member-invalid-dict.exit | 1 + .../struct-member-invalid-dict.json | 3 + .../struct-member-invalid-dict.out| 0 .../qapi-schema/union-branch-invalid-dict.err | 1 + .../union-branch-invalid-dict.exit| 1 + .../union-branch-invalid-dict.json| 4 ++ .../qapi-schema/union-branch-invalid-dict.out | 0 18 files changed, 66 insertions(+), 27 deletions(-) create mode 100644 tests/qapi-schema/alternate-invalid-dict.err create mode 100644 tests/qapi-schema/alternate-invalid-dict.exit create mode 100644 tests/qapi-schema/alternate-invalid-dict.json create mode 100644 tests/qapi-schema/alternate-invalid-dict.out create mode 100644 tests/qapi-schema/struct-member-invalid-dict.err create mode 100644 tests/qapi-schema/struct-member-invalid-dict.exit create mode 100644 tests/qapi-schema/struct-member-invalid-dict.json create mode 100644 tests/qapi-schema/struct-member-invalid-dict.out create mode 100644 tests/qapi-schema/union-branch-invalid-dict.err create mode 100644 tests/qapi-schema/union-branch-invalid-dict.exit create mode 100644 tests/qapi-schema/union-branch-invalid-dict.json create mode 100644 tests/qapi-schema/union-branch-invalid-dict.out diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 9eb2b0cc37..3f46ed5530 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -587,11 +587,11 @@ def discriminator_find_enum_define(expr): if not base_members: return None -discriminator_type = base_members.get(discriminator) -if not discriminator_type: +discriminator_member = base_members.get(discriminator) +if not discriminator_member: return None -return enum_types.get(discriminator_type) +return enum_types.get(discriminator_member['type']) # Names must be letters, numbers, -, and _. They must start with letter, @@ -659,6 +659,15 @@ def check_if(expr, info): check_if_str(ifcond, info) +def normalize_members(expr, field): +members = expr.get(field) +if isinstance(members, OrderedDict): +for key, arg in members.items(): +if isinstance(arg, dict): +continue +members[key] = {'type': arg} + + def check_type(info, source, value, allow_array=False, allow_implicit=False, allow_optional=False, allow_metas=[]): @@ -703,8 +712,9 @@ def check_type(info, source, value, allow_array=False, % (source, key)) # Todo: allow dictionaries to represent default values of # an optional argument. -check_type(info, "Member '%s' of %s" % (key, source), arg, - allow_array=True, +member_source = "Member '%s' of %s" % (key, source) +check_known_keys(info, member_source, arg, ['type'], []) +check_type(info, member_source, arg['type'], allow_array=True, allow_metas=['built-in', 'union', 'alternate', 'struct', 'enum']) @@ -775,13 +785,13 @@ def check_union(expr, info): # member of the base struct. check_name(info, "Discriminator of flat union '%s'" % name, discriminator) -discriminator_type = base_members.get(discriminator) -if not discriminator_type: +discriminator_member = base_members.get(discriminator) +if not discriminator_member: raise QAPISemError(info, "Discriminator '%s' is not a member of base " "struct '%s'" % (discriminator, base)) -enum_define = enum_types.get(discriminator_type) +enum_define = enum_types.get(discriminator_member['type']) allow_metas = ['struct'] # Do not allow string discriminator if not enum_define: @@ -793,11 +803,14 @@ def check_union(expr, info): if len(members) == 0: raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name) for (k
Re: [Qemu-devel] [PATCH v2 0/4] tpm: Fix initialization of a few flags of CRB interface
On 03/21/2018 06:35 AM, Marc-André Lureau wrote: Hi On Tue, Mar 20, 2018 at 9:52 PM, Stefan Berger wrote: Fix the initialization of a few flags of the CRB interface. I tested the changes with UEFI and it works fine. SeaBIOS needs to have the latest patches applied. Stefan Stefan Berger (4): tpm: CRB: Set tpmRegValidSts flag to '1' in device reset tpm: CRB: set registers to 0 by default tpm: CRB: reset locAssigned upon relinquishing locality tpm: CRB: query backend for TPM established flag hw/tpm/tpm_crb.c | 14 -- 1 file changed, 12 insertions(+), 2 deletions(-) Series: Reviewed-by: Marc-André Lureau For 2.12? Ideally, yes. thanks
[Qemu-devel] [PATCH v3 31/49] qapi2texi: add 'If:' section to generated documentation
The documentation is generated only once, and doesn't know C pre-conditions. Add 'If:' sections for top-level entities. Signed-off-by: Marc-André Lureau --- scripts/qapi/doc.py | 22 -- tests/qapi-schema/doc-good.json | 2 +- tests/qapi-schema/doc-good.out | 1 + tests/qapi-schema/doc-good.texi | 2 ++ 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py index 6c2bf98e1d..783b13303a 100755 --- a/scripts/qapi/doc.py +++ b/scripts/qapi/doc.py @@ -174,7 +174,7 @@ def texi_members(doc, what, base, variants, member_func): return '\n@b{%s:}\n@table @asis\n%s@end table\n' % (what, items) -def texi_sections(doc): +def texi_sections(doc, ifcond): """Format additional sections following arguments""" body = '' for section in doc.sections: @@ -185,14 +185,16 @@ def texi_sections(doc): body += texi_example(section.text) else: body += texi_format(section.text) +if ifcond: +body += '\n\n@b{If:} @code{%s}' % ", ".join(ifcond) return body -def texi_entity(doc, what, base=None, variants=None, +def texi_entity(doc, what, ifcond, base=None, variants=None, member_func=texi_member): return (texi_body(doc) + texi_members(doc, what, base, variants, member_func) -+ texi_sections(doc)) ++ texi_sections(doc, ifcond)) class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor): @@ -208,7 +210,7 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor): doc = self.cur_doc self._gen.add(TYPE_FMT(type='Enum', name=doc.symbol, - body=texi_entity(doc, 'Values', + body=texi_entity(doc, 'Values', ifcond, member_func=texi_enum_value))) def visit_object_type(self, name, info, ifcond, base, members, variants): @@ -217,14 +219,14 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor): base = None self._gen.add(TYPE_FMT(type='Object', name=doc.symbol, - body=texi_entity(doc, 'Members', + body=texi_entity(doc, 'Members', ifcond, base, variants))) def visit_alternate_type(self, name, info, ifcond, variants): doc = self.cur_doc self._gen.add(TYPE_FMT(type='Alternate', name=doc.symbol, - body=texi_entity(doc, 'Members'))) + body=texi_entity(doc, 'Members', ifcond))) def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob): @@ -233,9 +235,9 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor): body = texi_body(doc) body += ('\n@b{Arguments:} the members of @code{%s}\n' % arg_type.name) -body += texi_sections(doc) +body += texi_sections(doc, ifcond) else: -body = texi_entity(doc, 'Arguments') +body = texi_entity(doc, 'Arguments', ifcond) self._gen.add(MSG_FMT(type='Command', name=doc.symbol, body=body)) @@ -244,7 +246,7 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor): doc = self.cur_doc self._gen.add(MSG_FMT(type='Event', name=doc.symbol, - body=texi_entity(doc, 'Arguments'))) + body=texi_entity(doc, 'Arguments', ifcond))) def symbol(self, doc, entity): if self._gen._body: @@ -257,7 +259,7 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor): assert not doc.args if self._gen._body: self._gen.add('\n') -self._gen.add(texi_body(doc) + texi_sections(doc)) +self._gen.add(texi_body(doc) + texi_sections(doc, None)) def gen_doc(schema, output_dir, prefix): diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json index 97ab4625ff..984cd8ed06 100644 --- a/tests/qapi-schema/doc-good.json +++ b/tests/qapi-schema/doc-good.json @@ -55,7 +55,7 @@ # # @two is undocumented ## -{ 'enum': 'Enum', 'data': [ 'one', 'two' ] } +{ 'enum': 'Enum', 'data': [ 'one', 'two' ], 'if': 'defined(IFCOND)' } ## # @Base: diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out index 3cd5c094aa..e4054e293c 100644 --- a/tests/qapi-schema/doc-good.out +++ b/tests/qapi-schema/doc-good.out @@ -12,6 +12,7 @@ module doc-good.json enum Enum member one member two +if ['defined(IFCOND)'] object Base member base1: Enum optional=False object Variant1 diff --git a/tests/qapi-schem
[Qemu-devel] [PATCH v3 49/49] RFC: make RTC_CHANGE per-target
A few targets don't emit RTC_CHANGE, we could restrict the event to the tagets that do emit it. Note: There is a lot more of events & commands that we could restrict to capable targets, with the cost of some additional complexity, but the benefit of added correctness and better introspection. Note2: The rate limite could perhaps be part of the schema, and the common event emitter code, to simplify the need of custom and #ifdef code in the monitor. Signed-off-by: Marc-André Lureau --- qapi/misc.json | 22 -- qapi/target.json | 23 +++ hw/ppc/spapr_rtc.c | 2 +- hw/timer/mc146818rtc.c | 2 +- monitor.c | 4 +++- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/qapi/misc.json b/qapi/misc.json index e9538ecae6..6415bbb7fe 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -2856,28 +2856,6 @@ { 'event': 'ACPI_DEVICE_OST', 'data': { 'info': 'ACPIOSTInfo' } } -## -# @RTC_CHANGE: -# -# Emitted when the guest changes the RTC time. -# -# @offset: offset between base RTC clock (as specified by -rtc base), and -# new RTC clock value -# -# Note: This event is rate-limited. -# -# Since: 0.13.0 -# -# Example: -# -# <- { "event": "RTC_CHANGE", -#"data": { "offset": 78 }, -#"timestamp": { "seconds": 1267020223, "microseconds": 435656 } } -# -## -{ 'event': 'RTC_CHANGE', - 'data': { 'offset': 'int' } } - ## # @ReplayMode: # diff --git a/qapi/target.json b/qapi/target.json index 89ba4207b1..b9f6741fbf 100644 --- a/qapi/target.json +++ b/qapi/target.json @@ -9,6 +9,29 @@ { 'include': 'misc.json' } +## +# @RTC_CHANGE: +# +# Emitted when the guest changes the RTC time. +# +# @offset: offset between base RTC clock (as specified by -rtc base), and +# new RTC clock value +# +# Note: This event is rate-limited. +# +# Since: 0.13.0 +# +# Example: +# +# <- { "event": "RTC_CHANGE", +#"data": { "offset": 78 }, +#"timestamp": { "seconds": 1267020223, "microseconds": 435656 } } +# +## +{ 'event': 'RTC_CHANGE', + 'data': { 'offset': 'int' }, + 'if': 'defined(TARGET_ALPHA) || defined(TARGET_ARM) || defined(TARGET_HPPA) || defined(TARGET_I386) || defined(TARGET_MIPS) || defined(TARGET_MIPS64) || defined(TARGET_MOXIE) || defined(TARGET_PPC) || defined(TARGET_PPC64) || defined(TARGET_S390X) || defined(TARGET_SH4) || defined(TARGET_SPARC)' } + ## # @rtc-reset-reinjection: # diff --git a/hw/ppc/spapr_rtc.c b/hw/ppc/spapr_rtc.c index a37360537e..4cb73abf4a 100644 --- a/hw/ppc/spapr_rtc.c +++ b/hw/ppc/spapr_rtc.c @@ -31,7 +31,7 @@ #include "sysemu/sysemu.h" #include "hw/ppc/spapr.h" #include "qapi/error.h" -#include "qapi/qapi-events-misc.h" +#include "qapi/target-qapi-events.h" #include "qemu/cutils.h" void spapr_rtc_read(sPAPRRTCState *rtc, struct tm *tm, uint32_t *ns) diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index dd575ffbdf..7de7562850 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -32,7 +32,7 @@ #include "hw/timer/mc146818rtc.h" #include "qapi/error.h" #include "qapi/target-qapi-commands.h" -#include "qapi/qapi-events-misc.h" +#include "qapi/target-qapi-events.h" #include "qapi/visitor.h" #ifdef TARGET_I386 diff --git a/monitor.c b/monitor.c index 377ea3c98b..3c972206d9 100644 --- a/monitor.c +++ b/monitor.c @@ -635,7 +635,6 @@ monitor_qapi_event_queue(unsigned event, QDict *qdict, Error **errp) .size = QAPI_EVENT__MAX, .rate = { /* Limit guest-triggerable events to 1 per second */ -[QAPI_EVENT_RTC_CHANGE]= 1000 * SCALE_MS, [QAPI_EVENT_WATCHDOG] = 1000 * SCALE_MS, [QAPI_EVENT_BALLOON_CHANGE]= 1000 * SCALE_MS, [QAPI_EVENT_QUORUM_REPORT_BAD] = 1000 * SCALE_MS, @@ -680,6 +679,9 @@ target_monitor_qapi_event_queue(unsigned event, QDict *qdict, Error **errp) .size = TARGET_QAPI_EVENT__MAX, .rate = { /* Limit guest-triggerable events to 1 per second */ +#if defined(TARGET_ALPHA) || defined(TARGET_ARM) || defined(TARGET_HPPA) || defined(TARGET_I386) || defined(TARGET_MIPS) | defined(TARGET_MIPS64) || defined(TARGET_MOXIE) || defined(TARGET_PPC) || defined(TARGET_PPC64) || defined(TARGET_S390X) || defined(TARGET_SH4) || defined(TARGET_SPARC) +[TARGET_QAPI_EVENT_RTC_CHANGE] = 1000 * SCALE_MS, +#endif [TARGET_QAPI_EVENT__MAX] = 0, }, }; -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 29/49] qapi: add #if conditions to generated code members
Wrap generated enum/struct members and code with #if/#endif, using the .ifcond members added in the previous patches. Some types generate both enum and struct members for example, so a step-by-step is unnecessarily complicated to deal with (it would easily generate invalid intermediary code). Signed-off-by: Marc-André Lureau --- scripts/qapi/common.py | 4 scripts/qapi/introspect.py | 13 + scripts/qapi/types.py | 4 scripts/qapi/visit.py | 8 +++- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index c913c18d2d..174b39ea50 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -2084,11 +2084,13 @@ const QEnumLookup %(c_name)s_lookup = { ''', c_name=c_name(name)) for m in members: +ret += gen_if(m.ifcond) index = c_enum_const(name, m.name, prefix) ret += mcgen(''' [%(index)s] = "%(name)s", ''', index=index, name=m.name) +ret += gen_endif(m.ifcond) ret += mcgen(''' }, @@ -2110,10 +2112,12 @@ typedef enum %(c_name)s { c_name=c_name(name)) for m in enum_members: +ret += gen_if(m.ifcond) ret += mcgen(''' %(c_enum)s, ''', c_enum=c_enum_const(name, m.name, prefix)) +ret += gen_endif(m.ifcond) ret += mcgen(''' } %(c_name)s; diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py index d62fca84de..5b147a3d6f 100644 --- a/scripts/qapi/introspect.py +++ b/scripts/qapi/introspect.py @@ -151,6 +151,8 @@ const QLitObject %(c_name)s = %(c_string)s; ret = {'name': member.name, 'type': self._use_type(member.type)} if member.optional: ret['default'] = None +if member.ifcond: +ret = (ret, member.ifcond) return ret def _gen_variants(self, tag_name, variants): @@ -158,14 +160,16 @@ const QLitObject %(c_name)s = %(c_string)s; 'variants': [self._gen_variant(v) for v in variants]} def _gen_variant(self, variant): -return {'case': variant.name, 'type': self._use_type(variant.type)} +return ({'case': variant.name, 'type': self._use_type(variant.type)}, +variant.ifcond) def visit_builtin_type(self, name, info, json_type): self._gen_qlit(name, 'builtin', {'json-type': json_type}, []) def visit_enum_type(self, name, info, ifcond, members, prefix): self._gen_qlit(name, 'enum', - {'values': [m.name for m in members]}, ifcond) + {'values': [(m.name, m.ifcond) for m in members]}, + ifcond) def visit_array_type(self, name, info, ifcond, element_type): element = self._use_type(element_type) @@ -181,8 +185,9 @@ const QLitObject %(c_name)s = %(c_string)s; def visit_alternate_type(self, name, info, ifcond, variants): self._gen_qlit(name, 'alternate', - {'members': [{'type': self._use_type(m.type)} -for m in variants.variants]}, ifcond) + {'members': [ + ({'type': self._use_type(m.type)}, m.ifcond) + for m in variants.variants]}, ifcond) def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob): diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py index 5b790cb41d..b0d3ddb596 100644 --- a/scripts/qapi/types.py +++ b/scripts/qapi/types.py @@ -43,6 +43,7 @@ struct %(c_name)s { def gen_struct_members(members): ret = '' for memb in members: +ret += gen_if(memb.ifcond) if memb.optional: ret += mcgen(''' bool has_%(c_name)s; @@ -52,6 +53,7 @@ def gen_struct_members(members): %(c_type)s %(c_name)s; ''', c_type=memb.type.c_type(), c_name=c_name(memb.name)) +ret += gen_endif(memb.ifcond) return ret @@ -131,11 +133,13 @@ def gen_variants(variants): c_name=c_name(variants.tag_member.name)) for var in variants.variants: +ret += gen_if(var.ifcond) ret += mcgen(''' %(c_type)s %(c_name)s; ''', c_type=var.type.c_unboxed_type(), c_name=c_name(var.name)) +ret += gen_endif(var.ifcond) ret += mcgen(''' } u; diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index ee776386ae..dc5a3173fc 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -54,6 +54,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) c_type=base.c_name()) for memb in members: +ret += gen_if(memb.ifcond) if memb.optional: ret += mcgen(''' if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) { @@ -73,6 +
[Qemu-devel] [PATCH v3 33/49] qapi2texi: add 'If:' condition to struct members
Signed-off-by: Marc-André Lureau --- scripts/qapi/doc.py | 4 +++- tests/qapi-schema/doc-good.json | 3 ++- tests/qapi-schema/doc-good.out | 1 + tests/qapi-schema/doc-good.texi | 2 ++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py index f629425f53..42e34e1fe3 100755 --- a/scripts/qapi/doc.py +++ b/scripts/qapi/doc.py @@ -138,9 +138,11 @@ def texi_member(member, suffix=''): """Format a table of members item for an object type member""" typ = member.type.doc_type() membertype = ': ' + typ if typ else '' -return '@item @code{%s%s}%s%s\n' % ( +return '@item @code{%s%s}%s%s%s\n' % ( member.name, membertype, ' (optional)' if member.optional else '', +'\n@b{If:} @code{%s}\n' % +', '.join(member.ifcond) if member.ifcond else '', suffix) diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json index c7fe08c530..158443b1a3 100644 --- a/tests/qapi-schema/doc-good.json +++ b/tests/qapi-schema/doc-good.json @@ -72,7 +72,8 @@ # # Another paragraph (but no @var: line) ## -{ 'struct': 'Variant1', 'data': { 'var1': 'str' } } +{ 'struct': 'Variant1', + 'data': { 'var1': { 'type': 'str', 'if': 'defined(IFSTR)' } } } ## # @Variant2: diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out index d27d345de2..9976d29eb0 100644 --- a/tests/qapi-schema/doc-good.out +++ b/tests/qapi-schema/doc-good.out @@ -18,6 +18,7 @@ object Base member base1: Enum optional=False object Variant1 member var1: str optional=False +if ['defined(IFSTR)'] object Variant2 object Object base Base diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi index 2446a1c702..255eed9a30 100644 --- a/tests/qapi-schema/doc-good.texi +++ b/tests/qapi-schema/doc-good.texi @@ -120,6 +120,8 @@ Another paragraph (but no @code{var}: line) @b{Members:} @table @asis @item @code{var1: string} +@b{If:} @code{defined(IFSTR)} + Not documented @end table -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 30/49] docs: document schema configuration
Signed-off-by: Marc-André Lureau --- docs/devel/qapi-code-gen.txt | 38 1 file changed, 38 insertions(+) diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index a569d24745..eec52e63e5 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -728,6 +728,44 @@ Example: Red Hat, Inc. controls redhat.com, and may therefore add a downstream command __com.redhat_drive-mirror. +=== Configuring the schema === + +Top-level QAPI expressions and various type expressions listed below +can take an 'if' key. The value must be a string or a list of +string. The corresponding generated code will then guard the inclusion +of that member in the larger struct or function with #if IFCOND +(or several #if lines for a list), where IFCOND is the value of the +'if' key. + +'struct', 'enum', 'union', 'alternate', 'command' and 'event' +top-level QAPI expressions can take an 'if' keyword like: + +{ 'struct': 'IfStruct', 'data': { 'foo': 'int' }, + 'if': 'defined(IFCOND)' } + +Where a member can normally be defined with a single string value as its +type, it is also possible to supply a dictionary with both 'type' and +'if' keys. + +{ 'struct': 'IfStruct', 'data': + { 'foo': 'int', +'bar': { 'type': 'int', 'if': 'defined(IFCOND)'} } } + +An enum value can be replaced by a dictionary with a 'name' and a 'if' +key: + +{ 'enum': 'IfEnum', 'data': + [ 'foo', +{ 'name' : 'bar', 'if': 'defined(IFCOND)' } ] } + +Please note that you are responsible to ensure that the C code will +compile with an arbitrary combination of conditions, since the +generators are unable to check it at this point. + +The presence of 'if' keys in the schema is reflected through to the +introspection output depending on the build configuration. + + == Client JSON Protocol introspection == Clients of a Client JSON Protocol commonly need to figure out what -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 36/49] qapi: add conditions to SPICE type/commands/events on the schema
Add #if defined(CONFIG_SPICE) in generated code, and adjust the qmp/hmp code accordingly. query-qmp-schema no longer reports the command/events etc as available when disabled at compile time. Commands made conditional: * query-spice Before the patch, the command for !CONFIG_SPICE is unregistered. It will fail with the same error. Events made conditional: * SPICE_CONNECTED, SPICE_INITIALIZED, SPICE_DISCONNECTED, SPICE_MIGRATE_COMPLETED Chardev made conditional: * spiceport, spicevmc Before and after the patch for !CONFIG_SPICE, the error is the same ('spiceport' is not a valid char driver name). No HMP change, the code was already conditional. Signed-off-by: Marc-André Lureau Reviewed-by: Gerd Hoffmann --- qapi/char.json | 10 ++ qapi/ui.json | 30 -- monitor.c | 3 --- qmp.c | 16 4 files changed, 26 insertions(+), 33 deletions(-) diff --git a/qapi/char.json b/qapi/char.json index ae19dcd1ed..7fa1762ae5 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -318,7 +318,8 @@ # Since: 1.5 ## { 'struct': 'ChardevSpiceChannel', 'data': { 'type' : 'str' }, - 'base': 'ChardevCommon' } + 'base': 'ChardevCommon', + 'if': 'defined(CONFIG_SPICE)' } ## # @ChardevSpicePort: @@ -330,7 +331,8 @@ # Since: 1.5 ## { 'struct': 'ChardevSpicePort', 'data': { 'fqdn' : 'str' }, - 'base': 'ChardevCommon' } + 'base': 'ChardevCommon', + 'if': 'defined(CONFIG_SPICE)' } ## # @ChardevVC: @@ -384,8 +386,8 @@ 'testdev': 'ChardevCommon', 'stdio' : 'ChardevStdio', 'console': 'ChardevCommon', - 'spicevmc' : 'ChardevSpiceChannel', - 'spiceport' : 'ChardevSpicePort', + 'spicevmc' : { 'type': 'ChardevSpiceChannel', 'if': 'defined(CONFIG_SPICE)' }, + 'spiceport' : { 'type': 'ChardevSpicePort', 'if': 'defined(CONFIG_SPICE)' }, 'vc' : 'ChardevVC', 'ringbuf': 'ChardevRingbuf', # next one is just for compatibility diff --git a/qapi/ui.json b/qapi/ui.json index 4b96509446..e47fae2e90 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -118,7 +118,8 @@ { 'struct': 'SpiceBasicInfo', 'data': { 'host': 'str', 'port': 'str', -'family': 'NetworkAddressFamily' } } +'family': 'NetworkAddressFamily' }, + 'if': 'defined(CONFIG_SPICE)' } ## # @SpiceServerInfo: @@ -131,7 +132,8 @@ ## { 'struct': 'SpiceServerInfo', 'base': 'SpiceBasicInfo', - 'data': { '*auth': 'str' } } + 'data': { '*auth': 'str' }, + 'if': 'defined(CONFIG_SPICE)' } ## # @SpiceChannel: @@ -156,7 +158,8 @@ { 'struct': 'SpiceChannel', 'base': 'SpiceBasicInfo', 'data': {'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int', - 'tls': 'bool'} } + 'tls': 'bool'}, + 'if': 'defined(CONFIG_SPICE)' } ## # @SpiceQueryMouseMode: @@ -175,7 +178,8 @@ # Since: 1.1 ## { 'enum': 'SpiceQueryMouseMode', - 'data': [ 'client', 'server', 'unknown' ] } + 'data': [ 'client', 'server', 'unknown' ], + 'if': 'defined(CONFIG_SPICE)' } ## # @SpiceInfo: @@ -212,7 +216,8 @@ { 'struct': 'SpiceInfo', 'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int', '*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str', - 'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} } + 'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']}, + 'if': 'defined(CONFIG_SPICE)' } ## # @query-spice: @@ -257,7 +262,8 @@ #} # ## -{ 'command': 'query-spice', 'returns': 'SpiceInfo' } +{ 'command': 'query-spice', 'returns': 'SpiceInfo', + 'if': 'defined(CONFIG_SPICE)' } ## # @SPICE_CONNECTED: @@ -282,7 +288,8 @@ ## { 'event': 'SPICE_CONNECTED', 'data': { 'server': 'SpiceBasicInfo', -'client': 'SpiceBasicInfo' } } +'client': 'SpiceBasicInfo' }, + 'if': 'defined(CONFIG_SPICE)' } ## # @SPICE_INITIALIZED: @@ -310,7 +317,8 @@ ## { 'event': 'SPICE_INITIALIZED', 'data': { 'server': 'SpiceServerInfo', -'client': 'SpiceChannel' } } +'client': 'SpiceChannel' }, + 'if': 'defined(CONFIG_SPICE)' } ## # @SPICE_DISCONNECTED: @@ -335,7 +343,8 @@ ## { 'event': 'SPICE_DISCONNECTED', 'data': { 'server': 'SpiceBasicInfo', -'client': 'SpiceBasicInfo' } } +'client': 'SpiceBasicInfo' }, + 'if': 'defined(CONFIG_SPICE)' } ## # @SPICE_MIGRATE_COMPLETED: @@ -350,7 +359,8 @@ # "event": "SPICE_MIGRATE_COMPLETED" } # ## -{ 'event': 'SPICE_MIGRATE_COMPLETED' } +{ 'event': 'SPICE_MIGRATE_COMPLETED', + 'if': 'defined(CONFIG_SPICE)' } ## # == VNC diff
[Qemu-devel] [PATCH v3 38/49] build-sys: move qmp-introspect per target
The following patches are going to introduce per-target #ifdef in the schemas. The introspection data is statically generated once, and must thus be built per-target to reflect target-specific configuration. Drop "do_test_visitor_in_qmp_introspect(&qmp_schema_qlit)" since the schema is no longer in a common object. It is covered by the per-target query-qmp-schema test instead. Signed-off-by: Marc-André Lureau --- tests/test-qobject-input-visitor.c | 1 - Makefile.objs | 2 -- Makefile.target| 2 ++ 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-visitor.c index 6dc59c6211..e14544fc89 100644 --- a/tests/test-qobject-input-visitor.c +++ b/tests/test-qobject-input-visitor.c @@ -1270,7 +1270,6 @@ static void test_visitor_in_qmp_introspect(TestInputVisitorData *data, const void *unused) { do_test_visitor_in_qmp_introspect(data, &test_qmp_schema_qlit); -do_test_visitor_in_qmp_introspect(data, &qmp_schema_qlit); } int main(int argc, char **argv) diff --git a/Makefile.objs b/Makefile.objs index c6c9b8fc21..f0b10dbf23 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -55,7 +55,6 @@ util-obj-y += qapi/qapi-events-tpm.o util-obj-y += qapi/qapi-events-trace.o util-obj-y += qapi/qapi-events-transaction.o util-obj-y += qapi/qapi-events-ui.o -util-obj-y += qapi/qapi-introspect.o chardev-obj-y = chardev/ @@ -150,7 +149,6 @@ common-obj-y += qapi/qapi-commands-tpm.o common-obj-y += qapi/qapi-commands-trace.o common-obj-y += qapi/qapi-commands-transaction.o common-obj-y += qapi/qapi-commands-ui.o -common-obj-y += qapi/qapi-introspect.o common-obj-y += qmp.o hmp.o endif diff --git a/Makefile.target b/Makefile.target index 6549481096..0bb18dff9e 100644 --- a/Makefile.target +++ b/Makefile.target @@ -150,6 +150,8 @@ endif GENERATED_FILES += hmp-commands.h hmp-commands-info.h +obj-y += qapi/qapi-introspect.o + endif # CONFIG_SOFTMMU # Workaround for http://gcc.gnu.org/PR55489, see configure. -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 41/49] qapi: add a top-unit 'target' schema
Add a 'target' top-unit to be compiled seperately from the common qapi modules, in order to allow poisoined target #ifdef. The generated commands must be registered seperately. The events have a different enum, and must thus use a different limiter/emitter. Signed-off-by: Marc-André Lureau --- qapi/qapi-schema.json| 1 + qapi/target.json | 13 +++ include/qapi/qmp-event.h | 4 + monitor.c| 205 ++- qapi/qmp-event.c | 11 +++ Makefile | 1 + Makefile.target | 2 + 7 files changed, 170 insertions(+), 67 deletions(-) create mode 100644 qapi/target.json diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index 25bce78352..6e7f85ae6d 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -93,3 +93,4 @@ { 'include': 'trace.json' } { 'include': 'introspect.json' } { 'include': 'misc.json' } +{ 'include': 'target.json' } diff --git a/qapi/target.json b/qapi/target.json new file mode 100644 index 00..be2360ca34 --- /dev/null +++ b/qapi/target.json @@ -0,0 +1,13 @@ +# -*- Mode: Python -*- +# + +## +# = Target-specific commands & events +## + +{ 'pragma': { 'top-unit': 'target' } } + +## +# @DUMMY: +## +{ 'event': 'DUMMY' } diff --git a/include/qapi/qmp-event.h b/include/qapi/qmp-event.h index 0c87ad833e..cdf3b9b970 100644 --- a/include/qapi/qmp-event.h +++ b/include/qapi/qmp-event.h @@ -21,5 +21,9 @@ void qmp_event_set_func_emit(QMPEventFuncEmit emit); QMPEventFuncEmit qmp_event_get_func_emit(void); +void target_qmp_event_set_func_emit(QMPEventFuncEmit emit); + +QMPEventFuncEmit target_qmp_event_get_func_emit(void); + QDict *qmp_event_build_dict(const char *event_name); #endif diff --git a/monitor.c b/monitor.c index 0d84c3edb4..0b96285e94 100644 --- a/monitor.c +++ b/monitor.c @@ -77,6 +77,8 @@ #include "block/qapi.h" #include "qapi/qapi-commands.h" #include "qapi/qapi-events.h" +#include "qapi/target-qapi-commands.h" +#include "qapi/target-qapi-events.h" #include "qapi/error.h" #include "qapi/qmp-event.h" #include "qapi/qapi-introspect.h" @@ -184,22 +186,25 @@ typedef struct { GQueue *qmp_responses; } MonitorQMP; +typedef struct { +GHashTable *state; +const size_t size;/* size of array == number of events */ +const int64_t rate[]; /* Minimum time (in ns) between two events */ +} MonitorQAPIEventRateLimit; + /* * To prevent flooding clients, events can be throttled. The * throttling is calculated globally, rather than per-Monitor * instance. */ typedef struct MonitorQAPIEventState { -QAPIEvent event;/* Throttling state for this event type and... */ +const MonitorQAPIEventRateLimit *limiter; +unsigned event; /* Throttling state for this event type and... */ QDict *data;/* ... data, see qapi_event_throttle_equal() */ QEMUTimer *timer; /* Timer for handling delayed events */ QDict *qdict; /* Delayed event (if any) */ } MonitorQAPIEventState; -typedef struct { -int64_t rate; /* Minimum time (in ns) between two events */ -} MonitorQAPIEventConf; - struct Monitor { CharBackend chr; int reset_seen; @@ -502,23 +507,11 @@ static void monitor_qmp_bh_responder(void *opaque) } } -static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = { -/* Limit guest-triggerable events to 1 per second */ -[QAPI_EVENT_RTC_CHANGE]= { 1000 * SCALE_MS }, -[QAPI_EVENT_WATCHDOG] = { 1000 * SCALE_MS }, -[QAPI_EVENT_BALLOON_CHANGE]= { 1000 * SCALE_MS }, -[QAPI_EVENT_QUORUM_REPORT_BAD] = { 1000 * SCALE_MS }, -[QAPI_EVENT_QUORUM_FAILURE]= { 1000 * SCALE_MS }, -[QAPI_EVENT_VSERPORT_CHANGE] = { 1000 * SCALE_MS }, -}; - -GHashTable *monitor_qapi_event_state; - /* * Emits the event to every monitor instance, @event is only used for trace * Called with monitor_lock held. */ -static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict) +static void monitor_qapi_event_emit(unsigned event, QDict *qdict) { Monitor *mon; @@ -538,30 +531,31 @@ static void monitor_qapi_event_handler(void *opaque); * applying any rate limiting if required. */ static void -monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp) +monitor_qapi_event_queue_limit(const MonitorQAPIEventRateLimit *limiter, + unsigned event, QDict *qdict, Error **errp) { -MonitorQAPIEventConf *evconf; +int64_t rate; MonitorQAPIEventState *evstate; -assert(event < QAPI_EVENT__MAX); -evconf = &monitor_qapi_event_conf[event]; -trace_monitor_protocol_event_queue(event, qdict, evconf->rate); +assert(event < limiter->size); +rate = limiter->rate[event]; +trace_monitor_protocol_event_queue(event, qdict, rate); qemu_mutex_lock(&monitor_lock); -if (!evconf->rate) { +if (!rate) { /* Unthrottled event */ monitor_qapi_event_emit(event, qdi
[Qemu-devel] [PULL v1 1/4] tpm: CRB: Set tpmRegValidSts flag to '1' in device reset
Fix the initialization of the tpmRegValidSts flag and set it to '1' during device reset without expecting a write to another register. This seems to also be the default behavior of real hardware. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_crb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index d8917cb..114b66e 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -145,8 +145,6 @@ static void tpm_crb_mmio_write(void *opaque, hwaddr addr, beenSeized, 0); ARRAY_FIELD_DP32(s->regs, CRB_LOC_STATE, locAssigned, 1); -ARRAY_FIELD_DP32(s->regs, CRB_LOC_STATE, - tpmRegValidSts, 1); break; } break; @@ -210,6 +208,8 @@ static void tpm_crb_reset(void *dev) tpm_backend_reset(s->tpmbe); +ARRAY_FIELD_DP32(s->regs, CRB_LOC_STATE, + tpmRegValidSts, 1); ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID, InterfaceType, CRB_INTF_TYPE_CRB_ACTIVE); ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID, -- 2.5.5
[Qemu-devel] [PATCH v3 34/49] qapi2texi: add condition to variants
Signed-off-by: Marc-André Lureau --- scripts/qapi/doc.py | 5 +++-- tests/qapi-schema/doc-good.json | 4 ++-- tests/qapi-schema/doc-good.out | 3 +++ tests/qapi-schema/doc-good.texi | 4 ++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py index 42e34e1fe3..40dcedc6ed 100755 --- a/scripts/qapi/doc.py +++ b/scripts/qapi/doc.py @@ -165,8 +165,9 @@ def texi_members(doc, what, base, variants, member_func): items += '@item The members of @code{%s}\n' % base.doc_type() if variants: for v in variants.variants: -when = ' when @code{%s} is @t{"%s"}' % ( -variants.tag_member.name, v.name) +when = ' when @code{%s} is @t{"%s"}%s' % ( +variants.tag_member.name, v.name, +' (@b{If:} @code{%s})' % v.ifcond if v.ifcond else '') if v.type.is_implicit(): assert not v.type.base and not v.type.variants for m in v.type.local_members: diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json index 158443b1a3..afe46d93f0 100644 --- a/tests/qapi-schema/doc-good.json +++ b/tests/qapi-schema/doc-good.json @@ -86,13 +86,13 @@ { 'union': 'Object', 'base': 'Base', 'discriminator': 'base1', - 'data': { 'one': 'Variant1', 'two': 'Variant2' } } + 'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } } ## # @SugaredUnion: ## { 'union': 'SugaredUnion', - 'data': { 'one': 'Variant1', 'two': 'Variant2' } } + 'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } } ## # == Another subsection diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out index 9976d29eb0..4b36cf6f7d 100644 --- a/tests/qapi-schema/doc-good.out +++ b/tests/qapi-schema/doc-good.out @@ -25,6 +25,7 @@ object Object tag base1 case one: Variant1 case two: Variant2 +if ['IFTWO'] object q_obj_Variant1-wrapper member data: Variant1 optional=False object q_obj_Variant2-wrapper @@ -32,11 +33,13 @@ object q_obj_Variant2-wrapper enum SugaredUnionKind member one member two +if ['IFTWO'] object SugaredUnion member type: SugaredUnionKind optional=False tag type case one: q_obj_Variant1-wrapper case two: q_obj_Variant2-wrapper +if ['IFTWO'] object q_obj_cmd-arg member arg1: int optional=False member arg2: str optional=True diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi index 255eed9a30..6e226a6231 100644 --- a/tests/qapi-schema/doc-good.texi +++ b/tests/qapi-schema/doc-good.texi @@ -145,7 +145,7 @@ Not documented @table @asis @item The members of @code{Base} @item The members of @code{Variant1} when @code{base1} is @t{"one"} -@item The members of @code{Variant2} when @code{base1} is @t{"two"} +@item The members of @code{Variant2} when @code{base1} is @t{"two"} (@b{If:} @code{['IFTWO']}) @end table @end deftp @@ -161,7 +161,7 @@ Not documented @item @code{type} One of @t{"one"}, @t{"two"} @item @code{data: Variant1} when @code{type} is @t{"one"} -@item @code{data: Variant2} when @code{type} is @t{"two"} +@item @code{data: Variant2} when @code{type} is @t{"two"} (@b{If:} @code{['IFTWO']}) @end table @end deftp -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 44/49] target.json: add a note about query-cpu* not being s390x-specific
Signed-off-by: Marc-André Lureau Acked-by: Cornelia Huck --- qapi/target.json | 6 ++ 1 file changed, 6 insertions(+) diff --git a/qapi/target.json b/qapi/target.json index b07a8926d8..be0ff84a6e 100644 --- a/qapi/target.json +++ b/qapi/target.json @@ -241,6 +241,9 @@ # an unknown cpu definition name, unknown properties or properties # with wrong types. # +# Note: this command isn't specific to s390x, but is only implemented +# on this architecture currently. +# # Since: 2.8.0 ## { 'command': 'query-cpu-model-comparison', @@ -281,6 +284,9 @@ # an unknown cpu definition name, unknown properties or properties # with wrong types. # +# Note: this command isn't specific to s390x, but is only implemented +# on this architecture currently. +# # Since: 2.8.0 ## { 'command': 'query-cpu-model-baseline', -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 42/49] qapi: make rtc-reset-reinjection and SEV depend on TARGET_I386
Move rtc-reset-reinjection and SEV in target.json and make them conditional on TARGET_I386. Signed-off-by: Marc-André Lureau --- qapi/misc.json | 166 -- qapi/target.json | 175 - target/i386/sev_i386.h | 2 +- hw/timer/mc146818rtc.c | 2 +- monitor.c | 31 5 files changed, 175 insertions(+), 201 deletions(-) diff --git a/qapi/misc.json b/qapi/misc.json index 5636f4a149..690eeda41f 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -3005,24 +3005,6 @@ { 'event': 'ACPI_DEVICE_OST', 'data': { 'info': 'ACPIOSTInfo' } } -## -# @rtc-reset-reinjection: -# -# This command will reset the RTC interrupt reinjection backlog. -# Can be used if another mechanism to synchronize guest time -# is in effect, for example QEMU guest agent's guest-set-time -# command. -# -# Since: 2.1 -# -# Example: -# -# -> { "execute": "rtc-reset-reinjection" } -# <- { "return": {} } -# -## -{ 'command': 'rtc-reset-reinjection' } - ## # @RTC_CHANGE: # @@ -3247,154 +3229,6 @@ ## { 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' } - -## -# @SevState: -# -# An enumeration of SEV state information used during @query-sev. -# -# @uninit: The guest is uninitialized. -# -# @launch-update: The guest is currently being launched; plaintext data and -# register state is being imported. -# -# @launch-secret: The guest is currently being launched; ciphertext data -# is being imported. -# -# @running: The guest is fully launched or migrated in. -# -# @send-update: The guest is currently being migrated out to another machine. -# -# @receive-update: The guest is currently being migrated from another machine. -# -# Since: 2.12 -## -{ 'enum': 'SevState', - 'data': ['uninit', 'launch-update', 'launch-secret', 'running', - 'send-update', 'receive-update' ] } - -## -# @SevInfo: -# -# Information about Secure Encrypted Virtualization (SEV) support -# -# @enabled: true if SEV is active -# -# @api-major: SEV API major version -# -# @api-minor: SEV API minor version -# -# @build-id: SEV FW build id -# -# @policy: SEV policy value -# -# @state: SEV guest state -# -# @handle: SEV firmware handle -# -# Since: 2.12 -## -{ 'struct': 'SevInfo', -'data': { 'enabled': 'bool', - 'api-major': 'uint8', - 'api-minor' : 'uint8', - 'build-id' : 'uint8', - 'policy' : 'uint32', - 'state' : 'SevState', - 'handle' : 'uint32' -} -} - -## -# @query-sev: -# -# Returns information about SEV -# -# Returns: @SevInfo -# -# Since: 2.12 -# -# Example: -# -# -> { "execute": "query-sev" } -# <- { "return": { "enabled": true, "api-major" : 0, "api-minor" : 0, -# "build-id" : 0, "policy" : 0, "state" : "running", -# "handle" : 1 } } -# -## -{ 'command': 'query-sev', 'returns': 'SevInfo' } - -## -# @SevLaunchMeasureInfo: -# -# SEV Guest Launch measurement information -# -# @data: the measurement value encoded in base64 -# -# Since: 2.12 -# -## -{ 'struct': 'SevLaunchMeasureInfo', 'data': {'data': 'str'} } - -## -# @query-sev-launch-measure: -# -# Query the SEV guest launch information. -# -# Returns: The @SevLaunchMeasureInfo for the guest -# -# Since: 2.12 -# -# Example: -# -# -> { "execute": "query-sev-launch-measure" } -# <- { "return": { "data": "4l8LXeNlSPUDlXPJG5966/8%YZ" } } -# -## -{ 'command': 'query-sev-launch-measure', 'returns': 'SevLaunchMeasureInfo' } - -## -# @SevCapability: -# -# The struct describes capability for a Secure Encrypted Virtualization -# feature. -# -# @pdh: Platform Diffie-Hellman key (base64 encoded) -# -# @cert-chain: PDH certificate chain (base64 encoded) -# -# @cbitpos: C-bit location in page table entry -# -# @reduced-phys-bits: Number of physical Address bit reduction when SEV is -# enabled -# -# Since: 2.12 -## -{ 'struct': 'SevCapability', - 'data': { 'pdh': 'str', -'cert-chain': 'str', -'cbitpos': 'int', -'reduced-phys-bits': 'int'} } - -## -# @query-sev-capabilities: -# -# This command is used to get the SEV capabilities, and is supported on AMD -# X86 platforms only. -# -# Returns: SevCapability objects. -# -# Since: 2.12 -# -# Example: -# -# -> { "execute": "query-sev-capabilities" } -# <- { "return": { "pdh": "8CCDD8DDD", "cert-chain": "888CCCDDDEE", -# "cbitpos": 47, "reduced-phys-bits": 5}} -# -## -{ 'command': 'query-sev-capabilities', 'returns': 'SevCapability' } - ## # @CommandDropReason: # diff --git a/qapi/target.json b/qapi/target.json index be2360ca34..f277b69a2a 100644 --- a/qapi/target.json +++ b/qapi/target.json @@ -8,6 +8,177 @@ { 'pragma': { 'top-unit': 'target' } } ## -# @DUMMY: +# @rtc-reset-reinjection: +# +# This command will reset the RTC interrupt reinjection backlog. +# Can be used if another mechanism to synchronize guest time +# is in e
[Qemu-devel] [PATCH v3 35/49] qapi: add conditions to VNC type/commands/events on the schema
Add #if defined(CONFIG_VNC) in generated code, and adjust the qmp/hmp code accordingly. query-qmp-schema no longer reports the command/events etc as available when disabled at compile. Commands made conditional: * query-vnc, query-vnc-servers, change-vnc-password Before the patch, the commands for !CONFIG_VNC are stubs that fail like this: {"error": {"class": "GenericError", "desc": "The feature 'vnc' is not enabled"}} Afterwards, they fail like this: {"error": {"class": "CommandNotFound", "desc": "The command FOO has not been found"}} I call that an improvement, because it lets clients distinguish between command unavailable (class CommandNotFound) and command failed (class GenericError). Events made conditional: * VNC_CONNECTED, VNC_INITIALIZED, VNC_DISCONNECTED HMP change: * info vnc Will return "unknown command: 'info vnc'" when VNC is compiled out (same as error for spice when --disable-spice) Occurrences of VNC (case insensitive) in the schema that aren't covered by this change: * add_client Command has other uses, including "socket bases character devices". These are unconditional as far as I can tell. * set_password, expire_password In theory, these commands could be used for managing any service's password. In practice, they're used for VNC and SPICE services. They're documented for "remote display session" / "remote display server". The service is selected by argument @protocol. The code special-cases protocol-specific argument checking, then calls a protocol-specific function to do the work. If it fails, the command fails with "Could not set password". It does when the service isn't compiled in (it's a stub then). We could make these commands conditional on the conjunction of all services [currently: defined(CONFIG_VNC) || defined(CONFIG_SPICE)], but I doubt it's worthwhile. * change Command has other uses, namely changing media. This patch inlines a stub; no functional change. Signed-off-by: Marc-André Lureau Reviewed-by: Gerd Hoffmann --- qapi/ui.json | 45 +++- ui/vnc.h | 2 ++ hmp.c| 9 - qmp.c| 30 - hmp-commands-info.hx | 2 ++ 5 files changed, 44 insertions(+), 44 deletions(-) diff --git a/qapi/ui.json b/qapi/ui.json index 5d01ad4304..4b96509446 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -377,7 +377,8 @@ 'data': { 'host': 'str', 'service': 'str', 'family': 'NetworkAddressFamily', -'websocket': 'bool' } } +'websocket': 'bool' }, + 'if': 'defined(CONFIG_VNC)' } ## # @VncServerInfo: @@ -391,7 +392,8 @@ ## { 'struct': 'VncServerInfo', 'base': 'VncBasicInfo', - 'data': { '*auth': 'str' } } + 'data': { '*auth': 'str' }, + 'if': 'defined(CONFIG_VNC)' } ## # @VncClientInfo: @@ -408,7 +410,8 @@ ## { 'struct': 'VncClientInfo', 'base': 'VncBasicInfo', - 'data': { '*x509_dname': 'str', '*sasl_username': 'str' } } + 'data': { '*x509_dname': 'str', '*sasl_username': 'str' }, + 'if': 'defined(CONFIG_VNC)' } ## # @VncInfo: @@ -449,7 +452,8 @@ { 'struct': 'VncInfo', 'data': {'enabled': 'bool', '*host': 'str', '*family': 'NetworkAddressFamily', - '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} } + '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']}, + 'if': 'defined(CONFIG_VNC)' } ## # @VncPrimaryAuth: @@ -460,7 +464,8 @@ ## { 'enum': 'VncPrimaryAuth', 'data': [ 'none', 'vnc', 'ra2', 'ra2ne', 'tight', 'ultra', -'tls', 'vencrypt', 'sasl' ] } +'tls', 'vencrypt', 'sasl' ], + 'if': 'defined(CONFIG_VNC)' } ## # @VncVencryptSubAuth: @@ -474,8 +479,8 @@ 'tls-none', 'x509-none', 'tls-vnc', 'x509-vnc', 'tls-plain', 'x509-plain', -'tls-sasl', 'x509-sasl' ] } - +'tls-sasl', 'x509-sasl' ], + 'if': 'defined(CONFIG_VNC)' } ## # @VncServerInfo2: @@ -492,8 +497,8 @@ { 'struct': 'VncServerInfo2', 'base': 'VncBasicInfo', 'data': { 'auth' : 'VncPrimaryAuth', -'*vencrypt' : 'VncVencryptSubAuth' } } - +'*vencrypt' : 'VncVencryptSubAuth' }, + 'if': 'defined(CONFIG_VNC)' } ## # @VncInfo2: @@ -525,7 +530,8 @@ 'clients' : ['VncClientInfo'], 'auth' : 'VncPrimaryAuth', '*vencrypt' : 'VncVencryptSubAuth', -'*display' : 'str' } } +'*display' : 'str' }, + 'if': 'defined(CONFIG_VNC)' } ## # @query-vnc: @@ -556,8 +562,8 @@ #} # ## -{ 'command': 'query-vnc', 'returns': 'VncInfo' } - +{ 'command': 'query-vnc', 'returns': 'VncInfo', + 'if': 'defined(CONFIG_VNC)' } ## # @query-vnc-servers: # @@ -567,7 +573,8 @@ # # Since: 2.3 ## -{ 'command': 'query-vnc-servers', 'returns': ['VncInfo2'] } +{ 'command': 'que
[Qemu-devel] [PULL v1 4/4] tpm: CRB: query backend for TPM established flag
Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_crb.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index e8c42f6..ef8b80e 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -84,6 +84,12 @@ static uint64_t tpm_crb_mmio_read(void *opaque, hwaddr addr, unsigned offset = addr & 3; uint32_t val = *(uint32_t *)regs >> (8 * offset); +switch (addr) { +case A_CRB_LOC_STATE: +val |= !tpm_backend_get_tpm_established_flag(s->tpmbe); +break; +} + trace_tpm_crb_mmio_read(addr, size, val); return val; -- 2.5.5
[Qemu-devel] [PATCH v3 47/49] qapi: make query-cpu-definitions depend on specific targets
It depends on TARGET_PPC || TARGET_ARM || TARGET_I386 || TARGET_S390X. Signed-off-by: Marc-André Lureau Reviewed-by: Eduardo Habkost Acked-by: Cornelia Huck --- qapi/misc.json | 10 -- qapi/target.json| 12 include/sysemu/arch_init.h | 1 - monitor.c | 22 -- qmp.c | 5 - stubs/arch-query-cpu-def.c | 11 --- target/arm/helper.c | 3 ++- target/i386/cpu.c | 3 ++- target/ppc/translate_init.c | 3 ++- target/s390x/cpu_models.c | 2 +- stubs/Makefile.objs | 1 - 11 files changed, 19 insertions(+), 54 deletions(-) delete mode 100644 stubs/arch-query-cpu-def.c diff --git a/qapi/misc.json b/qapi/misc.json index 602c99b174..e9538ecae6 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -2027,16 +2027,6 @@ ## { 'command': 'query-memory-size-summary', 'returns': 'MemoryInfo' } -## -# @query-cpu-definitions: -# -# Return a list of supported virtual CPU definitions -# -# Returns: a list of CpuDefInfo -# -# Since: 1.2.0 -## -{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] } ## # @CpuModelInfo: diff --git a/qapi/target.json b/qapi/target.json index 323994a6ec..89ba4207b1 100644 --- a/qapi/target.json +++ b/qapi/target.json @@ -378,3 +378,15 @@ 'model': 'CpuModelInfo' }, 'returns': 'CpuModelExpansionInfo', 'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' } + +## +# @query-cpu-definitions: +# +# Return a list of supported virtual CPU definitions +# +# Returns: a list of CpuDefInfo +# +# Since: 1.2.0 +## +{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'], + 'if': 'defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_I386) || defined(TARGET_S390X)' } diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index 2497fd3351..10cbafe970 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -32,5 +32,4 @@ extern const uint32_t arch_type; int kvm_available(void); int xen_available(void); -CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp); #endif diff --git a/monitor.c b/monitor.c index 63c51ee05d..377ea3c98b 100644 --- a/monitor.c +++ b/monitor.c @@ -1143,26 +1143,6 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data, *ret_data = qobject_from_qlit(&qmp_schema_qlit); } -/* - * We used to define commands in qmp-commands.hx in addition to the - * QAPI schema. This permitted defining some of them only in certain - * configurations. query-commands has always reflected that (good, - * because it lets QMP clients figure out what's actually available), - * while query-qmp-schema never did (not so good). This function is a - * hack to keep the configuration-specific commands defined exactly as - * before, even though qmp-commands.hx is gone. - * - * FIXME Educate the QAPI schema on configuration-specific commands, - * and drop this hack. - */ -static void qmp_unregister_commands_hack(void) -{ -#if !defined(TARGET_PPC) && !defined(TARGET_ARM) && !defined(TARGET_I386) \ -&& !defined(TARGET_S390X) -qmp_unregister_command(&qmp_commands, "query-cpu-definitions"); -#endif -} - static void monitor_init_qmp_commands(void) { /* @@ -1184,8 +1164,6 @@ static void monitor_init_qmp_commands(void) qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add, QCO_NO_OPTIONS); -qmp_unregister_commands_hack(); - QTAILQ_INIT(&qmp_cap_negotiation_commands); qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities", qmp_marshal_qmp_capabilities, QCO_NO_OPTIONS); diff --git a/qmp.c b/qmp.c index 9ded2f48c4..cafda4417d 100644 --- a/qmp.c +++ b/qmp.c @@ -589,11 +589,6 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename, return prop_list; } -CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) -{ -return arch_query_cpu_definitions(errp); -} - void qmp_add_client(const char *protocol, const char *fdname, bool has_skipauth, bool skipauth, bool has_tls, bool tls, Error **errp) diff --git a/stubs/arch-query-cpu-def.c b/stubs/arch-query-cpu-def.c deleted file mode 100644 index d436f95314..00 --- a/stubs/arch-query-cpu-def.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "sysemu/arch_init.h" -#include "qapi/error.h" -#include "qapi/qmp/qerror.h" - -CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) -{ -error_setg(errp, QERR_UNSUPPORTED); -return NULL; -} diff --git a/target/arm/helper.c b/target/arm/helper.c index 09893e3f72..ab8520f07d 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -17,6 +17,7 @@ #include "exec/semihost.h" #include "sysemu/kvm.h" #include "fpu/softfloat.h" +#include "qapi/target-qapi-commands.h" #define ARM_CPU_FREQ 10 /* FIXME: 1 GHz,
[Qemu-devel] [PATCH v3 37/49] qapi: add conditions to REPLICATION type/commands on the schema
Add #if defined(CONFIG_REPLICATION) in generated code, and adjust the code accordingly. Made conditional: * xen-set-replication, query-xen-replication-status, xen-colo-do-checkpoint Before the patch, we first register the commands unconditionally in generated code (requires a stub), then conditionally unregister in qmp_unregister_commands_hack(). Afterwards, we register only when CONFIG_REPLICATION. The command fails exactly the same, with CommandNotFound. Improvement, because now query-qmp-schema is accurate, and we're one step closer to killing qmp_unregister_commands_hack(). * enum BlockdevDriver value "replication" in command blockdev-add * BlockdevOptions variant @replication And related structures. Signed-off-by: Marc-André Lureau --- qapi/block-core.json | 13 + qapi/migration.json | 12 migration/colo.c | 16 monitor.c| 5 - 4 files changed, 21 insertions(+), 25 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 1088ab0c78..c20d39049b 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2514,7 +2514,9 @@ 'dmg', 'file', 'ftp', 'ftps', 'gluster', 'host_cdrom', 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels', 'qcow', 'qcow2', 'qed', -'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh', +'quorum', 'raw', 'rbd', +{ 'name': 'replication', 'if': 'defined(CONFIG_REPLICATION)' }, +'sheepdog', 'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] } ## @@ -3228,7 +3230,8 @@ # # Since: 2.9 ## -{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ] } +{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ], + 'if': 'defined(CONFIG_REPLICATION)' } ## # @BlockdevOptionsReplication: @@ -3246,7 +3249,8 @@ { 'struct': 'BlockdevOptionsReplication', 'base': 'BlockdevOptionsGenericFormat', 'data': { 'mode': 'ReplicationMode', -'*top-id': 'str' } } +'*top-id': 'str' }, + 'if': 'defined(CONFIG_REPLICATION)' } ## # @NFSTransport: @@ -3545,7 +3549,8 @@ 'quorum': 'BlockdevOptionsQuorum', 'raw':'BlockdevOptionsRaw', 'rbd':'BlockdevOptionsRbd', - 'replication':'BlockdevOptionsReplication', + 'replication': { 'type': 'BlockdevOptionsReplication', + 'if': 'defined(CONFIG_REPLICATION)' }, 'sheepdog': 'BlockdevOptionsSheepdog', 'ssh':'BlockdevOptionsSsh', 'throttle': 'BlockdevOptionsThrottle', diff --git a/qapi/migration.json b/qapi/migration.json index 9d0bf82cf4..d2c6e4d646 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -1121,7 +1121,8 @@ # Since: 2.9 ## { 'command': 'xen-set-replication', - 'data': { 'enable': 'bool', 'primary': 'bool', '*failover' : 'bool' } } + 'data': { 'enable': 'bool', 'primary': 'bool', '*failover' : 'bool' }, + 'if': 'defined(CONFIG_REPLICATION)' } ## # @ReplicationStatus: @@ -1136,7 +1137,8 @@ # Since: 2.9 ## { 'struct': 'ReplicationStatus', - 'data': { 'error': 'bool', '*desc': 'str' } } + 'data': { 'error': 'bool', '*desc': 'str' }, + 'if': 'defined(CONFIG_REPLICATION)' } ## # @query-xen-replication-status: @@ -1153,7 +1155,8 @@ # Since: 2.9 ## { 'command': 'query-xen-replication-status', - 'returns': 'ReplicationStatus' } + 'returns': 'ReplicationStatus', + 'if': 'defined(CONFIG_REPLICATION)' } ## # @xen-colo-do-checkpoint: @@ -1169,4 +1172,5 @@ # # Since: 2.9 ## -{ 'command': 'xen-colo-do-checkpoint' } +{ 'command': 'xen-colo-do-checkpoint', + 'if': 'defined(CONFIG_REPLICATION)' } diff --git a/migration/colo.c b/migration/colo.c index 4381067ed4..2329e78e7f 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -24,7 +24,9 @@ #include "trace.h" #include "qemu/error-report.h" #include "migration/failover.h" +#ifdef CONFIG_REPLICATION #include "replication.h" +#endif static bool vmstate_loading; @@ -148,11 +150,11 @@ void colo_do_failover(MigrationState *s) } } +#ifdef CONFIG_REPLICATION void qmp_xen_set_replication(bool enable, bool primary, bool has_failover, bool failover, Error **errp) { -#ifdef CONFIG_REPLICATION ReplicationMode mode = primary ? REPLICATION_MODE_PRIMARY : REPLICATION_MODE_SECONDARY; @@ -171,14 +173,10 @@ void qmp_xen_set_replication(bool enable, bool primary, } replication_stop_all(failover, failover ? NULL : errp); } -#else -abort(); -#endif } ReplicationStatus *qmp_query_xen_replication_status(Error **errp) { -#ifdef CONFIG_REPLICATION Error *err = NULL; ReplicationStatus *s = g_new0(ReplicationStatus, 1); @@ -193,19 +191,13 @@ ReplicationStatus *qmp_query_xen_replication_stat
[Qemu-devel] [PATCH v3 45/49] qapi: make query-gic-capabilities depend on TARGET_ARM
Signed-off-by: Marc-André Lureau --- qapi/misc.json | 43 -- qapi/target.json | 45 monitor.c| 11 --- target/arm/monitor.c | 2 +- 4 files changed, 46 insertions(+), 55 deletions(-) diff --git a/qapi/misc.json b/qapi/misc.json index 1753a81b1e..a0032120da 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -2965,49 +2965,6 @@ ## { 'command': 'xen-load-devices-state', 'data': {'filename': 'str'} } -## -# @GICCapability: -# -# The struct describes capability for a specific GIC (Generic -# Interrupt Controller) version. These bits are not only decided by -# QEMU/KVM software version, but also decided by the hardware that -# the program is running upon. -# -# @version: version of GIC to be described. Currently, only 2 and 3 -#are supported. -# -# @emulated: whether current QEMU/hardware supports emulated GIC -#device in user space. -# -# @kernel: whether current QEMU/hardware supports hardware -#accelerated GIC device in kernel. -# -# Since: 2.6 -## -{ 'struct': 'GICCapability', - 'data': { 'version': 'int', -'emulated': 'bool', -'kernel': 'bool' } } - -## -# @query-gic-capabilities: -# -# This command is ARM-only. It will return a list of GICCapability -# objects that describe its capability bits. -# -# Returns: a list of GICCapability objects. -# -# Since: 2.6 -# -# Example: -# -# -> { "execute": "query-gic-capabilities" } -# <- { "return": [{ "version": 2, "emulated": true, "kernel": false }, -# { "version": 3, "emulated": false, "kernel": true } ] } -# -## -{ 'command': 'query-gic-capabilities', 'returns': ['GICCapability'] } - ## # @CpuInstanceProperties: # diff --git a/qapi/target.json b/qapi/target.json index be0ff84a6e..2ab18b38a9 100644 --- a/qapi/target.json +++ b/qapi/target.json @@ -294,3 +294,48 @@ 'modelb': 'CpuModelInfo' }, 'returns': 'CpuModelBaselineInfo', 'if': 'defined(TARGET_S390X)' } + +## +# @GICCapability: +# +# The struct describes capability for a specific GIC (Generic +# Interrupt Controller) version. These bits are not only decided by +# QEMU/KVM software version, but also decided by the hardware that +# the program is running upon. +# +# @version: version of GIC to be described. Currently, only 2 and 3 +#are supported. +# +# @emulated: whether current QEMU/hardware supports emulated GIC +#device in user space. +# +# @kernel: whether current QEMU/hardware supports hardware +#accelerated GIC device in kernel. +# +# Since: 2.6 +## +{ 'struct': 'GICCapability', + 'data': { 'version': 'int', +'emulated': 'bool', +'kernel': 'bool' }, + 'if': 'defined(TARGET_ARM)' } + +## +# @query-gic-capabilities: +# +# This command is ARM-only. It will return a list of GICCapability +# objects that describe its capability bits. +# +# Returns: a list of GICCapability objects. +# +# Since: 2.6 +# +# Example: +# +# -> { "execute": "query-gic-capabilities" } +# <- { "return": [{ "version": 2, "emulated": true, "kernel": false }, +# { "version": 3, "emulated": false, "kernel": true } ] } +# +## +{ 'command': 'query-gic-capabilities', 'returns': ['GICCapability'], + 'if': 'defined(TARGET_ARM)' } diff --git a/monitor.c b/monitor.c index bd9a6950cf..67b433f12d 100644 --- a/monitor.c +++ b/monitor.c @@ -1157,9 +1157,6 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data, */ static void qmp_unregister_commands_hack(void) { -#ifndef TARGET_ARM -qmp_unregister_command(&qmp_commands, "query-gic-capabilities"); -#endif #if !defined(TARGET_S390X) && !defined(TARGET_I386) qmp_unregister_command(&qmp_commands, "query-cpu-model-expansion"); #endif @@ -4696,14 +4693,6 @@ QemuOptsList qemu_mon_opts = { }, }; -#ifndef TARGET_ARM -GICCapabilityList *qmp_query_gic_capabilities(Error **errp) -{ -error_setg(errp, QERR_FEATURE_DISABLED, "query-gic-capabilities"); -return NULL; -} -#endif - HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); diff --git a/target/arm/monitor.c b/target/arm/monitor.c index 4cdd2676dd..250405bf4d 100644 --- a/target/arm/monitor.c +++ b/target/arm/monitor.c @@ -23,7 +23,7 @@ #include "qemu/osdep.h" #include "hw/boards.h" #include "kvm_arm.h" -#include "qapi/qapi-commands-misc.h" +#include "qapi/target-qapi-commands.h" static GICCapability *gic_cap_new(int version) { -- 2.16.2.521.g9aa15f885a
Re: [Qemu-devel] [PATCH v3 2/2] i386/kvm: lower requirements for Hyper-V frequency MSRs exposure
On Tue, Mar 20, 2018 at 06:35:00PM +0100, Vitaly Kuznetsov wrote: > Requiring tsc_is_stable_and_known() is too restrictive: even without INVTCS > nested Hyper-V-on-KVM enables TSC pages for its guests e.g. when > Reenlightenment MSRs are present. Presence of frequency MSRs doesn't mean > these frequencies are stable, it just means they're available for reading. > > Signed-off-by: Vitaly Kuznetsov > --- > target/i386/kvm.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/target/i386/kvm.c b/target/i386/kvm.c > index 7d9f9ca0b1..74fc3d3b2c 100644 > --- a/target/i386/kvm.c > +++ b/target/i386/kvm.c > @@ -651,7 +651,7 @@ static int hyperv_handle_properties(CPUState *cs) > env->features[FEAT_HYPERV_EAX] |= HV_TIME_REF_COUNT_AVAILABLE; > env->features[FEAT_HYPERV_EAX] |= HV_REFERENCE_TSC_AVAILABLE; > > -if (has_msr_hv_frequencies && tsc_is_stable_and_known(env)) { > +if (has_msr_hv_frequencies && env->tsc_khz) { > env->features[FEAT_HYPERV_EAX] |= HV_ACCESS_FREQUENCY_MSRS; > env->features[FEAT_HYPERV_EDX] |= HV_FREQUENCY_MSRS_AVAILABLE; > } I suggest that we add a corresponding cpu property here, too. The guest may legitimately rely on these msrs when it sees the support in CPUID, and migrating from a kernel with the feature supported (4.14+) to an older one will make it crash. Roman.
[Qemu-devel] [PATCH v3 48/49] qapi: remove qmp_unregister_command()
This command is no longer needed after the schema is made conditional. Signed-off-by: Marc-André Lureau --- include/qapi/qmp/dispatch.h | 1 - qapi/qmp-registry.c | 8 2 files changed, 9 deletions(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index ffb4652f71..dba9ee70b3 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -38,7 +38,6 @@ typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList; void qmp_register_command(QmpCommandList *cmds, const char *name, QmpCommandFunc *fn, QmpCommandOptions options); -void qmp_unregister_command(QmpCommandList *cmds, const char *name); QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name); QObject *qmp_dispatch(QmpCommandList *cmds, QObject *request); void qmp_disable_command(QmpCommandList *cmds, const char *name); diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c index 5af484cd9a..ca00f74795 100644 --- a/qapi/qmp-registry.c +++ b/qapi/qmp-registry.c @@ -27,14 +27,6 @@ void qmp_register_command(QmpCommandList *cmds, const char *name, QTAILQ_INSERT_TAIL(cmds, cmd, node); } -void qmp_unregister_command(QmpCommandList *cmds, const char *name) -{ -QmpCommand *cmd = qmp_find_command(cmds, name); - -QTAILQ_REMOVE(cmds, cmd, node); -g_free(cmd); -} - QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name) { QmpCommand *cmd; -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PATCH v3 39/49] qapi-commands: don't initialize command list in qmp_init_marshall()
This will let the caller add several list of commands coming from different schemas (the following patches split the schemas for common and arch-specific parts). Signed-off-by: Marc-André Lureau --- scripts/qapi/commands.py | 2 -- monitor.c| 1 + qga/main.c | 1 + tests/test-qmp-cmds.c| 1 + 4 files changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index 40bb680b7c..3d3e97f737 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -220,8 +220,6 @@ def gen_registry(registry, prefix): void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds) { -QTAILQ_INIT(cmds); - ''', c_prefix=c_name(prefix, protect=False)) ret += registry diff --git a/monitor.c b/monitor.c index 88e6fd2e6f..0d84c3edb4 100644 --- a/monitor.c +++ b/monitor.c @@ -1121,6 +1121,7 @@ static void monitor_init_qmp_commands(void) * "qmp_capabilities", to enforce capability negotiation */ +QTAILQ_INIT(&qmp_commands); qmp_init_marshal(&qmp_commands); qmp_register_command(&qmp_commands, "query-qmp-schema", diff --git a/qga/main.c b/qga/main.c index df1888edc1..6905c82b6c 100644 --- a/qga/main.c +++ b/qga/main.c @@ -1364,6 +1364,7 @@ int main(int argc, char **argv) config->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL; +QTAILQ_INIT(&ga_commands); qga_qmp_init_marshal(&ga_commands); init_dfl_pathnames(); diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c index e675722593..e723b440ca 100644 --- a/tests/test-qmp-cmds.c +++ b/tests/test-qmp-cmds.c @@ -285,6 +285,7 @@ int main(int argc, char **argv) g_test_add_func("/0.15/dealloc_types", test_dealloc_types); g_test_add_func("/0.15/dealloc_partial", test_dealloc_partial); +QTAILQ_INIT(&qmp_commands); test_qmp_init_marshal(&qmp_commands); g_test_run(); -- 2.16.2.521.g9aa15f885a
[Qemu-devel] [PULL v1 3/4] tpm: CRB: reset locAssigned upon relinquishing locality
Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_crb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index 4bd76b5..e8c42f6 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -137,6 +137,8 @@ static void tpm_crb_mmio_write(void *opaque, hwaddr addr, /* not loc 3 or 4 */ break; case CRB_LOC_CTRL_RELINQUISH: +ARRAY_FIELD_DP32(s->regs, CRB_LOC_STATE, + locAssigned, 0); break; case CRB_LOC_CTRL_REQUEST_ACCESS: ARRAY_FIELD_DP32(s->regs, CRB_LOC_STS, -- 2.5.5
Re: [Qemu-devel] [PATCH] scsi: turn "is this a SCSI device?" into a conditional hint
On 21/03/2018 11:58, Paolo Bonzini wrote: > If the user does not have permissions to send ioctls to the device (due to > SELinux or cgroups, for example), the output can look like > > qemu-kvm: -device scsi-block,drive=disk: cannot get SG_IO version number: > Operation not permitted. Is this a SCSI device? > > but this is confusing because the ioctl was blocked _before_ the device > even received the SG_GET_VERSION_NUM ioctl. Therefore, for EPERM errors > the suggestion should be eliminated. To make that simpler, change the > code to use error_append_hint. > > Reported-by: Ala Hino > Signed-off-by: Paolo Bonzini > --- > hw/scsi/scsi-disk.c| 7 --- > hw/scsi/scsi-generic.c | 7 --- > 2 files changed, 8 insertions(+), 6 deletions(-) > > diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c > index 94043ed024..ccc245589a 100644 > --- a/hw/scsi/scsi-disk.c > +++ b/hw/scsi/scsi-disk.c > @@ -2637,9 +2637,10 @@ static void scsi_block_realize(SCSIDevice *dev, Error > **errp) > /* check we are using a driver managing SG_IO (version 3 and after) */ > rc = blk_ioctl(s->qdev.conf.blk, SG_GET_VERSION_NUM, &sg_version); > if (rc < 0) { > -error_setg(errp, "cannot get SG_IO version number: %s. " > - "Is this a SCSI device?", > - strerror(-rc)); > +error_setg(errp, "cannot get SG_IO version number: %s", > strerror(-rc)); You could use: error_setg_errno(errp, -rc, "cannot get SG_IO version number"); Thanks, Laurent
[Qemu-devel] [PULL v1 2/4] tpm: CRB: set registers to 0 by default
Initialize all registers of the CRB device to 0. This clears a few flags upon a reset. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_crb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index 114b66e..4bd76b5 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -208,6 +208,8 @@ static void tpm_crb_reset(void *dev) tpm_backend_reset(s->tpmbe); +memset(s->regs, 0, sizeof(s->regs)); + ARRAY_FIELD_DP32(s->regs, CRB_LOC_STATE, tpmRegValidSts, 1); ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID, -- 2.5.5
Re: [Qemu-devel] [PATCH v1 3/6] migration: calculate vCPU blocktime on dst side
* Alexey Perevalov (a.pereva...@samsung.com) wrote: > This patch provides blocktime calculation per vCPU, > as a summary and as a overlapped value for all vCPUs. > > This approach was suggested by Peter Xu, as an improvements of > previous approch where QEMU kept tree with faulted page address and cpus > bitmask > in it. Now QEMU is keeping array with faulted page address as value and vCPU > as index. It helps to find proper vCPU at UFFD_COPY time. Also it keeps > list for blocktime per vCPU (could be traced with page_fault_addr) > > Blocktime will not calculated if postcopy_blocktime field of > MigrationIncomingState wasn't initialized. > > Signed-off-by: Alexey Perevalov > Reviewed-by: Dr. David Alan Gilbert > Reviewed-by: Juan Quintela > Signed-off-by: Juan Quintela > --- > migration/postcopy-ram.c | 149 > ++- > migration/trace-events | 5 +- > 2 files changed, 152 insertions(+), 2 deletions(-) > > diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c > index 9144102..9e51e84 100644 > --- a/migration/postcopy-ram.c > +++ b/migration/postcopy-ram.c > @@ -546,6 +546,148 @@ static int ram_block_enable_notify(const char > *block_name, void *host_addr, > return 0; > } > > +static int get_mem_fault_cpu_index(uint32_t pid) > +{ > +CPUState *cpu_iter; > + > +CPU_FOREACH(cpu_iter) { > +if (cpu_iter->thread_id == pid) { > +trace_get_mem_fault_cpu_index(cpu_iter->cpu_index, pid); > +return cpu_iter->cpu_index; > +} > +} > +trace_get_mem_fault_cpu_index(-1, pid); > +return -1; > +} > + > +static uint32_t get_low_time_offset(PostcopyBlocktimeContext *dc) > +{ > +int64_t start_time_offset = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - > +dc->start_time; > +return start_time_offset < 1 ? 1 : start_time_offset & UINT32_MAX; > +} > + > +/* > + * This function is being called when pagefault occurs. It > + * tracks down vCPU blocking time. > + * > + * @addr: faulted host virtual address > + * @ptid: faulted process thread id > + * @rb: ramblock appropriate to addr > + */ > +static void mark_postcopy_blocktime_begin(uintptr_t addr, uint32_t ptid, > + RAMBlock *rb) > +{ > +int cpu, already_received; > +MigrationIncomingState *mis = migration_incoming_get_current(); > +PostcopyBlocktimeContext *dc = mis->blocktime_ctx; > +uint32_t low_time_offset; > + > +if (!dc || ptid == 0) { > +return; > +} > +cpu = get_mem_fault_cpu_index(ptid); > +if (cpu < 0) { > +return; > +} > + > +low_time_offset = get_low_time_offset(dc); > +if (dc->vcpu_addr[cpu] == 0) { > +atomic_inc(&dc->smp_cpus_down); > +} > + > +atomic_xchg(&dc->last_begin, low_time_offset); > +atomic_xchg(&dc->page_fault_vcpu_time[cpu], low_time_offset); > +atomic_xchg(&dc->vcpu_addr[cpu], addr); > + > +/* check it here, not at the begining of the function, > + * due to, check could accur early than bitmap_set in > + * qemu_ufd_copy_ioctl */ > +already_received = ramblock_recv_bitmap_test(rb, (void *)addr); > +if (already_received) { > +atomic_xchg__nocheck(&dc->vcpu_addr[cpu], 0); > +atomic_xchg__nocheck(&dc->page_fault_vcpu_time[cpu], 0); Those don't need to be __nocheck do they? vcpu_addr is uintptr_t so I think should always be the right size, and page_fault_vcpu_time is uint32_t now, so again should be fine (and same below). Dave > +atomic_dec(&dc->smp_cpus_down); > +} > +trace_mark_postcopy_blocktime_begin(addr, dc, > dc->page_fault_vcpu_time[cpu], > +cpu, already_received); > +} > + > +/* > + * This function just provide calculated blocktime per cpu and trace it. > + * Total blocktime is calculated in mark_postcopy_blocktime_end. > + * > + * > + * Assume we have 3 CPU > + * > + * S1E1 S1 E1 > + * -***xxx***> > CPU1 > + * > + * S2E2 > + * xxx---> > CPU2 > + * > + * S3E3 > + * xxx---> > CPU3 > + * > + * We have sequence S1,S2,E1,S3,S1,E2,E3,E1 > + * S2,E1 - doesn't match condition due to sequence S1,S2,E1 doesn't include > CPU3 > + * S3,S1,E2 - sequence includes all CPUs, in this case overlap will be S1,E2 > - > + *it's a part of total blocktime. > + * S1 - here is last_begin > + * Legend of the picture is following: > + * * - means blocktime per vCPU > + * x - means overlapped blocktime (total blocktime) > + * > + * @addr: host virtual address > + */ > +static void mark_postcopy_blocktime_end(uintptr_t addr) > +{ > +MigrationIncomingState *mis
[Qemu-devel] [PATCH v3 40/49] RFC: qapi: learn to split schema by 'top-unit'
Another take at making the schema modular, this time by introducing the concept of a 'top-unit'. With this approach, each module is part of a top-unit, which is visited first before visiting the module themselfs. The default 'top-unit' is None. Else, a module belong to a 'top-unit' whose name is given by the 'top-unit' pragma value. This gives a chance to the generators to break generated output into different files. The point of this excercice is to have modules that can be compiled per qemu targets, instead of everything belonging to the top schema without the right to use poisoin defines for conditional compilation. Generated types, visitors, events and commands are split by 'top-unit'. The generated introspection and documentation remain monolithic. TODO: if this approach is acceptable, write tests & doc. Signed-off-by: Marc-André Lureau --- scripts/qapi/commands.py | 22 +--- scripts/qapi/common.py | 105 +++ scripts/qapi/events.py | 33 scripts/qapi/types.py| 8 +-- scripts/qapi/visit.py| 8 +-- 5 files changed, 129 insertions(+), 47 deletions(-) diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index 3d3e97f737..3ca36fc33b 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -235,14 +235,20 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor): QAPISchemaModularCVisitor.__init__( self, prefix, 'qapi-commands', ' * Schema-defined QAPI/QMP commands', __doc__) + +def visit_unit_begin(self, unit): +super(self.__class__, self).visit_unit_begin(unit) self._regy = QAPIGenCSnippet() self._visited_ret_types = {} -def _begin_module(self, name): +def _begin_module(self, name, main_module): self._visited_ret_types[self._genc] = set() -commands = self._module_basename('qapi-commands', name) -types = self._module_basename('qapi-types', name) -visit = self._module_basename('qapi-visit', name) +commands = self._module_basename('qapi-commands', name, + self._unit, main_module) +types = self._module_basename('qapi-types', name, + self._unit, main_module) +visit = self._module_basename('qapi-visit', name, + self._unit, main_module) self._genc.add(mcgen(''' #include "qemu/osdep.h" #include "qemu-common.h" @@ -265,13 +271,13 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor): ''', types=types)) -def visit_end(self): -(genc, genh) = self._module[self._main_module] +def visit_unit_end(self): +(genc, genh) = self.get_module_gen(self._main_module) genh.add(mcgen(''' void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds); ''', - c_prefix=c_name(self._prefix, protect=False))) -genc.add(gen_registry(self._regy.get_content(), self._prefix)) + c_prefix=c_name(self._prefix_unit(), protect=False))) +genc.add(gen_registry(self._regy.get_content(), self._prefix_unit())) def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob): diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 174b39ea50..bff8de05d1 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -271,11 +271,12 @@ class QAPISchemaParser(object): self.exprs = [] self.docs = [] self.accept() +self._top_unit = None cur_doc = None while self.tok is not None: info = {'file': self.fname, 'line': self.line, -'parent': self.incl_info} +'parent': self.incl_info, 'top-unit': self._top_unit} if self.tok == '#': self.reject_expr_doc(cur_doc) cur_doc = self.get_doc(info) @@ -298,6 +299,9 @@ class QAPISchemaParser(object): exprs_include = self._include(include, info, incl_fname, previously_included) if exprs_include: +incl_info = self.exprs[-1]['info'] +if exprs_include._top_unit: +incl_info['has-pragma-top-unit'] = exprs_include._top_unit self.exprs.extend(exprs_include.exprs) self.docs.extend(exprs_include.docs) elif "pragma" in expr: @@ -356,6 +360,11 @@ class QAPISchemaParser(object): raise QAPISemError(info, "Pragma 'doc-required' must be boolean") doc_required = value +elif name == 'top-unit': +if not isinstance(value, str): +raise QAPISemError(info, + "Pragma 'top-unit' must be a
[Qemu-devel] [PATCH] dump: display cause of write failure
Use error_setg_errno() to display the reason why data write has failed. For instance, instead of a laconic dump: failed to write elf header or dump: failed to save memory we have now: dump: failed to write elf header: No space left on device or dump: failed to save memory: No space left on device CC: Yasmin Beatriz CC: Jose Ricardo Ziviani Suggested-by: Eric Blake Signed-off-by: Laurent Vivier --- dump.c | 79 +++--- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/dump.c b/dump.c index 6bdb0dbe23..d04e3f56b0 100644 --- a/dump.c +++ b/dump.c @@ -140,7 +140,7 @@ static void write_elf64_header(DumpState *s, Error **errp) ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); if (ret < 0) { -error_setg(errp, "dump: failed to write elf header"); +error_setg_errno(errp, errno, "dump: failed to write elf header"); } } @@ -171,7 +171,7 @@ static void write_elf32_header(DumpState *s, Error **errp) ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); if (ret < 0) { -error_setg(errp, "dump: failed to write elf header"); +error_setg_errno(errp, errno, "dump: failed to write elf header"); } } @@ -194,7 +194,8 @@ static void write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); if (ret < 0) { -error_setg(errp, "dump: failed to write program header table"); +error_setg_errno(errp, errno, + "dump: failed to write program header table"); } } @@ -217,7 +218,8 @@ static void write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); if (ret < 0) { -error_setg(errp, "dump: failed to write program header table"); +error_setg_errno(errp, errno, + "dump: failed to write program header table"); } } @@ -237,7 +239,8 @@ static void write_elf64_note(DumpState *s, Error **errp) ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); if (ret < 0) { -error_setg(errp, "dump: failed to write program header table"); +error_setg_errno(errp, errno, + "dump: failed to write program header table"); } } @@ -254,7 +257,7 @@ static void write_guest_note(WriteCoreDumpFunction f, DumpState *s, if (s->guest_note) { ret = f(s->guest_note, s->guest_note_size, s); if (ret < 0) { -error_setg(errp, "dump: failed to write guest note"); +error_setg_errno(errp, errno, "dump: failed to write guest note"); } } } @@ -270,7 +273,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, id = cpu_index(cpu); ret = cpu_write_elf64_note(f, cpu, id, s); if (ret < 0) { -error_setg(errp, "dump: failed to write elf notes"); +error_setg_errno(errp, errno, "dump: failed to write elf notes"); return; } } @@ -278,7 +281,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, CPU_FOREACH(cpu) { ret = cpu_write_elf64_qemunote(f, cpu, s); if (ret < 0) { -error_setg(errp, "dump: failed to write CPU status"); +error_setg_errno(errp, errno, "dump: failed to write CPU status"); return; } } @@ -302,7 +305,8 @@ static void write_elf32_note(DumpState *s, Error **errp) ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); if (ret < 0) { -error_setg(errp, "dump: failed to write program header table"); +error_setg_errno(errp, errno, + "dump: failed to write program header table"); } } @@ -317,7 +321,7 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, id = cpu_index(cpu); ret = cpu_write_elf32_note(f, cpu, id, s); if (ret < 0) { -error_setg(errp, "dump: failed to write elf notes"); +error_setg_errno(errp, errno, "dump: failed to write elf notes"); return; } } @@ -325,7 +329,7 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, CPU_FOREACH(cpu) { ret = cpu_write_elf32_qemunote(f, cpu, s); if (ret < 0) { -error_setg(errp, "dump: failed to write CPU status"); +error_setg_errno(errp, errno, "dump: failed to write CPU status"); return; } } @@ -355,7 +359,8 @@ static void write_elf_section(DumpState *s, int type, Error **errp) ret = fd_write_vmcore(&shdr, shdr_size, s); if (ret < 0) { -error_setg(errp, "dump: failed to write section header table"); +error_setg_errno(errp, errno, + "dump: failed to write section header table"); } } @@ -365,7 +370,7 @@ static void write_data(
[Qemu-devel] [PATCH v3 46/49] qapi: make query-cpu-model-expansion depend on s390 or x86
Signed-off-by: Marc-André Lureau Reviewed-by: Eduardo Habkost Acked-by: Cornelia Huck --- qapi/misc.json | 38 - qapi/target.json | 39 ++ include/sysemu/arch_init.h | 3 -- monitor.c | 3 -- qmp.c | 7 - stubs/arch-query-cpu-model-expansion.c | 13 - target/i386/cpu.c | 3 +- target/s390x/cpu_models.c | 2 +- stubs/Makefile.objs| 1 - 9 files changed, 42 insertions(+), 67 deletions(-) delete mode 100644 stubs/arch-query-cpu-model-expansion.c diff --git a/qapi/misc.json b/qapi/misc.json index a0032120da..602c99b174 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -2102,44 +2102,6 @@ 'data': { 'model': 'CpuModelInfo' } } -## -# @query-cpu-model-expansion: -# -# Expands a given CPU model (or a combination of CPU model + additional options) -# to different granularities, allowing tooling to get an understanding what a -# specific CPU model looks like in QEMU under a certain configuration. -# -# This interface can be used to query the "host" CPU model. -# -# The data returned by this command may be affected by: -# -# * QEMU version: CPU models may look different depending on the QEMU version. -# (Except for CPU models reported as "static" in query-cpu-definitions.) -# * machine-type: CPU model may look different depending on the machine-type. -# (Except for CPU models reported as "static" in query-cpu-definitions.) -# * machine options (including accelerator): in some architectures, CPU models -# may look different depending on machine and accelerator options. (Except for -# CPU models reported as "static" in query-cpu-definitions.) -# * "-cpu" arguments and global properties: arguments to the -cpu option and -# global properties may affect expansion of CPU models. Using -# query-cpu-model-expansion while using these is not advised. -# -# Some architectures may not support all expansion types. s390x supports -# "full" and "static". -# -# Returns: a CpuModelExpansionInfo. Returns an error if expanding CPU models is -# not supported, if the model cannot be expanded, if the model contains -# an unknown CPU definition name, unknown properties or properties -# with a wrong type. Also returns an error if an expansion type is -# not supported. -# -# Since: 2.8.0 -## -{ 'command': 'query-cpu-model-expansion', - 'data': { 'type': 'CpuModelExpansionType', -'model': 'CpuModelInfo' }, - 'returns': 'CpuModelExpansionInfo' } - ## # @CpuModelCompareResult: # diff --git a/qapi/target.json b/qapi/target.json index 2ab18b38a9..323994a6ec 100644 --- a/qapi/target.json +++ b/qapi/target.json @@ -339,3 +339,42 @@ ## { 'command': 'query-gic-capabilities', 'returns': ['GICCapability'], 'if': 'defined(TARGET_ARM)' } + +## +# @query-cpu-model-expansion: +# +# Expands a given CPU model (or a combination of CPU model + additional options) +# to different granularities, allowing tooling to get an understanding what a +# specific CPU model looks like in QEMU under a certain configuration. +# +# This interface can be used to query the "host" CPU model. +# +# The data returned by this command may be affected by: +# +# * QEMU version: CPU models may look different depending on the QEMU version. +# (Except for CPU models reported as "static" in query-cpu-definitions.) +# * machine-type: CPU model may look different depending on the machine-type. +# (Except for CPU models reported as "static" in query-cpu-definitions.) +# * machine options (including accelerator): in some architectures, CPU models +# may look different depending on machine and accelerator options. (Except for +# CPU models reported as "static" in query-cpu-definitions.) +# * "-cpu" arguments and global properties: arguments to the -cpu option and +# global properties may affect expansion of CPU models. Using +# query-cpu-model-expansion while using these is not advised. +# +# Some architectures may not support all expansion types. s390x supports +# "full" and "static". +# +# Returns: a CpuModelExpansionInfo. Returns an error if expanding CPU models is +# not supported, if the model cannot be expanded, if the model contains +# an unknown CPU definition name, unknown properties or properties +# with a wrong type. Also returns an error if an expansion type is +# not supported. +# +# Since: 2.8.0 +## +{ 'command': 'query-cpu-model-expansion', + 'data': { 'type': 'CpuModelExpansionType', +'model': 'CpuModelInfo' }, + 'returns': 'CpuModelExpansionInfo', + 'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' } diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index f0ef652b2a..2497fd3351 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -33,7 +33,4
[Qemu-devel] [PATCH for-2.13 0/4] NBD export bitmaps
Hi all. This is a proposal and realization of new NBD meta context: qemu-dirty-bitmap. (I'll send corresponding proposal to NBD protocol after some negotiation here) Corresponding queries will look like: qemu-dirty-bitmap: Mapping from export-bitmap-name to BdrvDirtyBitmap is done through qmp command nbd-server-add-bitmap. For now, only one bitmap export is allowed per NBD export, however it may be easily improved if needed (we don't have such cases for now) Client and testing. I wrote client code for Virtuozzo, but it turned out to be unused, actually it's used only for tests. We don't have cases, where we need to import dirty bitmap through qemu nbd-client. All this done for exporting dirty bitmaps to the third tool. So, I think, it is not worth refactoring, rebasing and merging client part upstream, if there are no real usage cases. Vladimir Sementsov-Ogievskiy (4): nbd/server: refactor nbd_negotiate_meta_query for several namespaces nbd/server: add nbd_meta_single_query helper nbd/server: implement dirty bitmap export qapi: new qmp command nbd-server-add-bitmap qapi/block.json | 27 + include/block/nbd.h | 2 + blockdev-nbd.c | 23 nbd/server.c| 308 ++-- 4 files changed, 324 insertions(+), 36 deletions(-) -- 2.11.1
[Qemu-devel] [PULL v1 0/4] Merge tpm 2018/03/21
This series of patches fixes the initialization and setting of a few flags of the TPM CRB interface. The following changes since commit f1a63fcfcd92c88be8942b5ae71aef9749a4f135: Update version for v2.12.0-rc0 release (2018-03-20 19:04:22 +) are available in the git repository at: git://github.com/stefanberger/qemu-tpm.git tags/pull-tpm-2018-03-21-1 for you to fetch changes up to ffbf24bdb223914d5805fef15bfe9c4489868fad: tpm: CRB: query backend for TPM established flag (2018-03-21 08:01:03 -0400) Stefan Berger (4): tpm: CRB: Set tpmRegValidSts flag to '1' in device reset tpm: CRB: set registers to 0 by default tpm: CRB: reset locAssigned upon relinquishing locality tpm: CRB: query backend for TPM established flag hw/tpm/tpm_crb.c | 14 -- 1 file changed, 12 insertions(+), 2 deletions(-) -- 2.5.5
[Qemu-devel] [PATCH 4/4] qapi: new qmp command nbd-server-add-bitmap
Signed-off-by: Vladimir Sementsov-Ogievskiy --- qapi/block.json | 27 +++ blockdev-nbd.c | 23 +++ 2 files changed, 50 insertions(+) diff --git a/qapi/block.json b/qapi/block.json index c694524002..4afbbcd7b7 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -269,6 +269,33 @@ 'data': {'name': 'str', '*mode': 'NbdServerRemoveMode'} } ## +# @nbd-server-add-bitmap: +# +# Export dirty bitmap through selected export. Bitmaps are searched for in +# device attached to the export and in all its backings. Exported bitmap +# is locked until NBD export is removed. +# +# @name: Export name. +# +# @bitmap: Bitmap name to search. +# +# @bitmap-export-name: How the bitmap will be seen by nbd clients +# (default @bitmap) +# +# +# Returns: error on one of the following conditions: +# - the server is not running +# - export is not found +# - bitmap is not found +# - bitmap is disabled +# - bitmap is locked +# +# Since: 2.13 +## + { 'command': 'nbd-server-add-bitmap', +'data': {'name': 'str', 'bitmap': 'str', '*bitmap-export-name': 'str'} } + +## # @nbd-server-stop: # # Stop QEMU's embedded NBD server, and unregister all devices previously diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 65a84739ed..6b0c50732c 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -220,3 +220,26 @@ void qmp_nbd_server_stop(Error **errp) nbd_server_free(nbd_server); nbd_server = NULL; } + +void qmp_nbd_server_add_bitmap(const char *name, const char *bitmap, + bool has_bitmap_export_name, + const char *bitmap_export_name, + Error **errp) +{ +NBDExport *exp; + +if (!nbd_server) { +error_setg(errp, "NBD server not running"); +return; +} + +exp = nbd_export_find(name); +if (exp == NULL) { +error_setg(errp, "Export '%s' is not found", name); +return; +} + +nbd_export_bitmap(exp, bitmap, + has_bitmap_export_name ? bitmap_export_name : bitmap, + errp); +} -- 2.11.1
[Qemu-devel] [PATCH 3/4] nbd/server: implement dirty bitmap export
Signed-off-by: Vladimir Sementsov-Ogievskiy --- include/block/nbd.h | 2 + nbd/server.c| 207 ++-- 2 files changed, 203 insertions(+), 6 deletions(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index fcdcd54502..f0b459283f 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -315,6 +315,8 @@ void nbd_client_put(NBDClient *client); void nbd_server_start(SocketAddress *addr, const char *tls_creds, Error **errp); +void nbd_export_bitmap(NBDExport *exp, const char *bitmap, + const char *bitmap_export_name, Error **errp); /* nbd_read * Reads @size bytes from @ioc. Returns 0 on success. diff --git a/nbd/server.c b/nbd/server.c index 8fe53ffd4b..6554919ef2 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -23,6 +23,12 @@ #include "nbd-internal.h" #define NBD_META_ID_BASE_ALLOCATION 0 +#define NBD_META_ID_DIRTY_BITMAP 1 + +#define NBD_MAX_BITMAP_EXTENTS (0x10 / 8) /* 1 mb of extents data */ +#define MAX_EXTENT_LENGTH QEMU_ALIGN_DOWN(INT32_MAX, 512) + +#define NBD_STATE_DIRTY 1 static int system_errno_to_nbd_errno(int err) { @@ -80,6 +86,9 @@ struct NBDExport { BlockBackend *eject_notifier_blk; Notifier eject_notifier; + +BdrvDirtyBitmap *export_bitmap; +char *export_bitmap_name; }; static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports); @@ -92,6 +101,7 @@ typedef struct NBDExportMetaContexts { bool valid; /* means that negotiation of the option finished without errors */ bool base_allocation; /* export base:allocation context (block status) */ +bool dirty_bitmap; /* export qemu-dirty-bitmap: */ } NBDExportMetaContexts; struct NBDClient { @@ -786,12 +796,32 @@ static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, &meta->base_allocation, errp); } +/* nbd_meta_bitmap_query + * + * Handle query to 'qemu-dirty-bitmap' namespace. + * 'len' is the amount of text remaining to be read from the current name, after + * the 'qemu-dirty-bitmap:' portion has been stripped. + * + * Return -errno on I/O error, 0 if option was completely handled by + * sending a reply about inconsistent lengths, or 1 on success. */ +static int nbd_meta_bitmap_query(NBDClient *client, NBDExportMetaContexts *meta, + uint32_t len, Error **errp) +{ +if (!client->exp->export_bitmap) { +return nbd_opt_skip(client, len, errp); +} + +return nbd_meta_single_query(client, client->exp->export_bitmap_name, len, + &meta->dirty_bitmap, errp); +} + struct { const char *ns; int (*func)(NBDClient *, NBDExportMetaContexts *, uint32_t, Error **); } meta_namespace_handlers[] = { /* namespaces should go in non-decreasing order by name length */ {.ns = "base:", .func = nbd_meta_base_query}, +{.ns = "qemu-dirty-bitmap:", .func = nbd_meta_bitmap_query}, }; /* nbd_negotiate_meta_query @@ -921,6 +951,17 @@ static int nbd_negotiate_meta_queries(NBDClient *client, } } +if (meta->dirty_bitmap) { +char *context = g_strdup_printf("qemu-dirty-bitmap:%s", +exp->export_bitmap_name); +ret = nbd_negotiate_send_meta_context(client, context, + NBD_META_ID_DIRTY_BITMAP, + errp); +if (ret < 0) { +return ret; +} +} + ret = nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); if (ret == 0) { meta->valid = true; @@ -1549,6 +1590,11 @@ void nbd_export_put(NBDExport *exp) exp->blk = NULL; } +if (exp->export_bitmap) { +bdrv_dirty_bitmap_set_qmp_locked(exp->export_bitmap, false); +g_free(exp->export_bitmap_name); +} + g_free(exp); } } @@ -1790,6 +1836,9 @@ static int blockstatus_to_extent_be(BlockDriverState *bs, uint64_t offset, } /* nbd_co_send_extents + * + * NBD_REPLY_FLAG_DONE is not set, don't forget to send it. + * * @extents should be in big-endian */ static int nbd_co_send_extents(NBDClient *client, uint64_t handle, NBDExtent *extents, unsigned nb_extents, @@ -1802,7 +1851,7 @@ static int nbd_co_send_extents(NBDClient *client, uint64_t handle, {.iov_base = extents, .iov_len = nb_extents * sizeof(extents[0])} }; -set_be_chunk(&chunk.h, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_BLOCK_STATUS, +set_be_chunk(&chunk.h, 0, NBD_REPLY_TYPE_BLOCK_STATUS, handle, sizeof(chunk) - sizeof(chunk.h) + iov[1].iov_len); stl_be_p(&chunk.context_id, context_id); @@ -1827,6 +1876,91 @@ static int nbd_co_send_block_status(NBDClient *client, uint64_t handle, return nbd_co_send_extents(client, handle, &extent, 1, context_id, errp); }
[Qemu-devel] [PATCH 1/4] nbd/server: refactor nbd_negotiate_meta_query for several namespaces
Signed-off-by: Vladimir Sementsov-Ogievskiy --- nbd/server.c | 60 +++- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index cea158913b..b830997114 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -771,13 +771,19 @@ static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, return 1; } +struct { +const char *ns; +int (*func)(NBDClient *, NBDExportMetaContexts *, uint32_t, Error **); +} meta_namespace_handlers[] = { +/* namespaces should go in non-decreasing order by name length */ +{.ns = "base:", .func = nbd_meta_base_query}, +}; + /* nbd_negotiate_meta_query * * Parse namespace name and call corresponding function to parse body of the * query. * - * The only supported namespace now is 'base'. - * * The function aims not wasting time and memory to read long unknown namespace * names. * @@ -787,9 +793,12 @@ static int nbd_negotiate_meta_query(NBDClient *client, NBDExportMetaContexts *meta, Error **errp) { int ret; -char query[sizeof("base:") - 1]; -size_t baselen = strlen("base:"); +int i; uint32_t len; +int bytes_done = 0; +char *query; +int nb_ns = sizeof(meta_namespace_handlers) / +sizeof(meta_namespace_handlers[0]); ret = nbd_opt_read(client, &len, sizeof(len), errp); if (ret <= 0) { @@ -797,22 +806,39 @@ static int nbd_negotiate_meta_query(NBDClient *client, } cpu_to_be32s(&len); -/* The only supported namespace for now is 'base'. So query should start - * with 'base:'. Otherwise, we can ignore it and skip the remainder. */ -if (len < baselen) { -return nbd_opt_skip(client, len, errp); -} +query = g_malloc(strlen(meta_namespace_handlers[nb_ns - 1].ns)); -len -= baselen; -ret = nbd_opt_read(client, query, baselen, errp); -if (ret <= 0) { -return ret; -} -if (strncmp(query, "base:", baselen) != 0) { -return nbd_opt_skip(client, len, errp); +for (i = 0; i < nb_ns; i++) { +const char *ns = meta_namespace_handlers[i].ns; +int ns_len = strlen(ns); +int diff_len = strlen(ns) - bytes_done; + +assert(diff_len >= 0); + +if (diff_len > 0) { +if (len < diff_len) { +ret = nbd_opt_skip(client, len, errp); +goto out; +} + +len -= diff_len; +ret = nbd_opt_read(client, query + bytes_done, diff_len, errp); +if (ret <= 0) { +goto out; +} +} + +if (!strncmp(query, ns, ns_len)) { +ret = meta_namespace_handlers[i].func(client, meta, len, errp); +goto out; +} } -return nbd_meta_base_query(client, meta, len, errp); +ret = nbd_opt_skip(client, len, errp); + +out: +g_free(query); +return ret; } /* nbd_negotiate_meta_queries -- 2.11.1
[Qemu-devel] [PATCH 2/4] nbd/server: add nbd_meta_single_query helper
The helper will be reused for bitmaps namespace. Signed-off-by: Vladimir Sementsov-Ogievskiy --- nbd/server.c | 41 - 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index b830997114..8fe53ffd4b 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -733,44 +733,59 @@ static int nbd_negotiate_send_meta_context(NBDClient *client, return qio_channel_writev_all(client->ioc, iov, 2, errp) < 0 ? -EIO : 0; } -/* nbd_meta_base_query - * - * Handle query to 'base' namespace. For now, only base:allocation context is - * available in it. 'len' is the amount of text remaining to be read from - * the current name, after the 'base:' portion has been stripped. +/* Read len bytes and check matching to the pattern. + * @match is set to true on empty query for _LIST_ and for query matching the + * @pattern. @match is never set to false. * * Return -errno on I/O error, 0 if option was completely handled by * sending a reply about inconsistent lengths, or 1 on success. */ -static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, - uint32_t len, Error **errp) +static int nbd_meta_single_query(NBDClient *client, const char *pattern, + uint32_t len, bool *match, Error **errp) { int ret; -char query[sizeof("allocation") - 1]; -size_t alen = strlen("allocation"); +char *query; if (len == 0) { if (client->opt == NBD_OPT_LIST_META_CONTEXT) { -meta->base_allocation = true; +*match = true; } return 1; } -if (len != alen) { +if (len != strlen(pattern)) { return nbd_opt_skip(client, len, errp); } +query = g_malloc(len); ret = nbd_opt_read(client, query, len, errp); if (ret <= 0) { +g_free(query); return ret; } -if (strncmp(query, "allocation", alen) == 0) { -meta->base_allocation = true; +if (strncmp(query, pattern, len) == 0) { +*match = true; } +g_free(query); return 1; } +/* nbd_meta_base_query + * + * Handle query to 'base' namespace. For now, only base:allocation context is + * available in it. 'len' is the amount of text remaining to be read from + * the current name, after the 'base:' portion has been stripped. + * + * Return -errno on I/O error, 0 if option was completely handled by + * sending a reply about inconsistent lengths, or 1 on success. */ +static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, + uint32_t len, Error **errp) +{ +return nbd_meta_single_query(client, "allocation", len, + &meta->base_allocation, errp); +} + struct { const char *ns; int (*func)(NBDClient *, NBDExportMetaContexts *, uint32_t, Error **); -- 2.11.1
Re: [Qemu-devel] [PATCH] dump: display cause of write failure
On Wed, Mar 21, 2018 at 1:08 PM, Laurent Vivier wrote: > Use error_setg_errno() to display the reason why data write > has failed. For instance, instead of a laconic > > dump: failed to write elf header > or > dump: failed to save memory > > we have now: > > dump: failed to write elf header: No space left on device > or > dump: failed to save memory: No space left on device > > CC: Yasmin Beatriz > CC: Jose Ricardo Ziviani > Suggested-by: Eric Blake > Signed-off-by: Laurent Vivier Reviewed-by: Marc-André Lureau > --- > dump.c | 79 > +++--- > 1 file changed, 47 insertions(+), 32 deletions(-) > > diff --git a/dump.c b/dump.c > index 6bdb0dbe23..d04e3f56b0 100644 > --- a/dump.c > +++ b/dump.c > @@ -140,7 +140,7 @@ static void write_elf64_header(DumpState *s, Error **errp) > > ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); > if (ret < 0) { > -error_setg(errp, "dump: failed to write elf header"); > +error_setg_errno(errp, errno, "dump: failed to write elf header"); > } > } > > @@ -171,7 +171,7 @@ static void write_elf32_header(DumpState *s, Error **errp) > > ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); > if (ret < 0) { > -error_setg(errp, "dump: failed to write elf header"); > +error_setg_errno(errp, errno, "dump: failed to write elf header"); > } > } > > @@ -194,7 +194,8 @@ static void write_elf64_load(DumpState *s, MemoryMapping > *memory_mapping, > > ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); > if (ret < 0) { > -error_setg(errp, "dump: failed to write program header table"); > +error_setg_errno(errp, errno, > + "dump: failed to write program header table"); > } > } > > @@ -217,7 +218,8 @@ static void write_elf32_load(DumpState *s, MemoryMapping > *memory_mapping, > > ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); > if (ret < 0) { > -error_setg(errp, "dump: failed to write program header table"); > +error_setg_errno(errp, errno, > + "dump: failed to write program header table"); > } > } > > @@ -237,7 +239,8 @@ static void write_elf64_note(DumpState *s, Error **errp) > > ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); > if (ret < 0) { > -error_setg(errp, "dump: failed to write program header table"); > +error_setg_errno(errp, errno, > + "dump: failed to write program header table"); > } > } > > @@ -254,7 +257,7 @@ static void write_guest_note(WriteCoreDumpFunction f, > DumpState *s, > if (s->guest_note) { > ret = f(s->guest_note, s->guest_note_size, s); > if (ret < 0) { > -error_setg(errp, "dump: failed to write guest note"); > +error_setg_errno(errp, errno, "dump: failed to write guest > note"); > } > } > } > @@ -270,7 +273,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, > DumpState *s, > id = cpu_index(cpu); > ret = cpu_write_elf64_note(f, cpu, id, s); > if (ret < 0) { > -error_setg(errp, "dump: failed to write elf notes"); > +error_setg_errno(errp, errno, "dump: failed to write elf notes"); > return; > } > } > @@ -278,7 +281,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, > DumpState *s, > CPU_FOREACH(cpu) { > ret = cpu_write_elf64_qemunote(f, cpu, s); > if (ret < 0) { > -error_setg(errp, "dump: failed to write CPU status"); > +error_setg_errno(errp, errno, "dump: failed to write CPU > status"); > return; > } > } > @@ -302,7 +305,8 @@ static void write_elf32_note(DumpState *s, Error **errp) > > ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); > if (ret < 0) { > -error_setg(errp, "dump: failed to write program header table"); > +error_setg_errno(errp, errno, > + "dump: failed to write program header table"); > } > } > > @@ -317,7 +321,7 @@ static void write_elf32_notes(WriteCoreDumpFunction f, > DumpState *s, > id = cpu_index(cpu); > ret = cpu_write_elf32_note(f, cpu, id, s); > if (ret < 0) { > -error_setg(errp, "dump: failed to write elf notes"); > +error_setg_errno(errp, errno, "dump: failed to write elf notes"); > return; > } > } > @@ -325,7 +329,7 @@ static void write_elf32_notes(WriteCoreDumpFunction f, > DumpState *s, > CPU_FOREACH(cpu) { > ret = cpu_write_elf32_qemunote(f, cpu, s); > if (ret < 0) { > -error_setg(errp, "dump: failed to write CPU status"); > +error_setg_errno(errp, errno, "dump: failed to write CPU > status"); > return; > } > } > @@ -355,7 +359,8 @@ static void write_elf_section(Dump
Re: [Qemu-devel] [PATCH] scsi: turn "is this a SCSI device?" into a conditional hint
On 21/03/2018 13:17, Laurent Vivier wrote: > On 21/03/2018 11:58, Paolo Bonzini wrote: >> If the user does not have permissions to send ioctls to the device (due to >> SELinux or cgroups, for example), the output can look like >> >> qemu-kvm: -device scsi-block,drive=disk: cannot get SG_IO version number: >> Operation not permitted. Is this a SCSI device? >> >> but this is confusing because the ioctl was blocked _before_ the device >> even received the SG_GET_VERSION_NUM ioctl. Therefore, for EPERM errors >> the suggestion should be eliminated. To make that simpler, change the >> code to use error_append_hint. >> >> Reported-by: Ala Hino >> Signed-off-by: Paolo Bonzini >> --- >> hw/scsi/scsi-disk.c| 7 --- >> hw/scsi/scsi-generic.c | 7 --- >> 2 files changed, 8 insertions(+), 6 deletions(-) >> >> diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c >> index 94043ed024..ccc245589a 100644 >> --- a/hw/scsi/scsi-disk.c >> +++ b/hw/scsi/scsi-disk.c >> @@ -2637,9 +2637,10 @@ static void scsi_block_realize(SCSIDevice *dev, Error >> **errp) >> /* check we are using a driver managing SG_IO (version 3 and after) */ >> rc = blk_ioctl(s->qdev.conf.blk, SG_GET_VERSION_NUM, &sg_version); >> if (rc < 0) { >> -error_setg(errp, "cannot get SG_IO version number: %s. " >> - "Is this a SCSI device?", >> - strerror(-rc)); >> +error_setg(errp, "cannot get SG_IO version number: %s", >> strerror(-rc)); > > > You could use: > > error_setg_errno(errp, -rc, "cannot get SG_IO version number"); Nice, thanks. Will do. Paolo
Re: [Qemu-devel] [PATCH] scsi: turn "is this a SCSI device?" into a conditional hint
On 03/21/2018 05:58 AM, Paolo Bonzini wrote: If the user does not have permissions to send ioctls to the device (due to SELinux or cgroups, for example), the output can look like qemu-kvm: -device scsi-block,drive=disk: cannot get SG_IO version number: Operation not permitted. Is this a SCSI device? but this is confusing because the ioctl was blocked _before_ the device even received the SG_GET_VERSION_NUM ioctl. Therefore, for EPERM errors the suggestion should be eliminated. To make that simpler, change the code to use error_append_hint. Reported-by: Ala Hino Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c| 7 --- hw/scsi/scsi-generic.c | 7 --- 2 files changed, 8 insertions(+), 6 deletions(-) +++ b/hw/scsi/scsi-disk.c @@ -2637,9 +2637,10 @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) /* check we are using a driver managing SG_IO (version 3 and after) */ rc = blk_ioctl(s->qdev.conf.blk, SG_GET_VERSION_NUM, &sg_version); if (rc < 0) { -error_setg(errp, "cannot get SG_IO version number: %s. " - "Is this a SCSI device?", - strerror(-rc)); +error_setg(errp, "cannot get SG_IO version number: %s", strerror(-rc)); +if (rc != -EPERM) { +error_append_hint(errp, "Is this a SCSI device?"); Missing the \n (error_append_hint does NOT automatically add one, because sometimes hints are pieced together but should still display in one line). +++ b/hw/scsi/scsi-generic.c @@ -500,9 +500,10 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp) /* check we are using a driver managing SG_IO (version 3 and after */ rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version); if (rc < 0) { -error_setg(errp, "cannot get SG_IO version number: %s. " - "Is this a SCSI device?", - strerror(-rc)); +error_setg(errp, "cannot get SG_IO version number: %s", strerror(-rc)); +if (rc != -EPERM) { +error_append_hint(errp, "Is this a SCSI device?"); And again. With that fixed, Reviewed-by: Eric Blake -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
Re: [Qemu-devel] [PULL 31/36] monitor: enable IO thread for (qmp & !mux) typed
On 2018-03-21 13:37, Max Reitz wrote: > On 2018-03-12 19:36, Eric Blake wrote: >> From: Peter Xu >> >> Start to use dedicate IO thread for QMP monitors that are not using >> MUXed chardev. >> >> Reviewed-by: Fam Zheng >> Reviewed-by: Stefan Hajnoczi >> Signed-off-by: Peter Xu >> Message-Id: <20180309090006.10018-21-pet...@redhat.com> >> Signed-off-by: Eric Blake >> --- >> monitor.c | 5 - >> 1 file changed, 4 insertions(+), 1 deletion(-) > > It seems the iotests aren't quite ready for this change (breakage in > 040, 041, 051, 060, 085, 087, 093, 095, 109, 124, 127, 132, 136, 144, > 148, 152, 182, 183, 185, 186; and 030 hangs). (On second thought, 051, 185, and 186 have probably broken because of something else. Max) signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [PULL 31/36] monitor: enable IO thread for (qmp & !mux) typed
On 2018-03-12 19:36, Eric Blake wrote: > From: Peter Xu > > Start to use dedicate IO thread for QMP monitors that are not using > MUXed chardev. > > Reviewed-by: Fam Zheng > Reviewed-by: Stefan Hajnoczi > Signed-off-by: Peter Xu > Message-Id: <20180309090006.10018-21-pet...@redhat.com> > Signed-off-by: Eric Blake > --- > monitor.c | 5 - > 1 file changed, 4 insertions(+), 1 deletion(-) It seems the iotests aren't quite ready for this change (breakage in 040, 041, 051, 060, 085, 087, 093, 095, 109, 124, 127, 132, 136, 144, 148, 152, 182, 183, 185, 186; and 030 hangs). Max signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [PATCH 0/3] tests: trivial enhancements for OOB
On 03/21/2018 01:55 AM, Peter Xu wrote: First two patches add OOB detection for current qapi-schema tests (which I missed in the OOB series but pointed out by Eric Blake). The 3rd patch addressed one suggestion from Eric too here: http://lists.gnu.org/archive/html/qemu-devel/2018-03/msg03177.html I tried to batch the commands in a single string buffer but it's not that easy - because currently qtest_async_qmp() (and finally, qmp_fd_sendv()) does not really support multiple qobjects in a single command buffer. Let's put that aside. After all even calling qtest_async_qmp() many times would be really fast, since we are basically filling things to the write buffer very quickly (I believe that's much faster than the IO really flushed to the receiver side). But, adding the "id" field and check that would be far easier, that's what I did in that last patch. It's fine even for 2.12, but I'll let people decide. I consider added testsuite coverage of a new feature to be a bug fix (the feature was incomplete if the testsuite doesn't prevent regressions in the feature) and safe for freeze (the testsuite changes don't impact the main binary, so they can't break anything), so I'm happy to queue this through my qapi tree for 2.12 once it is reviewed. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
Re: [Qemu-devel] [PATCH 1/3] tests: let qapi-schema tests detect oob
On 03/21/2018 01:55 AM, Peter Xu wrote: The allow_oob parameter was passed in but not used in tests. Now reflect that in the tests, so we need to touch up other command testers with that new change. Signed-off-by: Peter Xu --- tests/qapi-schema/doc-good.out | 4 ++-- tests/qapi-schema/ident-with-escape.out | 2 +- tests/qapi-schema/indented-expr.out | 4 ++-- tests/qapi-schema/qapi-schema-test.out | 18 +- tests/qapi-schema/test-qapi.py | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) +++ b/tests/qapi-schema/test-qapi.py @@ -45,8 +45,8 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor): gen, success_response, boxed, allow_oob): print('command %s %s -> %s' % \ (name, arg_type and arg_type.name, ret_type and ret_type.name)) -print(' gen=%s success_response=%s boxed=%s' % \ - (gen, success_response, boxed)) +print(' gen=%s success_response=%s boxed=%s oob=%s' % \ + (gen, success_response, boxed, allow_oob)) Reviewed-by: Eric Blake -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
Re: [Qemu-devel] [PATCH v3 00/49] qapi: add #if pre-processor conditions to generated code
Hi, This series failed build test on s390x host. Please find the details below. Type: series Message-id: 20180321115211.17937-1-marcandre.lur...@redhat.com Subject: [Qemu-devel] [PATCH v3 00/49] qapi: add #if pre-processor conditions to generated code === 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 "=== ENV ===" env echo "=== PACKAGES ===" rpm -qa echo "=== TEST BEGIN ===" CC=$HOME/bin/cc INSTALL=$PWD/install BUILD=$PWD/build echo -n "Using CC: " realpath $CC 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 === Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384 From https://github.com/patchew-project/qemu * [new tag] patchew/1521634071-16519-1-git-send-email-stef...@linux.vnet.ibm.com -> patchew/1521634071-16519-1-git-send-email-stef...@linux.vnet.ibm.com * [new tag] patchew/20180321115211.17937-1-marcandre.lur...@redhat.com -> patchew/20180321115211.17937-1-marcandre.lur...@redhat.com * [new tag] patchew/20180321120853.14293-1-lviv...@redhat.com -> patchew/20180321120853.14293-1-lviv...@redhat.com Switched to a new branch 'test' ca50a2d8e3 RFC: make RTC_CHANGE per-target 032f3d2f59 qapi: remove qmp_unregister_command() 7a4b17cf54 qapi: make query-cpu-definitions depend on specific targets 557f536176 qapi: make query-cpu-model-expansion depend on s390 or x86 dc1b218319 qapi: make query-gic-capabilities depend on TARGET_ARM af9625c6c3 target.json: add a note about query-cpu* not being s390x-specific c9801977e9 qapi: make s390 commands depend on TARGET_S390X 6a49803445 qapi: make rtc-reset-reinjection and SEV depend on TARGET_I386 13b093aaae qapi: add a top-unit 'target' schema 8e42b4bfd8 RFC: qapi: learn to split schema by 'top-unit' 2984459cd6 qapi-commands: don't initialize command list in qmp_init_marshall() 7c39c807b5 build-sys: move qmp-introspect per target af7d5d518d qapi: add conditions to REPLICATION type/commands on the schema 9e583d1a1d qapi: add conditions to SPICE type/commands/events on the schema 8bc16dec62 qapi: add conditions to VNC type/commands/events on the schema 72664dbe15 qapi2texi: add condition to variants d7ff0ab4ef qapi2texi: add 'If:' condition to struct members bde44a6b1d qapi2texi: add 'If:' condition to enum values c87e1bc65f qapi2texi: add 'If:' section to generated documentation 3364d5099f docs: document schema configuration 77f7bafdc4 qapi: add #if conditions to generated code members a95929de93 qapi: add 'if' to alternate members b205d6198c qapi: add 'if' on union members 9613ba2cc2 qapi: add an error in case a discriminator is conditionnal cd025039c0 qapi: add 'if' to implicit struct members 6799c824a8 qapi: add a dictionary form with 'type' key for members c5b50ed9e3 qapi: rename allow_dict to allow_implicit ba4011e602 qapi-event: add 'if' condition to implicit event enum 7d828e85b9 qapi: add 'if' to enum members a20c2dc973 qapi: add a dictionnary form with 'name' key for enum members 061635eff1 qapi: factor out check_known_keys() b0ad9a471a tests: modify visit_enum_type() in test-qapi to print members 86933fb39c qapi: change enum visitor to take QAPISchemaMember cd6fb8e83f qapi: rename QAPISchemaEnumType.values to .members 31ea46dcec qapi: do not define enumeration value explicitely 55c7453f3c qapi-types: add #if conditions to types & visitors 4507e44d86 qapi-types: refactor variants handling 9c91a8fa1d qapi/events: add #if conditions to events 7ba12f474f qapi/commands: add #if conditions to commands fcf4dfeb56 qapi-introspect: add preprocessor conditions to generated QLit 51163f6ba0 qapi-introspect: modify to_qlit() to append ', ' on level > 0 75baac460c qapi: add #if/#endif helpers a001949a31 qapi: mcgen() shouldn't indent # lines a2ef5afa63 qapi: add 'ifcond' to visitor methods 688755b5fd qapi: leave the ifcond attribute undefined until check() 0566f4cb49 qapi: pass 'if' condition into QAPISchemaEntity objects 7b98d1b34c qapi: add 'if' to top-level expressions 6c36d8fa28 qapi/events: generate event enum in main module 7ced623f53 qapi/visit: remove useless prefix argument === OUTPUT BEGIN === === ENV === LANG=en_US.UTF-8 XDG_SESSION_ID=107260 USER=fam PWD=/var/tmp/patchew-tester-tmp-1tgugnof/src HOME=/home/fam SHELL=/bin/sh SHLVL=2 PATCHEW=/home/fam/patchew/patchew-cli -s http://patchew.org --nodebug LOGNAME=fam DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1012/bus XDG_RUNTIME_DIR=/run/user/1012 PATH=/usr/bin:/bin _=/usr/bin/env === PACKAGES === gpg-pubkey-873529b8-54e386ff glibc-debuginfo-common-2.24-10.fc25.s390x fedora-release-26-1.noarch dejavu-sans-mono-fonts-2.35-4.fc26.noarch xemacs-filesystem-21.5.34-22.20170124hgf412e9f093d4.fc26.noarch bash-4.4.12-7.fc26.s390x freetype-2.7.1-9.fc26.s390x libSM-1.2.2-5.fc26.s390x libmpc-1.0.2-6.fc2