Re: [Qemu-devel] [PATCH v3 00/32] implement vNVDIMM

2015-10-12 Thread Dan Williams
On Mon, Oct 12, 2015 at 10:49 PM, Xiao Guangrong
 wrote:
>
>
> On 10/13/2015 11:38 AM, Dan Williams wrote:
>>
>> On Mon, Oct 12, 2015 at 8:14 PM, Xiao Guangrong
>>  wrote:
>>>
>>> On 10/13/2015 12:36 AM, Dan Williams wrote:

 Static namespaces can be emitted without a label.  Linux needs this to
 support existing "label-less" bare metal NVDIMMs.
>>>
>>>
>>>
>>> This is Linux specific? As i did not see it has been documented in the
>>> spec...
>>
>>
>> I expect most NVDIMMs, especially existing ones available today, do
>> not have a label area.  This is not Linux specific and ACPI 6 does not
>> specify a label area, only the Intel DSM Interface Example.
>>
>
> Yup, label data is accessed via DSM interface, the spec I mentioned
> is Intel DSM Interface Example.
>
> However, IIRC Linux NVDIMM driver refused to use the device if no
> DSM GET_LABEL support, are you going to update it?

Label-less DIMMs are tested as part of the unit test [1] and the
"memmap=nn!ss" kernel parameter that registers a persistent-memory
address range without a DIMM.  What error do you see when label
support is disabled?

[1]: https://github.com/pmem/ndctl/blob/master/README.md



Re: [Qemu-devel] [PATCH v3 23/32] nvdimm: build ACPI NFIT table

2015-10-12 Thread Xiao Guangrong



On 10/13/2015 01:42 PM, Michael S. Tsirkin wrote:

On Tue, Oct 13, 2015 at 01:13:18PM +0800, Xiao Guangrong wrote:



  #endif


This header is too small to be worth it.
nvdimm_get_built_list seems to be the only interface -
just stick it in the header you have under include.



Other functions are introudced and included into it in later patches,
it includes the internal things shared between nvdimm device, nvdimm ACPI,
nvdimm namespace.

Furthermore, this is a internal include file, it is not bad i think.


Each time we do this, this seems to invite abuse where
people add APIs without documenting them.



Understood.


I guess I could buy this if you add nvdimm_defs.h
with just internal things such as layout of the buffer
used for communication between ACPI and hardware.



Okay, i will rename internel.h to nvdimm_defs.h and carefully document
everything (definitions, function prototypes, etc.) in this file. :)




Re: [Qemu-devel] [PATCH v3 23/32] nvdimm: build ACPI NFIT table

2015-10-12 Thread Michael S. Tsirkin
On Tue, Oct 13, 2015 at 01:17:20PM +0800, Xiao Guangrong wrote:
> >Would it worth including / copying the ACPICA header files directly?
> >
> >https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/acpi/actbl1.h
> >https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/acpi/acuuid.h
> 
> Good point, Dan.
> 
> These files are not exported under uapi/ so that it is not good to directly
> include it, i will learn the definition and adjust it to QEMU's code style
> in the next version.
> 
> Thanks!
> 

You can talk to acpica guys to try to move acuuid.h to uapi
if you like. But there's not a lot there that we need,
I'm not sure it's worth it.

-- 
MST



Re: [Qemu-devel] [PATCH v3 00/32] implement vNVDIMM

2015-10-12 Thread Xiao Guangrong



On 10/13/2015 01:57 PM, Michael S. Tsirkin wrote:

On Tue, Oct 13, 2015 at 01:29:48PM +0800, Xiao Guangrong wrote:



On 10/12/2015 07:55 PM, Michael S. Tsirkin wrote:

On Sun, Oct 11, 2015 at 11:52:32AM +0800, Xiao Guangrong wrote:

Changelog in v3:
There is huge change in this version, thank Igor, Stefan, Paolo, Eduardo,
Michael for their valuable comments, the patchset finally gets better shape.


Thanks!
This needs some changes in coding style, and more comments, to
make it easier to maintain going forward.


Thanks for your review, Michael. I have learned lots of thing from
your comments.



High level comments - I didn't point out all instances,
please go over code and locate them yourself.
I focused on acpi code in this review.


Okay, will do.



 - fix coding style violations, prefix eveything with nvdimm_ etc


Actually i did not pay attention on naming the stuff which is only internally
used. Thank you for pointing it out and will fix it in next version.


 - in apci code, avoid manual memory management/complex pointer math


I am not very good at ACPI ASL/AML, could you please more detail?


It's about C.

For example:
Foo *foo = acpi_data_push(table, sizeof *foo);
Bar *foo = acpi_data_push(table, sizeof *bar);
is pretty obviously safe, and it doesn't require you to do any
calculations.
char *buf = acpi_data_push(table, sizeof *foo + sizeof *bar);
is worse, now you need:
Bar *bar = (Bar *)(buf + sizeof *foo);
which will corrupt memory if you get the size wrong in push.


Ah, got it. :)



Re: [Qemu-devel] [PATCH v3 00/32] implement vNVDIMM

2015-10-12 Thread Michael S. Tsirkin
On Tue, Oct 13, 2015 at 01:29:48PM +0800, Xiao Guangrong wrote:
> 
> 
> On 10/12/2015 07:55 PM, Michael S. Tsirkin wrote:
> >On Sun, Oct 11, 2015 at 11:52:32AM +0800, Xiao Guangrong wrote:
> >>Changelog in v3:
> >>There is huge change in this version, thank Igor, Stefan, Paolo, Eduardo,
> >>Michael for their valuable comments, the patchset finally gets better shape.
> >
> >Thanks!
> >This needs some changes in coding style, and more comments, to
> >make it easier to maintain going forward.
> 
> Thanks for your review, Michael. I have learned lots of thing from
> your comments.
> 
> >
> >High level comments - I didn't point out all instances,
> >please go over code and locate them yourself.
> >I focused on acpi code in this review.
> 
> Okay, will do.
> 
> >
> > - fix coding style violations, prefix eveything with nvdimm_ etc
> 
> Actually i did not pay attention on naming the stuff which is only internally
> used. Thank you for pointing it out and will fix it in next version.
> 
> > - in apci code, avoid manual memory management/complex pointer math
> 
> I am not very good at ACPI ASL/AML, could you please more detail?

It's about C.

For example:
Foo *foo = acpi_data_push(table, sizeof *foo);
Bar *foo = acpi_data_push(table, sizeof *bar);
is pretty obviously safe, and it doesn't require you to do any
calculations.
char *buf = acpi_data_push(table, sizeof *foo + sizeof *bar);
is worse, now you need:
Bar *bar = (Bar *)(buf + sizeof *foo);
which will corrupt memory if you get the size wrong in push.

> > - comments are needed to document apis & explain what's going on
> > - constants need comments too, refer to text that
> >   can be looked up in acpi spec verbatim
> 
> Indeed, will document carefully.



Re: [Qemu-devel] [PATCH v3 00/32] implement vNVDIMM

2015-10-12 Thread Xiao Guangrong



On 10/13/2015 11:38 AM, Dan Williams wrote:

On Mon, Oct 12, 2015 at 8:14 PM, Xiao Guangrong
 wrote:

On 10/13/2015 12:36 AM, Dan Williams wrote:

Static namespaces can be emitted without a label.  Linux needs this to
support existing "label-less" bare metal NVDIMMs.



This is Linux specific? As i did not see it has been documented in the
spec...


I expect most NVDIMMs, especially existing ones available today, do
not have a label area.  This is not Linux specific and ACPI 6 does not
specify a label area, only the Intel DSM Interface Example.



Yup, label data is accessed via DSM interface, the spec I mentioned
is Intel DSM Interface Example.

However, IIRC Linux NVDIMM driver refused to use the device if no
DSM GET_LABEL support, are you going to update it?



Re: [Qemu-devel] [PATCH v7 4/5] block: add a 'blockdev-snapshot' QMP command

2015-10-12 Thread Alberto Garcia
On Mon 12 Oct 2015 10:29:35 PM CEST, Max Reitz  wrote:
>> -if (has_snapshot_node_name &&
>> -bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) {
>> -error_setg(errp, "New snapshot node name already in use");
>
> There's a difference from v6 here...
[...]
>> -options = qdict_new();
>> -if (has_snapshot_node_name) {
>> -qdict_put(options, "node-name",
>> -  qstring_from_str(snapshot_node_name));
>> +if (snapshot_node_name &&
>> +bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) {
>> +error_setg(errp, "New snapshot node name already in use");
>
> ...and here, but how to resolve the conflict resulting from the newly
> added patch 1 was obvious, so my R-b stands, of course.

The differences are because this patch is now rebased on top of the new
one, sorry if I overstepped by keeping your R-b here!

>> +if (state->new_bs->backing_hd != NULL) {
>> +error_setg(errp, "The snapshot already has a backing image");
>>  }
>
> It's here: In case Kevin's series is applied before this one (which
> I'm assuming since you were brave enough to base this series on my BB
> series), this needs to be s/backing_hd/backing/. I'm just saying this
> so you know you can keep my R-b then.

Sure, I was about to test your new version of the series.

Thanks,

Berto



Re: [Qemu-devel] [PATCH v3 23/32] nvdimm: build ACPI NFIT table

2015-10-12 Thread Michael S. Tsirkin
On Tue, Oct 13, 2015 at 01:13:18PM +0800, Xiao Guangrong wrote:
> >
> >>  #endif
> >
> >This header is too small to be worth it.
> >nvdimm_get_built_list seems to be the only interface -
> >just stick it in the header you have under include.
> >
> 
> Other functions are introudced and included into it in later patches,
> it includes the internal things shared between nvdimm device, nvdimm ACPI,
> nvdimm namespace.
> 
> Furthermore, this is a internal include file, it is not bad i think.

Each time we do this, this seems to invite abuse where
people add APIs without documenting them.

I guess I could buy this if you add nvdimm_defs.h
with just internal things such as layout of the buffer
used for communication between ACPI and hardware.

-- 
MST



Re: [Qemu-devel] [PATCH v3 00/32] implement vNVDIMM

2015-10-12 Thread Xiao Guangrong



On 10/12/2015 07:55 PM, Michael S. Tsirkin wrote:

On Sun, Oct 11, 2015 at 11:52:32AM +0800, Xiao Guangrong wrote:

Changelog in v3:
There is huge change in this version, thank Igor, Stefan, Paolo, Eduardo,
Michael for their valuable comments, the patchset finally gets better shape.


Thanks!
This needs some changes in coding style, and more comments, to
make it easier to maintain going forward.


Thanks for your review, Michael. I have learned lots of thing from
your comments.



High level comments - I didn't point out all instances,
please go over code and locate them yourself.
I focused on acpi code in this review.


Okay, will do.



 - fix coding style violations, prefix eveything with nvdimm_ etc


Actually i did not pay attention on naming the stuff which is only internally
used. Thank you for pointing it out and will fix it in next version.


 - in apci code, avoid manual memory management/complex pointer math


I am not very good at ACPI ASL/AML, could you please more detail?


 - comments are needed to document apis & explain what's going on
 - constants need comments too, refer to text that
   can be looked up in acpi spec verbatim


Indeed, will document carefully.



Re: [Qemu-devel] [PATCH v3 23/32] nvdimm: build ACPI NFIT table

2015-10-12 Thread Xiao Guangrong



On 10/13/2015 12:40 AM, Dan Williams wrote:

On Sat, Oct 10, 2015 at 8:52 PM, Xiao Guangrong
 wrote:

NFIT is defined in ACPI 6.0: 5.2.25 NVDIMM Firmware Interface Table (NFIT)

Currently, we only support PMEM mode. Each device has 3 structures:
- SPA structure, defines the PMEM region info

- MEM DEV structure, it has the @handle which is used to associate specified
   ACPI NVDIMM  device we will introduce in later patch.
   Also we can happily ignored the memory device's interleave, the real
   nvdimm hardware access is hidden behind host

- DCR structure, it defines vendor ID used to associate specified vendor
   nvdimm driver. Since we only implement PMEM mode this time, Command
   window and Data window are not needed

Signed-off-by: Xiao Guangrong 
---
  hw/i386/acpi-build.c |   4 +
  hw/mem/nvdimm/acpi.c | 209 ++-
  hw/mem/nvdimm/internal.h |  13 +++
  hw/mem/nvdimm/nvdimm.c   |  25 ++
  include/hw/mem/nvdimm.h  |   2 +
  5 files changed, 252 insertions(+), 1 deletion(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 95e0c65..c637dc8 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1661,6 +1661,7 @@ static bool acpi_has_iommu(void)
  static
  void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
  {
+PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
  GArray *table_offsets;
  unsigned facs, ssdt, dsdt, rsdt;
  AcpiCpuInfo cpu;
@@ -1742,6 +1743,9 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables 
*tables)
  build_dmar_q35(tables_blob, tables->linker);
  }

+nvdimm_build_acpi_table(&pcms->nvdimm_memory, table_offsets, tables_blob,
+tables->linker);
+
  /* Add tables supplied by user (if any) */
  for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
  unsigned len = acpi_table_len(u);
diff --git a/hw/mem/nvdimm/acpi.c b/hw/mem/nvdimm/acpi.c
index b640874..62b1e02 100644
--- a/hw/mem/nvdimm/acpi.c
+++ b/hw/mem/nvdimm/acpi.c
@@ -32,6 +32,46 @@
  #include "hw/mem/nvdimm.h"
  #include "internal.h"

+static void nfit_spa_uuid_pm(uuid_le *uuid)
+{
+uuid_le uuid_pm = UUID_LE(0x66f0d379, 0xb4f3, 0x4074, 0xac, 0x43, 0x0d,
+  0x33, 0x18, 0xb7, 0x8c, 0xdb);
+memcpy(uuid, &uuid_pm, sizeof(uuid_pm));
+}
+
+enum {
+NFIT_STRUCTURE_SPA = 0,
+NFIT_STRUCTURE_MEMDEV = 1,
+NFIT_STRUCTURE_IDT = 2,
+NFIT_STRUCTURE_SMBIOS = 3,
+NFIT_STRUCTURE_DCR = 4,
+NFIT_STRUCTURE_BDW = 5,
+NFIT_STRUCTURE_FLUSH = 6,
+};
+
+enum {
+EFI_MEMORY_UC = 0x1ULL,
+EFI_MEMORY_WC = 0x2ULL,
+EFI_MEMORY_WT = 0x4ULL,
+EFI_MEMORY_WB = 0x8ULL,
+EFI_MEMORY_UCE = 0x10ULL,
+EFI_MEMORY_WP = 0x1000ULL,
+EFI_MEMORY_RP = 0x2000ULL,
+EFI_MEMORY_XP = 0x4000ULL,
+EFI_MEMORY_NV = 0x8000ULL,
+EFI_MEMORY_MORE_RELIABLE = 0x1ULL,
+};


Would it worth including / copying the ACPICA header files directly?

https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/acpi/actbl1.h
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/acpi/acuuid.h


Good point, Dan.

These files are not exported under uapi/ so that it is not good to directly
include it, i will learn the definition and adjust it to QEMU's code style
in the next version.

Thanks!





Re: [Qemu-devel] [PATCH v3 23/32] nvdimm: build ACPI NFIT table

2015-10-12 Thread Xiao Guangrong



On 10/12/2015 07:27 PM, Michael S. Tsirkin wrote:

On Sun, Oct 11, 2015 at 11:52:55AM +0800, Xiao Guangrong wrote:

NFIT is defined in ACPI 6.0: 5.2.25 NVDIMM Firmware Interface Table (NFIT)

Currently, we only support PMEM mode. Each device has 3 structures:
- SPA structure, defines the PMEM region info

- MEM DEV structure, it has the @handle which is used to associate specified
   ACPI NVDIMM  device we will introduce in later patch.
   Also we can happily ignored the memory device's interleave, the real
   nvdimm hardware access is hidden behind host

- DCR structure, it defines vendor ID used to associate specified vendor
   nvdimm driver. Since we only implement PMEM mode this time, Command
   window and Data window are not needed

Signed-off-by: Xiao Guangrong 
---
  hw/i386/acpi-build.c |   4 +
  hw/mem/nvdimm/acpi.c | 209 ++-
  hw/mem/nvdimm/internal.h |  13 +++
  hw/mem/nvdimm/nvdimm.c   |  25 ++
  include/hw/mem/nvdimm.h  |   2 +
  5 files changed, 252 insertions(+), 1 deletion(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 95e0c65..c637dc8 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1661,6 +1661,7 @@ static bool acpi_has_iommu(void)
  static
  void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
  {
+PCMachineState *pcms = PC_MACHINE(qdev_get_machine());


I don't like more code poking at machine directly.
I know srat does it, and I don't like it. Any chance you can add
acpi_get_nvdumm_info to get all you need from nvdimm state?


Do you mean introduce a wrapper to do this,like:
struct nvdimm_state *acpi_get_nvdumm_info(void)
{
return &PC_MACHINE(qdev_get_machine())->nvdimm_memory;
}

Or should we maintain nvdimm state in other place (for example, a global
value in nvdimm.c)?




  GArray *table_offsets;
  unsigned facs, ssdt, dsdt, rsdt;
  AcpiCpuInfo cpu;
@@ -1742,6 +1743,9 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables 
*tables)
  build_dmar_q35(tables_blob, tables->linker);
  }

+nvdimm_build_acpi_table(&pcms->nvdimm_memory, table_offsets, tables_blob,
+tables->linker);
+
  /* Add tables supplied by user (if any) */
  for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
  unsigned len = acpi_table_len(u);
diff --git a/hw/mem/nvdimm/acpi.c b/hw/mem/nvdimm/acpi.c
index b640874..62b1e02 100644
--- a/hw/mem/nvdimm/acpi.c
+++ b/hw/mem/nvdimm/acpi.c
@@ -32,6 +32,46 @@
  #include "hw/mem/nvdimm.h"
  #include "internal.h"

+static void nfit_spa_uuid_pm(uuid_le *uuid)
+{
+uuid_le uuid_pm = UUID_LE(0x66f0d379, 0xb4f3, 0x4074, 0xac, 0x43, 0x0d,
+  0x33, 0x18, 0xb7, 0x8c, 0xdb);
+memcpy(uuid, &uuid_pm, sizeof(uuid_pm));
+}
+


Just add a static constant:
 const uint8_t nfit_spa_uuid[] = {0x79, 0xd3, . }
then memcpy instead of a wrapper.


Okay, good to me.




+enum {
+NFIT_STRUCTURE_SPA = 0,
+NFIT_STRUCTURE_MEMDEV = 1,
+NFIT_STRUCTURE_IDT = 2,
+NFIT_STRUCTURE_SMBIOS = 3,
+NFIT_STRUCTURE_DCR = 4,
+NFIT_STRUCTURE_BDW = 5,
+NFIT_STRUCTURE_FLUSH = 6,
+};
+
+enum {
+EFI_MEMORY_UC = 0x1ULL,
+EFI_MEMORY_WC = 0x2ULL,
+EFI_MEMORY_WT = 0x4ULL,
+EFI_MEMORY_WB = 0x8ULL,
+EFI_MEMORY_UCE = 0x10ULL,
+EFI_MEMORY_WP = 0x1000ULL,
+EFI_MEMORY_RP = 0x2000ULL,
+EFI_MEMORY_XP = 0x4000ULL,
+EFI_MEMORY_NV = 0x8000ULL,
+EFI_MEMORY_MORE_RELIABLE = 0x1ULL,
+};
+
+/*
+ * NVDIMM Firmware Interface Table
+ * @signature: "NFIT"
+ */
+struct nfit {
+ACPI_TABLE_HEADER_DEF
+uint32_t reserved;
+} QEMU_PACKED;
+typedef struct nfit nfit;
+
  /* System Physical Address Range Structure */
  struct nfit_spa {
  uint16_t type;
@@ -40,13 +80,21 @@ struct nfit_spa {
  uint16_t flags;
  uint32_t reserved;
  uint32_t proximity_domain;
-uint8_t type_guid[16];
+uuid_le type_guid;
  uint64_t spa_base;
  uint64_t spa_length;
  uint64_t mem_attr;
  } QEMU_PACKED;
  typedef struct nfit_spa nfit_spa;

+/*
+ * Control region is strictly for management during hot add/online
+ * operation.
+ */
+#define SPA_FLAGS_ADD_ONLINE_ONLY (1)


unused


Indeed, currently vNVDIMM did not use this flag, it just introduces
the definition following the spec.

I do not see the hurt of these macros, it is really unacceptable?
Or just the programming style in QEMU?




+/* Data in Proximity Domain field is valid. */
+#define SPA_FLAGS_PROXIMITY_VALID (1 << 1)
+
  /* Memory Device to System Physical Address Range Mapping Structure */
  struct nfit_memdev {
  uint16_t type;
@@ -91,12 +139,20 @@ struct nfit_dcr {
  } QEMU_PACKED;
  typedef struct nfit_dcr nfit_dcr;

+#define REVSISON_ID1
+#define NFIT_FIC1  0x201
+
  static uint64_t nvdimm_device_structure_size(uint64_t slots)
  {
  /* each nvdimm has three structures. */
  return slots * (sizeof(nfit_spa) + sizeof(nfit_memdev) +

Re: [Qemu-devel] [RFC 0/4] AHCI patches + Allwinner SATA

2015-10-12 Thread Peter Crosthwaite
On Mon, Oct 12, 2015 at 1:41 PM, Beniamino Galvani  wrote:
> On Sun, Oct 11, 2015 at 09:21:32AM -0700, Peter Crosthwaite wrote:
>> Hi John and Beniamino,
>>
>> This patch series adds bear-minimum Allwinner SATA support.
>
> Hi Peter,
>
> can you suggest a qemu command line to test this?
>

-drive file=path/to/rootfs.ext4,if=none,id=sata
-device ide-drive,drive=sata,bus=ide.0
--append "root=/dev/sda"

Regards,
Peter

> Beniamino



Re: [Qemu-devel] [RFC 3/4] ahci: Add allwinner AHCI

2015-10-12 Thread Peter Crosthwaite
On Mon, Oct 12, 2015 at 4:09 PM, John Snow  wrote:
> Is there any spec or documentation I can cross-reference this against?
>

Not that I know of. I am running off a combination of experiments
(looking at messages from P1) and the Linux driver source.

> I gather this exists within the vendor-specific reserved region from
> 0xA0 to 0xFF just prior to the port registers, so this all /looks/ like
> it's right, I just don't have any way to verify it.
>
> On 10/11/2015 12:21 PM, Peter Crosthwaite wrote:
>> Add a Sysbus AHCI subclass for the Allwinner AHCI. It has a few extra
>> vendor specific registers that are used for phy and power init.
>>
>> Signed-off-by: Peter Crosthwaite 
>> ---
>>  hw/ide/ahci.c | 98 
>> +++
>>  hw/ide/ahci.h | 16 ++
>>  2 files changed, 114 insertions(+)
>>
>> diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
>> index eff01b2..a7fa147 100644
>> --- a/hw/ide/ahci.c
>> +++ b/hw/ide/ahci.c
>> @@ -1692,9 +1692,107 @@ static const TypeInfo sysbus_ahci_info = {
>>  .class_init= sysbus_ahci_class_init,
>>  };
>>
>> +#define ALLWINNER_AHCI_MMIO_OFF  0x80
>> +#define ALLWINNER_AHCI_MMIO_SIZE 0x80
>> +
>> +#define ALLWINNER_AHCI_BISTAFR((0xa0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_BISTCR ((0xa4 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_BISTFCTR   ((0xa8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_BISTSR ((0xac - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_BISTDECR   ((0xb0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_DIAGNR0((0xb4 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_DIAGNR1((0xb8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_OOBR   ((0xbc - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_PHYCS0R((0xc0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_PHYCS1R((0xc4 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_PHYCS2R((0xc8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_TIMER1MS   ((0xe0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_GPARAM1R   ((0xe8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_GPARAM2R   ((0xec - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_PPARAMR((0xf0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_TESTR  ((0xf4 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_VERSIONR   ((0xf8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_IDR((0xfc - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +#define ALLWINNER_AHCI_RWCR   ((0xfc - ALLWINNER_AHCI_MMIO_OFF) / 4)
>> +
>> +static uint64_t allwinner_ahci_mem_read(void *opaque, hwaddr addr,
>> +unsigned size)
>> +{
>> +AllwinnerAHCIState *a = opaque;
>> +uint64_t val = a->regs[addr/4];
>> +
>> +switch (addr / 4) {
>> +case ALLWINNER_AHCI_PHYCS0R:
>> +val |= 0x2 << 28;
>> +break;
>> +case ALLWINNER_AHCI_PHYCS2R:
>> +val &= ~(0x1 << 24);
>> +break;
>> +}
>> +DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n",
>> +addr, val, size);
>> +return  val;
>> +}
>> +
>> +static void allwinner_ahci_mem_write(void *opaque, hwaddr addr,
>> + uint64_t val, unsigned size)
>> +{
>> +AllwinnerAHCIState *a = opaque;
>> +
>> +DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n",
>> +addr, val, size);
>> +a->regs[addr/4] = val;
>> +}
>> +
>> +static const MemoryRegionOps allwinner_ahci_mem_ops = {
>> +.read = allwinner_ahci_mem_read,
>> +.write = allwinner_ahci_mem_write,
>> +.valid.min_access_size = 4,
>> +.valid.max_access_size = 4,
>
> Are you sure devices won't try to read individual bytes for error codes
> out of these vendor registers?
>

No idea.

Regards,
Peter

>> +.endianness = DEVICE_LITTLE_ENDIAN,
>> +};
>> +
>> +static void allwinner_ahci_init(Object *obj)
>> +{
>> +SysbusAHCIState *s = SYSBUS_AHCI(obj);
>> +AllwinnerAHCIState *a = ALLWINNER_AHCI(obj);
>> +
>> +memory_region_init_io(&a->mmio, OBJECT(obj), &allwinner_ahci_mem_ops, a,
>> +  "allwinner_ahci", ALLWINNER_AHCI_MMIO_SIZE);
>> +memory_region_add_subregion(&s->ahci.mem, ALLWINNER_AHCI_MMIO_OFF,
>> +&a->mmio);
>> +}
>> +
>> +static const VMStateDescription vmstate_allwinner_ahci = {
>> +.name = "a10.pic",
>> +.version_id = 1,
>> +.minimum_version_id = 1,
>> +.fields = (VMStateField[]) {
>> +VMSTATE_UINT32_ARRAY(regs, AllwinnerAHCIState,
>> + ALLWINNER_AHCI_MMIO_SIZE/4),
>> +VMSTATE_END_OF_LIST()
>> +}
>> +};
>> +
>> +static void allwinner_ahci_class_init(ObjectClass *klass, void *data)
>> +{
>> +DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +dc->vmsd = &vmstate_allwinner_ahci;
>> +}
>> +
>> +stat

Re: [Qemu-devel] [RFC 4/4] arm: allwinner-a10: Add SATA

2015-10-12 Thread Peter Crosthwaite
On Mon, Oct 12, 2015 at 3:32 PM, John Snow  wrote:
>
>
> On 10/11/2015 12:21 PM, Peter Crosthwaite wrote:
>> Add the Allwinner A10 AHCI controller module to the SoC.
>>
>> Signed-off-by: Peter Crosthwaite 
>> ---
>>  hw/arm/allwinner-a10.c | 11 +++
>>  include/hw/arm/allwinner-a10.h |  5 +
>>  2 files changed, 16 insertions(+)
>>
>> diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c
>> index 56e924d..145038d 100644
>> --- a/hw/arm/allwinner-a10.c
>> +++ b/hw/arm/allwinner-a10.c
>> @@ -42,6 +42,9 @@ static void aw_a10_init(Object *obj)
>>
>>  object_initialize(&s->ccm, sizeof(s->ccm), TYPE_AW_A10_CCM);
>>  qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
>> +
>> +object_initialize(&s->sata, sizeof(s->sata), TYPE_ALLWINNER_AHCI);
>> +qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default());
>>  }
>>
>>  static void aw_a10_realize(DeviceState *dev, Error **errp)
>> @@ -104,6 +107,14 @@ static void aw_a10_realize(DeviceState *dev, Error 
>> **errp)
>>  sysbusdev = SYS_BUS_DEVICE(&s->ccm);
>>  sysbus_mmio_map(sysbusdev, 0, AW_A10_CCM_REG_BASE);
>>
>> +object_property_set_bool(OBJECT(&s->sata), true, "realized", &err);
>> +if (err) {
>> +error_propagate(errp, err);
>> +return;
>> +}
>> +sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, AW_A10_SATA_BASE);
>> +sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, s->irq[56]);
>> +
>>  /* FIXME use a qdev chardev prop instead of serial_hds[] */
>>  serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2, s->irq[1],
>> 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
>> diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h
>> index 88632c0..e0daff8 100644
>> --- a/include/hw/arm/allwinner-a10.h
>> +++ b/include/hw/arm/allwinner-a10.h
>> @@ -8,6 +8,8 @@
>>  #include "hw/intc/allwinner-a10-pic.h"
>>  #include "hw/net/allwinner_emac.h"
>>  #include "hw/misc/allwinner-a10-ccm.h"
>> +#include "hw/ide/pci.h"
>> +#include "hw/ide/ahci.h"
>>
>>  #include "sysemu/sysemu.h"
>>  #include "exec/address-spaces.h"
>> @@ -18,6 +20,7 @@
>>  #define AW_A10_PIT_REG_BASE 0x01c20c00
>>  #define AW_A10_UART0_REG_BASE   0x01c28000
>>  #define AW_A10_EMAC_BASE0x01c0b000
>> +#define AW_A10_SATA_BASE0x01c18000
>>
>>  #define AW_A10_SDRAM_BASE   0x4000
>>
>> @@ -35,6 +38,8 @@ typedef struct AwA10State {
>>  AwA10PICState intc;
>>  AwEmacState emac;
>>  AwA10CCMState ccm;
>> +
>> +AllwinnerAHCIState sata;
>>  } AwA10State;
>>
>>  #define ALLWINNER_H_
>>
>
> Does this series have a pre-requisite patchset for this to apply cleanly?

Yes I need to drop out the CCM patches that I have in the branch in V2. Sorry.

Regards,
Peter

>
> --js



[Qemu-devel] [PATCH v8 14/18] qapi: Detect collisions in C member names

2015-10-12 Thread Eric Blake
Detect attempts to declare two object members that would result
in the same C member name, by keying the 'seen' dictionary off
of the C name rather than the qapi name.  It also requires passing
info through some of the check() methods.

This fixes two previously-broken tests, and the resulting error
messages demonstrate the utility of the .describe() method added
previously.  No change to generated code.

Signed-off-by: Eric Blake 

---
v8: rebase to earlier changes
v7: split out error reporting prep and member.c_name() addition
v6: rebase to earlier testsuite and info improvements
---
 scripts/qapi.py| 33 --
 tests/qapi-schema/args-name-clash.err  |  1 +
 tests/qapi-schema/args-name-clash.exit |  2 +-
 tests/qapi-schema/args-name-clash.json |  6 ++---
 tests/qapi-schema/args-name-clash.out  |  6 -
 tests/qapi-schema/flat-union-clash-branch.err  |  1 +
 tests/qapi-schema/flat-union-clash-branch.exit |  2 +-
 tests/qapi-schema/flat-union-clash-branch.json |  9 +++
 tests/qapi-schema/flat-union-clash-branch.out  | 14 ---
 9 files changed, 32 insertions(+), 42 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 8b29e11..58c4bb3 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -978,11 +978,11 @@ class QAPISchemaObjectType(QAPISchemaType):
 seen = {}
 for m in members:
 assert m.c_name() not in seen
-seen[m.name] = m
+seen[m.c_name()] = m
 for m in self.local_members:
-m.check(schema, members, seen)
+m.check(schema, self.info, members, seen)
 if self.variants:
-self.variants.check(schema, members, seen)
+self.variants.check(schema, self.info, members, seen)
 self.members = members

 def is_implicit(self):
@@ -1022,13 +1022,19 @@ class QAPISchemaObjectTypeMember(object):
 assert not self.owner
 self.owner = name

-def check(self, schema, all_members, seen):
+def check(self, schema, info, all_members, seen):
 assert self.owner
-assert self.name not in seen
 self.type = schema.lookup_type(self._type_name)
 assert self.type
+# Check that there is no collision in generated C names (which
+# also ensures no collisions in QMP names)
+if self.c_name() in seen:
+raise QAPIExprError(info,
+"%s collides with %s"
+% (self.describe(),
+   seen[self.c_name()].describe()))
 all_members.append(self)
-seen[self.name] = self
+seen[self.c_name()] = self

 def c_name(self):
 return c_name(self.name)
@@ -1088,23 +1094,24 @@ class QAPISchemaObjectTypeVariants(object):
 for v in self.variants:
 v.set_owner(name)

-def check(self, schema, members, seen):
+def check(self, schema, info, members, seen):
 if self.tag_name:
-self.tag_member = seen[self.tag_name]
+self.tag_member = seen[c_name(self.tag_name)]
+assert self.tag_name == self.tag_member.name
 else:
-self.tag_member.check(schema, members, seen)
+self.tag_member.check(schema, info, members, seen)
 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
 for v in self.variants:
 vseen = dict(seen)
-v.check(schema, self.tag_member.type, vseen)
+v.check(schema, info, self.tag_member.type, vseen)


 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
 def __init__(self, name, typ):
 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)

-def check(self, schema, tag_type, seen):
-QAPISchemaObjectTypeMember.check(self, schema, [], seen)
+def check(self, schema, info, tag_type, seen):
+QAPISchemaObjectTypeMember.check(self, schema, info, [], seen)
 assert self.name in tag_type.values

 # This function exists to support ugly simple union special cases
@@ -1129,7 +1136,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
 self.variants = variants

 def check(self, schema):
-self.variants.check(schema, [], {})
+self.variants.check(schema, self.info, [], {})

 def json_type(self):
 return 'value'
diff --git a/tests/qapi-schema/args-name-clash.err 
b/tests/qapi-schema/args-name-clash.err
index e69de29..2735217 100644
--- a/tests/qapi-schema/args-name-clash.err
+++ b/tests/qapi-schema/args-name-clash.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-name-clash.json:5: 'a_b' (argument of oops) collides 
with 'a-b' (argument of oops)
diff --git a/tests/qapi-schema/args-name-clash.exit 
b/tests/qapi-schema/args-name-clash.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/args-name-clash.exit
+++ b/tests/qapi-schema/args-name-clash.exit
@@ -1 +1 @@
-0
+1
diff --git a/te

[Qemu-devel] [PATCH v8 10/18] qapi: Move union tag quirks into subclass

2015-10-12 Thread Eric Blake
Right now, simple unions have a quirk of using 'kind' in the C
struct to match the QMP wire name 'type'.  This has resulted in
messy clients each doing special cases.  While we plan to
eventually rename things to match, it is better in the meantime
to consolidate the quirks into a special subclass, by adding a
new member.c_name() function.  This will also make it easier
for reworking how alternate types are laid out in a future
patch.  Use the new c_name() function where possible.

No change to generated code.

Signed-off-by: Eric Blake 

---
v7: new patch, but borrows idea of subclass from v6 10/12, as
well as c_name() from 7/12
---
 scripts/qapi-commands.py |  8 
 scripts/qapi-types.py| 12 +---
 scripts/qapi-visit.py| 17 +
 scripts/qapi.py  | 26 +++---
 4 files changed, 33 insertions(+), 30 deletions(-)

diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 43a893b..53a79ab 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -32,8 +32,8 @@ def gen_call(name, arg_type, ret_type):
 if arg_type:
 for memb in arg_type.members:
 if memb.optional:
-argstr += 'has_%s, ' % c_name(memb.name)
-argstr += '%s, ' % c_name(memb.name)
+argstr += 'has_' + memb.c_name() + ', '
+argstr += memb.c_name() + ', '

 lhs = ''
 if ret_type:
@@ -77,11 +77,11 @@ def gen_marshal_vars(arg_type, ret_type):
 ret += mcgen('''
 bool has_%(c_name)s = false;
 ''',
- c_name=c_name(memb.name))
+ c_name=memb.c_name())
 ret += mcgen('''
 %(c_type)s %(c_name)s = %(c_null)s;
 ''',
- c_name=c_name(memb.name),
+ c_name=memb.c_name(),
  c_type=memb.type.c_type(),
  c_null=memb.type.c_null())
 ret += '\n'
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 4fe618e..e37d529 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -136,9 +136,10 @@ struct %(c_name)s {
 ''')
 else:
 ret += mcgen('''
-%(c_type)s kind;
+%(c_type)s %(c_name)s;
 ''',
- c_type=c_name(variants.tag_member.type.name))
+ c_type=variants.tag_member.type.c_name(),
+ c_name=variants.tag_member.c_name())

 # FIXME: What purpose does data serve, besides preventing a union that
 # has a branch named 'data'? We use it in qapi-visit.py to decide
@@ -152,10 +153,7 @@ struct %(c_name)s {
 union { /* union tag is @%(c_name)s */
 void *data;
 ''',
- # TODO ugly special case for simple union
- # Use same tag name in C as on the wire to get rid of
- # it, then: c_name=c_name(variants.tag_member.name)
- c_name=c_name(variants.tag_name or 'kind'))
+ c_name=variants.tag_member.c_name())

 for var in variants.variants:
 # Ugly special case for simple union TODO get rid of it
@@ -164,7 +162,7 @@ struct %(c_name)s {
 %(c_type)s %(c_name)s;
 ''',
  c_type=typ.c_type(),
- c_name=c_name(var.name))
+ c_name=var.c_name())

 ret += mcgen('''
 };
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 2a9fab8..cb251b2 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -196,7 +196,7 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, 
const char *name, Error
  case=c_enum_const(variants.tag_member.type.name,
var.name),
  c_type=var.type.c_name(),
- c_name=c_name(var.name))
+ c_name=var.c_name())

 ret += mcgen('''
 default:
@@ -249,10 +249,6 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, 
const char *name, Error
  c_name=c_name(name))
 ret += gen_err_check(label='out_obj')

-tag_key = variants.tag_member.name
-if not variants.tag_name:
-# we pointlessly use a different key for simple unions
-tag_key = 'type'
 ret += mcgen('''
 visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
 if (err) {
@@ -264,11 +260,8 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, 
const char *name, Error
 switch ((*obj)->%(c_name)s) {
 ''',
  c_type=variants.tag_member.type.c_name(),
- # TODO ugly special case for simple union
- # Use same tag name in C as on the wire to get rid of
- # it, then: c_name=c_name(variants.tag_member.name)
- c_name=c_name(variants.tag_name or 'kind'),
- name=tag_key)
+ c_name=variants.tag_member.c_name(),
+ name=variants.tag_member.name)

 for v

[Qemu-devel] [PATCH v8 12/18] qapi: Track location that created an implicit type

2015-10-12 Thread Eric Blake
A future patch will move some error checking from the parser
to the various QAPISchema*.check() methods, which run only
after parsing completes.  It will thus be possible to create
a python instance representing an implicit QAPI type that
parses fine but will fail validation during check().  Since
all errors have to have an associated 'info' location, we
need a location to be associated with those implicit types.
The intuitive info to use is the location of the enclosing
entity that caused the creation of the implicit type; similar
to what was done for array types in an earlier patch.

Note that we do not anticipate builtin types being used in
an error message (as they are not part of the user's QAPI
input, the user can't cause a semantic error in their
behavior), so we exempt those types from requiring info, by
setting a flag to track the completion of _def_predefineds(),
and tracking that flag in _def_entity().

No change to the generated code.

Signed-off-by: Eric Blake 

---
v8: rebase to earlier changes, improve comment, rework predefined
flag name
v7: better commit message and comments, fix info assertion to
use instance flag rather than ugly leaky abstraction static flag
v6: improve commit message, track implicit enum info, rebase
on new lazy array handling
---
 scripts/qapi.py | 32 ++--
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 80c026b..c9ce9ee 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -793,9 +793,9 @@ class QAPISchemaEntity(object):
 # For explicitly defined entities, info points to the (explicit)
 # definition.  For builtins (and their arrays), info is None.
 # For other arrays, info points to an explicit place that uses
-# the array (there may be more than one such place).
-# TODO For other implicitly defined entities, it should point to
-# a place that triggers implicit definition.
+# the array (there may be more than one such place).  For other
+# implicitly defined entities, it points to the place that
+# triggered the implicit definition.
 self.info = info

 def c_name(self):
@@ -1146,7 +1146,9 @@ class QAPISchema(object):
 try:
 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
 self._entity_dict = {}
+self._predefining = True
 self._def_predefineds()
+self._predefining = False
 self._def_exprs()
 self.check()
 except (QAPISchemaError, QAPIExprError), err:
@@ -1154,6 +1156,8 @@ class QAPISchema(object):
 exit(1)

 def _def_entity(self, ent):
+# Only the predefined types are allowed to not have info
+assert ent.info or self._predefining
 assert ent.name not in self._entity_dict
 self._entity_dict[ent.name] = ent

@@ -1196,9 +1200,9 @@ class QAPISchema(object):
   [], None)
 self._def_entity(self.the_empty_object_type)

-def _make_implicit_enum_type(self, name, values):
+def _make_implicit_enum_type(self, name, info, values):
 name = name + 'Kind'   # Use namespace reserved by add_name()
-self._def_entity(QAPISchemaEnumType(name, None, values, None))
+self._def_entity(QAPISchemaEnumType(name, info, values, None))
 return name

 def _make_array_type(self, element_type, info):
@@ -1209,12 +1213,12 @@ class QAPISchema(object):
 self._def_entity(QAPISchemaArrayType(name, info, element_type))
 return name

-def _make_implicit_object_type(self, name, role, members):
+def _make_implicit_object_type(self, name, info, role, members):
 if not members:
 return None
 name = ':obj-%s-%s' % (name, role)
 if not self.lookup_entity(name, QAPISchemaObjectType):
-self._def_entity(QAPISchemaObjectType(name, None, None,
+self._def_entity(QAPISchemaObjectType(name, info, None,
   members, None))
 return name

@@ -1254,11 +1258,11 @@ class QAPISchema(object):
 assert len(typ) == 1
 typ = self._make_array_type(typ[0], info)
 typ = self._make_implicit_object_type(
-typ, 'wrapper', [self._make_member('data', typ, info)])
+typ, info, 'wrapper', [self._make_member('data', typ, info)])
 return QAPISchemaObjectTypeVariant(case, typ)

-def _make_implicit_tag(self, type_name, variants):
-typ = self._make_implicit_enum_type(type_name,
+def _make_implicit_tag(self, type_name, info, variants):
+typ = self._make_implicit_enum_type(type_name, info,
 [v.name for v in variants])
 return QAPISchemaObjectTypeUnionTag('type', typ, False)

@@ -1274,7 +1278,7 @@ class QAPISchema(object):
 else:
  

[Qemu-devel] [PATCH v8 15/18] qapi: Move duplicate member checks to schema check()

2015-10-12 Thread Eric Blake
With the previous commit, we have two different locations for
detecting member name clashes - one at parse time, and another
at QAPISchema*.check() time.  Consolidate some of the checks
into a single place, which is also in line with our TODO to
eventually move all of the parse time semantic checking into
the newer schema code.  The check_member_clash() function is
no longer needed.

Checking variants is tricky: we need to check that the branch
name will not cause a collision (important for C code, but
no bearing on QMP).  Then, if the variant belongs to a union
(flat or simple), we need to check that QMP members of that
type will not collide with non-variant QMP members (but do
not care if they collide with C branch names).  Each call to
variant.check() has a 'seen' that contains all [*] non-variant
C names (which includes all non-variant QMP names), but does
not add to that array (QMP members of one branch do not cause
collisions with other branches).  This means that there is
one form of collision we still miss: when two branch names
collide.  However, that will be dealt with in the next patch.

[*] Exception - the 'seen' array doesn't contain 'base', which
is currently a non-variant C member of structs; but since
structs don't contain variants, it doesn't hurt. Besides, a
later patch will be unboxing structs the way flat unions
have already been unboxed.

The wording of several error messages has changed, but in many
cases feels like an improvement rather than a regression.  The
recent change (commit 7b2a5c2) to avoid an assertion failure
when a flat union branch name collides with its discriminator
name is also handled nicely by this code; but there is more work
needed before we can detect all collisions in simple union branch
names done by the old code.

No change to generated code.

Signed-off-by: Eric Blake 

---
v8: decide whether to inline members based on union vs. alternate,
not on flat vs. simple, and fix logic to avoid breaking
union-clash-data in the process; add comments; assumes
pull-qapi-2015-10-12 will go in without modifying commit ids
v7: comment improvements, retitle subject
v6: rebase to earlier testsuite improvements, fold in cleanup
of flat-union-clash-type
---
 scripts/qapi.py   | 70 ---
 tests/qapi-schema/flat-union-clash-member.err |  2 +-
 tests/qapi-schema/flat-union-clash-type.err   |  2 +-
 tests/qapi-schema/struct-base-clash-deep.err  |  2 +-
 tests/qapi-schema/struct-base-clash.err   |  2 +-
 5 files changed, 36 insertions(+), 42 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 58c4bb3..144dd4a 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -496,21 +496,6 @@ def check_type(expr_info, source, value, allow_array=False,
 'enum'])


-def check_member_clash(expr_info, base_name, data, source=""):
-base = find_struct(base_name)
-assert base
-base_members = base['data']
-for key in data.keys():
-if key.startswith('*'):
-key = key[1:]
-if key in base_members or "*" + key in base_members:
-raise QAPIExprError(expr_info,
-"Member name '%s'%s clashes with base '%s'"
-% (key, source, base_name))
-if base.get('base'):
-check_member_clash(expr_info, base['base'], data, source)
-
-
 def check_command(expr, expr_info):
 name = expr['command']

@@ -589,30 +574,18 @@ def check_union(expr, expr_info):
 for (key, value) in members.items():
 check_name(expr_info, "Member of union '%s'" % name, key)

-# Each value must name a known type; furthermore, in flat unions,
-# branches must be a struct with no overlapping member names
+# Each value must name a known type
 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
value, allow_array=not base, allow_metas=allow_metas)
-if base:
-branch_struct = find_struct(value)
-assert branch_struct
-check_member_clash(expr_info, base, branch_struct['data'],
-   " of branch '%s'" % key)

 # If the discriminator names an enum type, then all members
-# of 'data' must also be members of the enum type, which in turn
-# must not collide with the discriminator name.
+# of 'data' must also be members of the enum type.
 if enum_define:
 if key not in enum_define['enum_values']:
 raise QAPIExprError(expr_info,
 "Discriminator value '%s' is not found in "
 "enum '%s'" %
 (key, enum_define["enum_name"]))
-if discriminator in enum_define['enum_values']:
-raise QAPIExprError(expr_info,
-"Discriminator name '%s' collides with "
-  

[Qemu-devel] [PATCH v8 11/18] qapi: Simplify gen_struct_field()

2015-10-12 Thread Eric Blake
Rather than having all callers pass a name, type, and optional
flag, have them instead pass a QAPISchemaObjectTypeMember which
already has all that information.

This will allow a future patch to simplify alternates to use
a special tag 'qtype_code type'.  In the meantime, it requires
a hack to create a temporary member 'base' for struct base
classes; this temporary member will go away in a later patch
that flattens structs in the same way that flat union base
classes were flattened in commit 1e6c1616.

No change to generated code.

Signed-off-by: Eric Blake 

---
v8: new patch
---
 scripts/qapi-types.py | 16 ++--
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index e37d529..5ffabf5 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -36,18 +36,18 @@ struct %(c_name)s {
  c_name=c_name(name), c_type=element_type.c_type())


-def gen_struct_field(name, typ, optional):
+def gen_struct_field(member):
 ret = ''

-if optional:
+if member.optional:
 ret += mcgen('''
 bool has_%(c_name)s;
 ''',
- c_name=c_name(name))
+ c_name=member.c_name())
 ret += mcgen('''
 %(c_type)s %(c_name)s;
 ''',
- c_type=typ.c_type(), c_name=c_name(name))
+ c_type=member.type.c_type(), c_name=member.c_name())
 return ret


@@ -55,7 +55,7 @@ def gen_struct_fields(members):
 ret = ''

 for memb in members:
-ret += gen_struct_field(memb.name, memb.type, memb.optional)
+ret += gen_struct_field(memb)
 return ret


@@ -67,7 +67,11 @@ struct %(c_name)s {
 c_name=c_name(name))

 if base:
-ret += gen_struct_field('base', base, False)
+# TODO Flatten this struct, similar to flat union bases. Until
+# then, hack around it with a temporary member.
+member = QAPISchemaObjectTypeMember('base', base.name, False)
+member.type = base
+ret += gen_struct_field(member)

 ret += gen_struct_fields(members)

-- 
2.4.3




[Qemu-devel] [PATCH v8 13/18] qapi: Track owner of each object member

2015-10-12 Thread Eric Blake
Future commits will migrate semantic checking away from parsing
and over to the various QAPISchema*.check() methods.  But to
report an error message about an incorrect semantic use of a
member of an object type, it helps to know which type, command,
or event owns the member.  In particular, when a member is
inherited from a base type, it is desirable to associate the
member name with the base type (and not the type calling
member.check()).

Rather than packing additional information into the seen array
passed to each member.check() (as in seen[m.name] = {'member':m,
'owner':type}), it is easier to have each member track the name
of the owner type in the first place (keeping things simpler
with the existing seen[m.name] = m).  The new member.owner field
is set via a new set_owner() function, called when registering
the members and variants arrays with an object or variant type.
Track only a name, and not the actual type object, to avoid
creating a circular python reference chain.

The source information is intended for human consumption in
error messages, and a new describe() method is added to access
the resulting information.  For example, given the qapi:
  { 'command': 'foo', 'data': { 'string': 'str' } }
an implementation of visit_command() that calls
  arg_type.members[0].describe()
will see "'string' (argument of foo)".

To make the human-readable name of implicit types work without
duplicating efforts, the describe() method has to reverse the
name of implicit types.

No change to generated code.

Signed-off-by: Eric Blake 

---
v8: don't munge implicit type names [except for event data], and
instead make describe() create nicer messages. Add set_owner(), and
use field 'role' instead of method _describe()
v7: total rewrite: rework implicit object names, assign owner
when initializing owner type rather than when creating member
python object
v6: rebase on new lazy array creation and simple union 'type'
motion; tweak commit message
---
 scripts/qapi.py| 48 +++---
 tests/qapi-schema/qapi-schema-test.out |  8 +++---
 2 files changed, 49 insertions(+), 7 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index c9ce9ee..8b29e11 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -952,8 +952,10 @@ class QAPISchemaObjectType(QAPISchemaType):
 assert base is None or isinstance(base, str)
 for m in local_members:
 assert isinstance(m, QAPISchemaObjectTypeMember)
-assert (variants is None or
-isinstance(variants, QAPISchemaObjectTypeVariants))
+m.set_owner(name)
+if variants is not None:
+assert isinstance(variants, QAPISchemaObjectTypeVariants)
+variants.set_owner(name)
 self._base_name = base
 self.base = None
 self.local_members = local_members
@@ -1014,8 +1016,14 @@ class QAPISchemaObjectTypeMember(object):
 self._type_name = typ
 self.type = None
 self.optional = optional
+self.owner = None
+
+def set_owner(self, name):
+assert not self.owner
+self.owner = name

 def check(self, schema, all_members, seen):
+assert self.owner
 assert self.name not in seen
 self.type = schema.lookup_type(self._type_name)
 assert self.type
@@ -1025,6 +1033,25 @@ class QAPISchemaObjectTypeMember(object):
 def c_name(self):
 return c_name(self.name)

+def describe(self):
+owner = self.owner
+# See QAPISchema._make_implicit_object_type() - reverse the
+# mapping there to create a nice human-readable description
+if owner.startswith(':obj-'):
+owner = owner[5:]
+if owner.endswith('-arg'):
+source = '(argument of %s)' % owner[:4]
+elif owner.endswith('-data'):
+source = '(data of %s)' % owner[:5]
+else:
+assert owner.endswith('-wrapper')
+source = '(branch of %s)' % owner[:8]
+else:
+source = '(%s of %s)' % (self.role, owner)
+return "'%s' %s" % (self.name, source)
+
+role = 'member'
+

 # TODO Drop this class once we no longer have the 'type'/'kind' mismatch
 class QAPISchemaObjectTypeUnionTag(QAPISchemaObjectTypeMember):
@@ -1034,6 +1061,11 @@ class 
QAPISchemaObjectTypeUnionTag(QAPISchemaObjectTypeMember):
 assert self.type.is_implicit()
 return 'kind'

+def describe(self):
+# Must override superclass describe() because self.name is 'type'
+assert self.owner[0] != ':'
+return "'kind' (implicit tag of %s)" % self.owner
+

 class QAPISchemaObjectTypeVariants(object):
 def __init__(self, tag_name, tag_member, variants):
@@ -1050,6 +1082,12 @@ class QAPISchemaObjectTypeVariants(object):
 self.tag_member = tag_member
 self.variants = variants

+def set_owner(self, name):
+if self.tag_member:
+   

[Qemu-devel] [PATCH v8 00/18] post-introspection cleanups, subset B

2015-10-12 Thread Eric Blake
Pending prerequisite: Markus' qapi-next branch (which has my
subset A patches):
git://repo.or.cz/qemu/armbru.git pull-qapi-2015-10-12
https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02796.html

Also available as a tag at this location:
git fetch git://repo.or.cz/qemu/ericb.git qapi-cleanupv8b

and I plan to eventually forcefully update my branch with the rest
of the v5 series, at:
http://repo.or.cz/qemu/ericb.git/shortlog/refs/heads/qapi

v8 notes:
Address review comments, including fixing a bug with tracking
branch name collisions. Include a few more simple test cleanups
(4-6), and add another patch (11) that will make converting from
kind=>type easier in a later subset.  More details in per-patch
changelogs.

001/18:[] [--] 'qapi: Use predicate callback to determine visit filtering'
002/18:[] [--] 'qapi: Prepare for errors during check()'
003/18:[] [--] 'qapi: Drop redundant alternate-good test'
004/18:[down] 'qapi: Move empty-enum to compile-time test'
005/18:[down] 'qapi: Drop redundant returns-int test'
006/18:[down] 'qapi: Drop redundant flat-union-reverse-define test'
007/18:[0026] [FC] 'qapi: Don't use info as witness of implicit object type'
008/18:[0005] [FC] 'qapi: Lazy creation of array types'
009/18:[0010] [FC] 'qapi: Create simple union type member earlier'
010/18:[0017] [FC] 'qapi: Move union tag quirks into subclass'
011/18:[down] 'qapi: Simplify gen_struct_field()'
012/18:[0027] [FC] 'qapi: Track location that created an implicit type'
013/18:[0165] [FC] 'qapi: Track owner of each object member'
014/18:[0006] [FC] 'qapi: Detect collisions in C member names'
015/18:[0033] [FC] 'qapi: Move duplicate member checks to schema check()'
016/18:[0007] [FC] 'qapi: Move duplicate enum value checks to schema check()'
017/18:[] [-C] 'qapi: Add test for alternate branch 'kind' clash'
018/18:[] [--] 'qapi: Detect base class loops'

v7 notes:
https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg01387.html
Address comments, including a couple of new commits that made
later patches a bit cleaner.  Backport diff gets a bit confused
by a couple of patch titles changing.

v6 notes:
https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg00562.html
This is patches 11-16 of my v5 series; it has grown a bit with
splitting some patches and adding some others.  I suspect that
12/12 on this series will be discarded, but am including it because
it was split from v5 content.

Not much review comments other than on the original 11/46, but there
is enough churn due to rebasing that it's now easier to review this
version than plowing through v5.

Subset C (and more?) will come later.

In v5:
https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg05410.html
I _did_ rearrange patches to try and group related features:

1-2: Groundwork cleanups
3-5: Add more test cases
6-16: Front-end cleanups
17-18: Introspection output cleanups
19-20: 'alternate' type cleanups
21-29: qapi visitor cleanups
30-45: qapi-ify netdev_add
46: add qapi shorthand for flat unions

Lots of fixes based on additional testing, and rebased to
track other changes that happened in the meantime.  The series
is huge; I can split off smaller portions as requested.

In v4:
https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg02580.html
add some more clean up patches
rebase to Markus' recent work
pull in part of Zoltán's work to make netdev_add a flat union,
further enhancing it to be introspectible

I might be able to rearrange some of these patches, or separate
it into smaller independent series, if requested; but I'm
posting now to get review started.

In v3:
https://lists.gnu.org/archive/html/qemu-devel/2015-08/msg02059.html
redo cleanup of dealloc of partial struct
add patches to make all visit_type_*() avoid leaks on failure
add patches to allow boxed command arguments and events

In v2:
https://lists.gnu.org/archive/html/qemu-devel/2015-08/msg00900.html
rebase to Markus' v3 series
rework how comments are emitted for fields inherited from base
additional patches added for deleting colliding 'void *data'
documentation updates to match code changes

v1 was here:
https://lists.gnu.org/archive/html/qemu-devel/2015-07/msg05266.html
https://lists.gnu.org/archive/html/qemu-devel/2015-07/msg05325.html

Eric Blake (18):
  qapi: Use predicate callback to determine visit filtering
  qapi: Prepare for errors during check()
  qapi: Drop redundant alternate-good test
  qapi: Move empty-enum to compile-time test
  qapi: Drop redundant returns-int test
  qapi: Drop redundant flat-union-reverse-define test
  qapi: Don't use info as witness of implicit object type
  qapi: Lazy creation of array types
  qapi: Create simple union type member earlier
  qapi: Move union tag quirks into subclass
  qapi: Simplify gen_struct_field()
  qapi: Track location that created an implicit type
  qapi: Track owner of each object member
  qapi: Detect collisions in C member names
  qapi: Move duplicate member checks to schema check()
  qapi: Move du

[Qemu-devel] [PATCH v8 09/18] qapi: Create simple union type member earlier

2015-10-12 Thread Eric Blake
For simple unions, we were creating the implicit 'type' tag
member during the QAPISchemaObjectTypeVariants constructor.
This is different from every other implicit QAPISchemaEntity
object, which get created by QAPISchema methods.  Hoist the
creation to the caller (renaming _make_tag_enum() to
_make_implicit_tag()), and pass the entity rather than the
string name, so that we have the nice property that no
entities are created as a side effect within a different
entity.  A later patch will then have an easier time of
associating location info with each entity creation.

No change to generated code.

Signed-off-by: Eric Blake 

---
v8: rename tag_enum to tag_member
v7: Rework assertions, rename to _make_implicit_tag()
v6: New patch
---
 scripts/qapi.py | 35 ++-
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 73080e3..5b66264 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1024,18 +1024,18 @@ class QAPISchemaObjectTypeMember(object):


 class QAPISchemaObjectTypeVariants(object):
-def __init__(self, tag_name, tag_enum, variants):
-assert tag_name is None or isinstance(tag_name, str)
-assert tag_enum is None or isinstance(tag_enum, str)
+def __init__(self, tag_name, tag_member, variants):
+# Flat unions pass tag_name but not tag_member.
+# Simple unions and alternates pass tag_member but not tag_name.
+# After check(), tag_member is always set, and tag_name remains
+# a reliable witness of being used by a flat union.
+assert bool(tag_member) != bool(tag_name)
+assert (isinstance(tag_name, str) or
+isinstance(tag_member, QAPISchemaObjectTypeMember))
 for v in variants:
 assert isinstance(v, QAPISchemaObjectTypeVariant)
 self.tag_name = tag_name
-if tag_name:
-assert not tag_enum
-self.tag_member = None
-else:
-self.tag_member = QAPISchemaObjectTypeMember('type', tag_enum,
- False)
+self.tag_member = tag_member
 self.variants = variants

 def check(self, schema, members, seen):
@@ -1245,28 +1245,29 @@ class QAPISchema(object):
 typ, 'wrapper', [self._make_member('data', typ, info)])
 return QAPISchemaObjectTypeVariant(case, typ)

-def _make_tag_enum(self, type_name, variants):
-return self._make_implicit_enum_type(type_name,
- [v.name for v in variants])
+def _make_implicit_tag(self, type_name, variants):
+typ = self._make_implicit_enum_type(type_name,
+[v.name for v in variants])
+return QAPISchemaObjectTypeMember('type', typ, False)

 def _def_union_type(self, expr, info):
 name = expr['union']
 data = expr['data']
 base = expr.get('base')
 tag_name = expr.get('discriminator')
-tag_enum = None
+tag_member = None
 if tag_name:
 variants = [self._make_variant(key, value)
 for (key, value) in data.iteritems()]
 else:
 variants = [self._make_simple_variant(key, value, info)
 for (key, value) in data.iteritems()]
-tag_enum = self._make_tag_enum(name, variants)
+tag_member = self._make_implicit_tag(name, variants)
 self._def_entity(
 QAPISchemaObjectType(name, info, base,
  self._make_members(OrderedDict(), info),
  QAPISchemaObjectTypeVariants(tag_name,
-  tag_enum,
+  tag_member,
   variants)))

 def _def_alternate_type(self, expr, info):
@@ -1274,11 +1275,11 @@ class QAPISchema(object):
 data = expr['data']
 variants = [self._make_variant(key, value)
 for (key, value) in data.iteritems()]
-tag_enum = self._make_tag_enum(name, variants)
+tag_member = self._make_implicit_tag(name, variants)
 self._def_entity(
 QAPISchemaAlternateType(name, info,
 QAPISchemaObjectTypeVariants(None,
- tag_enum,
+ tag_member,
  variants)))

 def _def_command(self, expr, info):
-- 
2.4.3




[Qemu-devel] [PATCH v8 07/18] qapi: Don't use info as witness of implicit object type

2015-10-12 Thread Eric Blake
A future patch will enable error reporting from the various
QAPISchema*.check() methods.  But to report an error related
to an implicit type, we'll need to associate a location with
the type (the same location as the top-level entity that is
causing the creation of the implicit type), and once we do
that, keying off of whether foo.info exists is no longer a
viable way to determine if foo is an implicit type.

Instead, add an is_implicit() method to QAPISchemaEntity, with
overrides for ObjectType and EnumType, and use that function
where needed.

Signed-off-by: Eric Blake 

---
v8: separate isinstance back to verbose form, add comments
v7: declare at the Entity level, with an optional argument for
filtering by sub-class
v6: split 11/46 into pieces; don't rename _info yet; rework atop
nicer filtering mechanism, including no need to change visitor
signature
---
 scripts/qapi-types.py |  3 ++-
 scripts/qapi-visit.py |  3 ++-
 scripts/qapi.py   | 22 ++
 3 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 2a29c6e..4fe618e 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -235,7 +235,8 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):

 def visit_needed(self, entity):
 # Visit everything except implicit objects
-return not isinstance(entity, QAPISchemaObjectType) or entity.info
+return not (entity.is_implicit() and
+isinstance(entity, QAPISchemaObjectType))

 def _gen_type_cleanup(self, name):
 self.decl += gen_type_cleanup_decl(name)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 9fc79a7..2a9fab8 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -335,7 +335,8 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):

 def visit_needed(self, entity):
 # Visit everything except implicit objects
-return not isinstance(entity, QAPISchemaObjectType) or entity.info
+return not (entity.is_implicit() and
+isinstance(entity, QAPISchemaObjectType))

 def visit_enum_type(self, name, info, values, prefix):
 self.decl += gen_visit_decl(name, scalar=True)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 68f97a1..e263ecf 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -798,6 +798,9 @@ class QAPISchemaEntity(object):
 def check(self, schema):
 pass

+def is_implicit(self):
+return not self.info
+
 def visit(self, visitor):
 pass

@@ -900,6 +903,10 @@ class QAPISchemaEnumType(QAPISchemaType):
 def check(self, schema):
 assert len(set(self.values)) == len(self.values)

+def is_implicit(self):
+# See QAPISchema._make_implicit_enum_type()
+return self.name[-4:] == 'Kind'
+
 def c_type(self, is_param=False):
 return c_name(self.name)

@@ -970,12 +977,16 @@ class QAPISchemaObjectType(QAPISchemaType):
 self.variants.check(schema, members, seen)
 self.members = members

+def is_implicit(self):
+# See QAPISchema._make_implicit_object_type()
+return self.name[0] == ':'
+
 def c_name(self):
-assert self.info
+assert not self.is_implicit()
 return QAPISchemaType.c_name(self)

 def c_type(self, is_param=False):
-assert self.info
+assert not self.is_implicit()
 return QAPISchemaType.c_type(self)

 def json_type(self):
@@ -1043,7 +1054,8 @@ class 
QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
 # This function exists to support ugly simple union special cases
 # TODO get rid of them, and drop the function
 def simple_union_type(self):
-if isinstance(self.type, QAPISchemaObjectType) and not self.type.info:
+if (self.type.is_implicit() and
+isinstance(self.type, QAPISchemaObjectType)):
 assert len(self.type.members) == 1
 assert not self.type.variants
 return self.type.members[0].type
@@ -1162,11 +1174,13 @@ class QAPISchema(object):
 self._def_entity(self.the_empty_object_type)

 def _make_implicit_enum_type(self, name, values):
-name = name + 'Kind'
+name = name + 'Kind'   # Use namespace reserved by add_name()
 self._def_entity(QAPISchemaEnumType(name, None, values, None))
 return name

 def _make_array_type(self, element_type):
+# TODO fooList namespace is not reserved; user can create collisions,
+# or abuse our type system with ['fooList'] for 2D array
 name = element_type + 'List'
 if not self.lookup_type(name):
 self._def_entity(QAPISchemaArrayType(name, None, element_type))
-- 
2.4.3




[Qemu-devel] [PATCH v8 01/18] qapi: Use predicate callback to determine visit filtering

2015-10-12 Thread Eric Blake
Previously, qapi-types and qapi-visit filtered out implicit
objects during visit_object_type() by using 'info' (works since
implicit objects do not [yet] have associated info); meanwhile
qapi-introspect filtered out all schema types on the first pass
by returning a python type from visit_begin(), which was then
used at a distance in QAPISchema.visit() to do the filtering.

Rather than keeping these ad hoc approaches, add a new visitor
callback visit_needed() which returns False to skip a given
entity, and which defaults to True unless overridden.  Use the
new mechanism to simplify all three filtering visitors.

No change to the generated code.

Suggested-by: Markus Armbruster 
Signed-off-by: Eric Blake 

---
v8: no change
v7: rename to visit_needed(), add comment
v6: new patch
---
 scripts/qapi-introspect.py |  5 -
 scripts/qapi-types.py  | 19 +++
 scripts/qapi-visit.py  | 17 ++---
 scripts/qapi.py| 12 
 4 files changed, 33 insertions(+), 20 deletions(-)

diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 7d39320..c0dad66 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -54,7 +54,6 @@ class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor):
 self._jsons = []
 self._used_types = []
 self._name_map = {}
-return QAPISchemaType   # don't visit types for now

 def visit_end(self):
 # visit the types that are actually used
@@ -82,6 +81,10 @@ const char %(c_name)s[] = %(c_string)s;
 self._used_types = None
 self._name_map = None

+def visit_needed(self, entity):
+# Ignore types on first pass; visit_end() will pick up used types
+return not isinstance(entity, QAPISchemaType)
+
 def _name(self, name):
 if self._unmask:
 return name
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index d405f8d..2a29c6e 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -233,6 +233,10 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
 self.decl = self._btin + self.decl
 self._btin = None

+def visit_needed(self, entity):
+# Visit everything except implicit objects
+return not isinstance(entity, QAPISchemaObjectType) or entity.info
+
 def _gen_type_cleanup(self, name):
 self.decl += gen_type_cleanup_decl(name)
 self.defn += gen_type_cleanup(name)
@@ -254,14 +258,13 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
 self._gen_type_cleanup(name)

 def visit_object_type(self, name, info, base, members, variants):
-if info:
-self._fwdecl += gen_fwd_object_or_array(name)
-if variants:
-assert not members  # not implemented
-self.decl += gen_union(name, base, variants)
-else:
-self.decl += gen_struct(name, base, members)
-self._gen_type_cleanup(name)
+self._fwdecl += gen_fwd_object_or_array(name)
+if variants:
+assert not members  # not implemented
+self.decl += gen_union(name, base, variants)
+else:
+self.decl += gen_struct(name, base, members)
+self._gen_type_cleanup(name)

 def visit_alternate_type(self, name, info, variants):
 self._fwdecl += gen_fwd_object_or_array(name)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 4f97781..9fc79a7 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -333,6 +333,10 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
 self.decl = self._btin + self.decl
 self._btin = None

+def visit_needed(self, entity):
+# Visit everything except implicit objects
+return not isinstance(entity, QAPISchemaObjectType) or entity.info
+
 def visit_enum_type(self, name, info, values, prefix):
 self.decl += gen_visit_decl(name, scalar=True)
 self.defn += gen_visit_enum(name)
@@ -349,13 +353,12 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
 self.defn += defn

 def visit_object_type(self, name, info, base, members, variants):
-if info:
-self.decl += gen_visit_decl(name)
-if variants:
-assert not members  # not implemented
-self.defn += gen_visit_union(name, base, variants)
-else:
-self.defn += gen_visit_struct(name, base, members)
+self.decl += gen_visit_decl(name)
+if variants:
+assert not members  # not implemented
+self.defn += gen_visit_union(name, base, variants)
+else:
+self.defn += gen_visit_struct(name, base, members)

 def visit_alternate_type(self, name, info, variants):
 self.decl += gen_visit_decl(name)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 26cff3f..543b378 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ 

[Qemu-devel] [PATCH v8 05/18] qapi: Drop redundant returns-int test

2015-10-12 Thread Eric Blake
qapi-schema-test was already testing that we could have a
command returning int, but burned a command name in the whitelist.
Merge the redundant positive test returns-int, and pick a name
that reduces the whitelist size.

Signed-off-by: Eric Blake 

---
v8: (no v7) hoist from subset C into B
v6: new patch; could be hoisted earlier alongside subset B v7 3/17
---
 scripts/qapi.py |  3 ---
 tests/Makefile  |  1 -
 tests/qapi-schema/qapi-schema-test.json |  5 +++--
 tests/qapi-schema/qapi-schema-test.out  | 10 +-
 tests/qapi-schema/returns-int.err   |  0
 tests/qapi-schema/returns-int.exit  |  1 -
 tests/qapi-schema/returns-int.json  |  3 ---
 tests/qapi-schema/returns-int.out   |  3 ---
 tests/test-qmp-commands.c   |  4 ++--
 9 files changed, 10 insertions(+), 20 deletions(-)
 delete mode 100644 tests/qapi-schema/returns-int.err
 delete mode 100644 tests/qapi-schema/returns-int.exit
 delete mode 100644 tests/qapi-schema/returns-int.json
 delete mode 100644 tests/qapi-schema/returns-int.out

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 4573599..68f97a1 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -56,9 +56,6 @@ returns_whitelist = [
 'guest-set-vcpus',
 'guest-sync',
 'guest-sync-delimited',
-
-# From qapi-schema-test:
-'user_def_cmd3',
 ]

 enum_types = []
diff --git a/tests/Makefile b/tests/Makefile
index e058312..3512f8c 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -318,7 +318,6 @@ qapi-schema += redefined-type.json
 qapi-schema += returns-alternate.json
 qapi-schema += returns-array-bad.json
 qapi-schema += returns-dict.json
-qapi-schema += returns-int.json
 qapi-schema += returns-unknown.json
 qapi-schema += returns-whitelist.json
 qapi-schema += struct-base-clash-base.json
diff --git a/tests/qapi-schema/qapi-schema-test.json 
b/tests/qapi-schema/qapi-schema-test.json
index c8cd2dd..67c6bca 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -104,9 +104,10 @@
 { 'command': 'user_def_cmd2',
   'data': {'ud1a': 'UserDefOne', '*ud1b': 'UserDefOne'},
   'returns': 'UserDefTwo' }
-{ 'command': 'user_def_cmd3', 'data': {'a': 'int', '*b': 'int' },
+
+# Returning a non-dictionary requires a name from the whitelist
+{ 'command': 'guest-get-time', 'data': {'a': 'int', '*b': 'int' },
   'returns': 'int' }
-# note: command name 'guest-sync' chosen to avoid "cannot use built-in" error
 { 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' }

 # For testing integer range flattening in opts-visitor. The following schema
diff --git a/tests/qapi-schema/qapi-schema-test.out 
b/tests/qapi-schema/qapi-schema-test.out
index e3504ab..93f6250 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -17,6 +17,9 @@ object :obj-anyList-wrapper
 member data: anyList optional=False
 object :obj-boolList-wrapper
 member data: boolList optional=False
+object :obj-guest-get-time-arg
+member a: int optional=False
+member b: int optional=True
 object :obj-guest-sync-arg
 member arg: any optional=False
 object :obj-int16List-wrapper
@@ -50,9 +53,6 @@ object :obj-user_def_cmd1-arg
 object :obj-user_def_cmd2-arg
 member ud1a: UserDefOne optional=False
 member ud1b: UserDefOne optional=True
-object :obj-user_def_cmd3-arg
-member a: int optional=False
-member b: int optional=True
 alternate AltIntNum
 case i: int
 case n: number
@@ -184,6 +184,8 @@ object __org.qemu_x-Union2
 case __org.qemu_x-value: __org.qemu_x-Struct2
 command __org.qemu_x-command :obj-__org.qemu_x-command-arg -> 
__org.qemu_x-Union1
gen=True success_response=True
+command guest-get-time :obj-guest-get-time-arg -> int
+   gen=True success_response=True
 command guest-sync :obj-guest-sync-arg -> any
gen=True success_response=True
 command user_def_cmd None -> None
@@ -192,5 +194,3 @@ command user_def_cmd1 :obj-user_def_cmd1-arg -> None
gen=True success_response=True
 command user_def_cmd2 :obj-user_def_cmd2-arg -> UserDefTwo
gen=True success_response=True
-command user_def_cmd3 :obj-user_def_cmd3-arg -> int
-   gen=True success_response=True
diff --git a/tests/qapi-schema/returns-int.err 
b/tests/qapi-schema/returns-int.err
deleted file mode 100644
index e69de29..000
diff --git a/tests/qapi-schema/returns-int.exit 
b/tests/qapi-schema/returns-int.exit
deleted file mode 100644
index 573541a..000
--- a/tests/qapi-schema/returns-int.exit
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/tests/qapi-schema/returns-int.json 
b/tests/qapi-schema/returns-int.json
deleted file mode 100644
index 870ec63..000
--- a/tests/qapi-schema/returns-int.json
+++ /dev/null
@@ -1,3 +0,0 @@
-# It is okay (although not extensible) to return a non-dictionary
-# But to make it work, the name must be in a whitelist
-{ 'command': 'guest-get-time', 'returns': 'int' }
diff --git a/tests/qapi-schema/ret

[Qemu-devel] [PATCH v8 02/18] qapi: Prepare for errors during check()

2015-10-12 Thread Eric Blake
The next few patches will start migrating error checking from
ad hoc parse methods into the QAPISchema*.check() methods.  But
for an error message to display, we first have to fix the
overall 'try' to catch those errors.  We also want to enable a
few more assertions, such as making sure every attempt to
raise a semantic error is passed a valid location info, or that
various preconditions hold.

The general approach for moving error checking will then be to
relax an assertion into an if that raises an exception if the
condition does not hold, and removing the counterpart ad hoc
check done during the parse phase.

Signed-off-by: Eric Blake 

---
v8: no change
v7: Split off of v6 7/12, plus other obvious asserts floated up
---
 scripts/qapi.py | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 543b378..4573599 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -103,6 +103,7 @@ class QAPISchemaError(Exception):
 class QAPIExprError(Exception):
 def __init__(self, expr_info, msg):
 Exception.__init__(self)
+assert expr_info
 self.info = expr_info
 self.msg = msg

@@ -964,6 +965,7 @@ class QAPISchemaObjectType(QAPISchemaType):
 members = []
 seen = {}
 for m in members:
+assert c_name(m.name) not in seen
 seen[m.name] = m
 for m in self.local_members:
 m.check(schema, members, seen)
@@ -1116,13 +1118,13 @@ class QAPISchema(object):
 def __init__(self, fname):
 try:
 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
+self._entity_dict = {}
+self._def_predefineds()
+self._def_exprs()
+self.check()
 except (QAPISchemaError, QAPIExprError), err:
 print >>sys.stderr, err
 exit(1)
-self._entity_dict = {}
-self._def_predefineds()
-self._def_exprs()
-self.check()

 def _def_entity(self, ent):
 assert ent.name not in self._entity_dict
-- 
2.4.3




[Qemu-devel] [PATCH v8 18/18] qapi: Detect base class loops

2015-10-12 Thread Eric Blake
It should be fairly obvious that qapi base classes need to
form an acyclic graph, since QMP cannot specify the same
key more than once, while base classes are included as flat
members alongside other members added by the child.  But the
old check_member_clash() parser function was not prepared to
check for this, and entered an infinite recursion (at least
until python gives up, complaining about nesting too deep).

Now that check_member_clash() has been recently removed,
attempts at self-inheritance trigger an assertion failure
introduced by commit ac88219a.  The obvious fix is to turn
the assertion into a conditional.

This patch includes both the test and the fix, since the .err
file output for the unfixed case is not useful (particularly
when it was warning about unbounded recursion, as that limit
may be platform-specific).

We don't need to worry about cycles in flat unions (neither
the base nor a variant class can be a union) nor in alternates
(alternate branches cannot themselves be an alternate).

Signed-off-by: Eric Blake 

---
v8: improve commit message
v7: improve commit message
v6: rebase to earlier info changes
---
 scripts/qapi.py   | 6 +-
 tests/Makefile| 1 +
 tests/qapi-schema/base-cycle.err  | 1 +
 tests/qapi-schema/base-cycle.exit | 1 +
 tests/qapi-schema/base-cycle.json | 3 +++
 tests/qapi-schema/base-cycle.out  | 0
 6 files changed, 11 insertions(+), 1 deletion(-)
 create mode 100644 tests/qapi-schema/base-cycle.err
 create mode 100644 tests/qapi-schema/base-cycle.exit
 create mode 100644 tests/qapi-schema/base-cycle.json
 create mode 100644 tests/qapi-schema/base-cycle.out

diff --git a/scripts/qapi.py b/scripts/qapi.py
index b21e38e..d6825ce 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -927,7 +927,11 @@ class QAPISchemaObjectType(QAPISchemaType):
 self.members = None

 def check(self, schema):
-assert self.members is not False# not running in cycles
+if self.members is False:   # check for cycles
+assert self._base_name
+raise QAPIExprError(self.info,
+"Object %s cyclically depends on %s"
+% (self.name, self._base_name))
 if self.members:
 return
 self.members = False# mark as being checked
diff --git a/tests/Makefile b/tests/Makefile
index 443e345..1ef44aa 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -251,6 +251,7 @@ qapi-schema += bad-ident.json
 qapi-schema += bad-type-bool.json
 qapi-schema += bad-type-dict.json
 qapi-schema += bad-type-int.json
+qapi-schema += base-cycle.json
 qapi-schema += command-int.json
 qapi-schema += comments.json
 qapi-schema += double-data.json
diff --git a/tests/qapi-schema/base-cycle.err b/tests/qapi-schema/base-cycle.err
new file mode 100644
index 000..e0221b5
--- /dev/null
+++ b/tests/qapi-schema/base-cycle.err
@@ -0,0 +1 @@
+tests/qapi-schema/base-cycle.json:2: Object Base1 cyclically depends on Base2
diff --git a/tests/qapi-schema/base-cycle.exit 
b/tests/qapi-schema/base-cycle.exit
new file mode 100644
index 000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/base-cycle.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/base-cycle.json 
b/tests/qapi-schema/base-cycle.json
new file mode 100644
index 000..2866772
--- /dev/null
+++ b/tests/qapi-schema/base-cycle.json
@@ -0,0 +1,3 @@
+# we reject a loop in base classes
+{ 'struct': 'Base1', 'base': 'Base2', 'data': {} }
+{ 'struct': 'Base2', 'base': 'Base1', 'data': {} }
diff --git a/tests/qapi-schema/base-cycle.out b/tests/qapi-schema/base-cycle.out
new file mode 100644
index 000..e69de29
-- 
2.4.3




[Qemu-devel] [PATCH v8 16/18] qapi: Move duplicate enum value checks to schema check()

2015-10-12 Thread Eric Blake
Similar to the previous commit, move the detection of a collision
in enum values from parse time to QAPISchemaEnumType.check().
This happens to also detect collisions in union branch names,
so for a decent error message, we have to determine if the enum
is implicit (and if so where the real collision lies).

Testing this showed that the test union-bad-branch and
union-clash-branches were basically testing the same thing;
with the minor difference that the former clashes only in the
enum, while the latter also clashes in the C union member
names that would be generated. So delete the weaker test.

No change to generated code.

Signed-off-by: Eric Blake 

---
v8: rebase to earlier changes; better comments
v7: retitle and improve commit message; earlier subclass patches
avoid problem with detecting 'kind' collision
v6: new patch
---
 scripts/qapi.py| 54 +-
 tests/Makefile |  1 -
 tests/qapi-schema/alternate-clash.err  |  2 +-
 tests/qapi-schema/enum-clash-member.err|  2 +-
 tests/qapi-schema/enum-max-member.err  |  2 +-
 tests/qapi-schema/union-bad-branch.err |  1 -
 tests/qapi-schema/union-bad-branch.exit|  1 -
 tests/qapi-schema/union-bad-branch.json|  8 -
 tests/qapi-schema/union-bad-branch.out |  0
 tests/qapi-schema/union-clash-branches.err |  2 +-
 tests/qapi-schema/union-clash-type.err |  2 +-
 tests/qapi-schema/union-max.err|  2 +-
 12 files changed, 29 insertions(+), 48 deletions(-)
 delete mode 100644 tests/qapi-schema/union-bad-branch.err
 delete mode 100644 tests/qapi-schema/union-bad-branch.exit
 delete mode 100644 tests/qapi-schema/union-bad-branch.json
 delete mode 100644 tests/qapi-schema/union-bad-branch.out

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 144dd4a..b21e38e 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -527,7 +527,6 @@ def check_union(expr, expr_info):
 base = expr.get('base')
 discriminator = expr.get('discriminator')
 members = expr['data']
-values = {'MAX': '(automatic)', 'KIND': '(automatic)'}

 # Two types of unions, determined by discriminator.

@@ -587,34 +586,16 @@ def check_union(expr, expr_info):
 "enum '%s'" %
 (key, enum_define["enum_name"]))

-# Otherwise, check for conflicts in the generated enum
-else:
-c_key = camel_to_upper(key)
-if c_key in values:
-raise QAPIExprError(expr_info,
-"Union '%s' member '%s' clashes with '%s'"
-% (name, key, values[c_key]))
-values[c_key] = key
-

 def check_alternate(expr, expr_info):
 name = expr['alternate']
 members = expr['data']
-values = {'MAX': '(automatic)'}
 types_seen = {}

 # Check every branch
 for (key, value) in members.items():
 check_name(expr_info, "Member of alternate '%s'" % name, key)

-# Check for conflicts in the generated enum
-c_key = camel_to_upper(key)
-if c_key in values:
-raise QAPIExprError(expr_info,
-"Alternate '%s' member '%s' clashes with '%s'"
-% (name, key, values[c_key]))
-values[c_key] = key
-
 # Ensure alternates have no type conflicts.
 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
value,
@@ -633,7 +614,6 @@ def check_enum(expr, expr_info):
 name = expr['enum']
 members = expr.get('data')
 prefix = expr.get('prefix')
-values = {'MAX': '(automatic)'}

 if not isinstance(members, list):
 raise QAPIExprError(expr_info,
@@ -644,12 +624,6 @@ def check_enum(expr, expr_info):
 for member in members:
 check_name(expr_info, "Member of enum '%s'" % name, member,
enum_member=True)
-key = camel_to_upper(member)
-if key in values:
-raise QAPIExprError(expr_info,
-"Enum '%s' member '%s' clashes with '%s'"
-% (name, member, values[key]))
-values[key] = member


 def check_struct(expr, expr_info):
@@ -878,7 +852,26 @@ class QAPISchemaEnumType(QAPISchemaType):
 self.prefix = prefix

 def check(self, schema):
-assert len(set(self.values)) == len(self.values)
+# Check for collisions on the generated C enum values
+seen = {c_enum_const(self.name, 'MAX'): '(automatic MAX)'}
+for value in self.values:
+c_value = c_enum_const(self.name, value)
+if c_value in seen:
+# If the enum is implicit, report the error on behalf of
+# the union or alternate that triggered the enum
+if self.is_implicit():
+owner = schema.lookup_type(self.name[:-4])
+

[Qemu-devel] [PATCH v8 04/18] qapi: Move empty-enum to compile-time test

2015-10-12 Thread Eric Blake
Rather than just asserting that we can parse an empty enum,
let's also make sure we can compile it, by including it in
qapi-schema-test.

Signed-off-by: Eric Blake 

---
v8: (no v7) hoist from subset C into B
v6: new patch; could be hoisted earlier alongside subset B v7 3/14
---
 tests/Makefile  | 1 -
 tests/qapi-schema/enum-empty.err| 0
 tests/qapi-schema/enum-empty.exit   | 1 -
 tests/qapi-schema/enum-empty.json   | 2 --
 tests/qapi-schema/enum-empty.out| 2 --
 tests/qapi-schema/qapi-schema-test.json | 6 ++
 tests/qapi-schema/qapi-schema-test.out  | 1 +
 7 files changed, 7 insertions(+), 6 deletions(-)
 delete mode 100644 tests/qapi-schema/enum-empty.err
 delete mode 100644 tests/qapi-schema/enum-empty.exit
 delete mode 100644 tests/qapi-schema/enum-empty.json
 delete mode 100644 tests/qapi-schema/enum-empty.out

diff --git a/tests/Makefile b/tests/Makefile
index 9a6601d..e058312 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -260,7 +260,6 @@ qapi-schema += enum-bad-name.json
 qapi-schema += enum-bad-prefix.json
 qapi-schema += enum-clash-member.json
 qapi-schema += enum-dict-member.json
-qapi-schema += enum-empty.json
 qapi-schema += enum-int-member.json
 qapi-schema += enum-max-member.json
 qapi-schema += enum-missing-data.json
diff --git a/tests/qapi-schema/enum-empty.err b/tests/qapi-schema/enum-empty.err
deleted file mode 100644
index e69de29..000
diff --git a/tests/qapi-schema/enum-empty.exit 
b/tests/qapi-schema/enum-empty.exit
deleted file mode 100644
index 573541a..000
--- a/tests/qapi-schema/enum-empty.exit
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/tests/qapi-schema/enum-empty.json 
b/tests/qapi-schema/enum-empty.json
deleted file mode 100644
index 40d4e85..000
--- a/tests/qapi-schema/enum-empty.json
+++ /dev/null
@@ -1,2 +0,0 @@
-# An empty enum, although unusual, is currently acceptable
-{ 'enum': 'MyEnum', 'data': [ ] }
diff --git a/tests/qapi-schema/enum-empty.out b/tests/qapi-schema/enum-empty.out
deleted file mode 100644
index a449d45..000
--- a/tests/qapi-schema/enum-empty.out
+++ /dev/null
@@ -1,2 +0,0 @@
-object :empty
-enum MyEnum []
diff --git a/tests/qapi-schema/qapi-schema-test.json 
b/tests/qapi-schema/qapi-schema-test.json
index abe59fd..c8cd2dd 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -1,11 +1,17 @@
 # *-*- Mode: Python -*-*

+# This file is a stress test of supported qapi constructs that must
+# parse and compile correctly.
+
 # for testing enums
 { 'enum': 'EnumOne',
   'data': [ 'value1', 'value2', 'value3' ] }
 { 'struct': 'NestedEnumsOne',
   'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', 
'*enum4': 'EnumOne' } }

+# An empty enum, although unusual, is currently acceptable
+{ 'enum': 'MyEnum', 'data': [ ] }
+
 # for testing override of default naming heuristic
 { 'enum': 'QEnumTwo',
   'prefix': 'QENUM_TWO',
diff --git a/tests/qapi-schema/qapi-schema-test.out 
b/tests/qapi-schema/qapi-schema-test.out
index 8f81784..e3504ab 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -86,6 +86,7 @@ object EventStructOne
 member struct1: UserDefOne optional=False
 member string: str optional=False
 member enum2: EnumOne optional=True
+enum MyEnum []
 object NestedEnumsOne
 member enum1: EnumOne optional=False
 member enum2: EnumOne optional=True
-- 
2.4.3




[Qemu-devel] [PATCH v8 08/18] qapi: Lazy creation of array types

2015-10-12 Thread Eric Blake
Commit ac88219a had several TODO markers about whether we needed
to automatically create the corresponding array type alongside
any other type.  It turns out that most of the time, we don't!

As part of lazy creation of array types, this patch now assigns
an 'info' to array types at their point of first instantiation,
rather than leaving it None.

There are a few exceptions: 1) We have a few situations where we
use an array type in internal code but do not expose that type
through QMP; fix it by declaring a dummy type that forces the
generator to see that we want to use the array type.

2) The builtin arrays (such as intList for QAPI ['int']) must
always be generated, because of the way our QAPI_TYPES_BUILTIN
compile guard works: we have situations (at the very least
tests/test-qmp-output-visitor.c) that include both top-level
"qapi-types.h" (via "error.h") and a secondary
"test-qapi-types.h". If we were to only emit the builtin types
when used locally, then the first .h file would not include all
types, but the second .h does not declare anything at all because
the first .h set QAPI_TYPES_BUILTIN, and we would end up with
compilation error due to things like unknown type 'int8List'.

Actually, we may need to revisit how we do type guards, and
change from a single QAPI_TYPES_BUILTIN over to a different
usage pattern that does one #ifdef per qapi type - right now,
the only types that are declared multiple times between two qapi
.json files for inclusion by a single .c file happen to be the
builtin arrays.  But now that we have QAPI 'include' statements,
it is logical to assume that we will soon reach a point where
we want to reuse non-builtin types (yes, I'm thinking about what
it will take to add introspection to QGA, where we will want to
reuse the SchemaInfo type and friends).  One #ifdef per type
will help ensure that generating the same qapi type into more
than one qapi-types.h won't cause collisions when both are
included in the same .c file; but we also have to solve how to
avoid creating duplicate qapi-types.c entry points.  So that
is a problem left for another day.

Generated code for qapi-types and qapi-visit is drastically
reduced; less than a third of the arrays that were blindly
created were actually needed (a quick grep shows we dropped
from 219 to 69 *List types), and the .o files lost more than
30% of their bulk.  [For best results, diff the generated
files with 'git diff --patience --no-index pre post'.]

Interestingly, the introspection output is unchanged - this is
because we already cull all types that are not indirectly
reachable from a command or event, so introspection was already
using only a subset of array types.  The subset of types
introspected is now a much larger percentage of the overall set
of array types emitted in qapi-types.h (since the larger set
shrunk), but still not 100% (evidence that the array types
emitted for our new Dummy structs, and the new struct itself,
don't affect QMP).

Signed-off-by: Eric Blake 

---
v8: commit message wording, rebase qapi-schema-test.out,
improved comment on .info
v7: improve commit message, add comments, rename dummy type,
better line wrapping
v6: new patch
---
 qapi-schema.json| 11 +++
 scripts/qapi.py | 53 +++--
 tests/qapi-schema/qapi-schema-test.json |  4 +++
 tests/qapi-schema/qapi-schema-test.out  |  3 ++
 4 files changed, 48 insertions(+), 23 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index a386605..702b7b5 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3416,6 +3416,17 @@
 'features': 'int' } }

 ##
+# @DummyForceArrays
+#
+# Not used by QMP; hack to let us use X86CPUFeatureWordInfoList internally
+#
+# Since 2.5
+##
+{ 'struct': 'DummyForceArrays',
+  'data': { 'unused': ['X86CPUFeatureWordInfo'] } }
+
+
+##
 # @RxState:
 #
 # Packets receiving state
diff --git a/scripts/qapi.py b/scripts/qapi.py
index e263ecf..73080e3 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -790,6 +790,12 @@ class QAPISchemaEntity(object):
 def __init__(self, name, info):
 assert isinstance(name, str)
 self.name = name
+# For explicitly defined entities, info points to the (explicit)
+# definition.  For builtins (and their arrays), info is None.
+# For other arrays, info points to an explicit place that uses
+# the array (there may be more than one such place).
+# TODO For other implicitly defined entities, it should point to
+# a place that triggers implicit definition.
 self.info = info

 def c_name(self):
@@ -1151,7 +1157,12 @@ class QAPISchema(object):
 def _def_builtin_type(self, name, json_type, c_type, c_null):
 self._def_entity(QAPISchemaBuiltinType(name, json_type,
c_type, c_null))
-self._make_array_type(name) # TODO really needed?
+# TODO As long as we have QAP

[Qemu-devel] [PATCH v8 17/18] qapi: Add test for alternate branch 'kind' clash

2015-10-12 Thread Eric Blake
Rename alternate-clash to alternate-clash-members, and add a
new test alternate-clash-type.  While similar to the earlier
addition of union-clash-type, we have one major difference: a
future patch will be simplifying alternates to not need an
implict AlternateKind enum, but we still need to detect the
collision with the resulting C 'qtype_code type;' tag.

No change to generated code.

Signed-off-by: Eric Blake 

---
v8: no change
v7: retitle 10/12 and limit to just testsuite changes
v6: New patch
---
 tests/Makefile |  3 ++-
 tests/qapi-schema/alternate-clash-members.err  |  1 +
 .../{alternate-clash.exit => alternate-clash-members.exit} |  0
 .../{alternate-clash.json => alternate-clash-members.json} |  0
 .../{alternate-clash.out => alternate-clash-members.out}   |  0
 tests/qapi-schema/alternate-clash-type.err |  1 +
 tests/qapi-schema/alternate-clash-type.exit|  1 +
 tests/qapi-schema/alternate-clash-type.json| 10 ++
 tests/qapi-schema/alternate-clash-type.out |  0
 tests/qapi-schema/alternate-clash.err  |  1 -
 10 files changed, 15 insertions(+), 2 deletions(-)
 create mode 100644 tests/qapi-schema/alternate-clash-members.err
 rename tests/qapi-schema/{alternate-clash.exit => 
alternate-clash-members.exit} (100%)
 rename tests/qapi-schema/{alternate-clash.json => 
alternate-clash-members.json} (100%)
 rename tests/qapi-schema/{alternate-clash.out => alternate-clash-members.out} 
(100%)
 create mode 100644 tests/qapi-schema/alternate-clash-type.err
 create mode 100644 tests/qapi-schema/alternate-clash-type.exit
 create mode 100644 tests/qapi-schema/alternate-clash-type.json
 create mode 100644 tests/qapi-schema/alternate-clash-type.out
 delete mode 100644 tests/qapi-schema/alternate-clash.err

diff --git a/tests/Makefile b/tests/Makefile
index 2cd5d31..443e345 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -226,7 +226,8 @@ check-qtest-generic-y += tests/qom-test$(EXESUF)

 qapi-schema += alternate-array.json
 qapi-schema += alternate-base.json
-qapi-schema += alternate-clash.json
+qapi-schema += alternate-clash-members.json
+qapi-schema += alternate-clash-type.json
 qapi-schema += alternate-conflict-dict.json
 qapi-schema += alternate-conflict-string.json
 qapi-schema += alternate-empty.json
diff --git a/tests/qapi-schema/alternate-clash-members.err 
b/tests/qapi-schema/alternate-clash-members.err
new file mode 100644
index 000..0adf737
--- /dev/null
+++ b/tests/qapi-schema/alternate-clash-members.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-clash-members.json:7: Alternate 'Alt1' branch 
'a_b' clashes with 'a-b'
diff --git a/tests/qapi-schema/alternate-clash.exit 
b/tests/qapi-schema/alternate-clash-members.exit
similarity index 100%
rename from tests/qapi-schema/alternate-clash.exit
rename to tests/qapi-schema/alternate-clash-members.exit
diff --git a/tests/qapi-schema/alternate-clash.json 
b/tests/qapi-schema/alternate-clash-members.json
similarity index 100%
rename from tests/qapi-schema/alternate-clash.json
rename to tests/qapi-schema/alternate-clash-members.json
diff --git a/tests/qapi-schema/alternate-clash.out 
b/tests/qapi-schema/alternate-clash-members.out
similarity index 100%
rename from tests/qapi-schema/alternate-clash.out
rename to tests/qapi-schema/alternate-clash-members.out
diff --git a/tests/qapi-schema/alternate-clash-type.err 
b/tests/qapi-schema/alternate-clash-type.err
new file mode 100644
index 000..cdd2090
--- /dev/null
+++ b/tests/qapi-schema/alternate-clash-type.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-clash-type.json:9: 'kind' (branch of Alt1) 
collides with 'kind' (implicit tag of Alt1)
diff --git a/tests/qapi-schema/alternate-clash-type.exit 
b/tests/qapi-schema/alternate-clash-type.exit
new file mode 100644
index 000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/alternate-clash-type.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/alternate-clash-type.json 
b/tests/qapi-schema/alternate-clash-type.json
new file mode 100644
index 000..629584b
--- /dev/null
+++ b/tests/qapi-schema/alternate-clash-type.json
@@ -0,0 +1,10 @@
+# Alternate branch 'type'
+# Reject this, because we would have a clash in generated C, between the
+# alternate's implicit tag member 'kind' and the branch name 'kind'
+# within the alternate.
+# TODO: Even if alternates are simplified in the future to use a simpler
+# 'qtype_code type' tag, rather than a full QAPISchemaObjectTypeMember,
+# we must still flag the collision, or else munge the generated C branch
+# names to allow compilation.
+{ 'alternate': 'Alt1',
+  'data': { 'kind': 'str', 'type': 'int' } }
diff --git a/tests/qapi-schema/alternate-clash-type.out 
b/tests/qapi-schema/alternate-clash-type.out
new file mode 100644
index 000..e69de29
diff --git a/tests/qapi-schema/alternate-clash.err 
b/tests/qapi-schema/alternate-cl

[Qemu-devel] [PATCH v8 03/18] qapi: Drop redundant alternate-good test

2015-10-12 Thread Eric Blake
The alternate-good.json test was already covered by
qapi-schema-test.json.  As future commits will be tweaking
how alternates are laid out, removing the duplicate test now
reduces churn.

Signed-off-by: Eric Blake 

---
v8: no change
v7: new patch
---
 tests/Makefile|  1 -
 tests/qapi-schema/alternate-good.err  |  0
 tests/qapi-schema/alternate-good.exit |  1 -
 tests/qapi-schema/alternate-good.json |  9 -
 tests/qapi-schema/alternate-good.out  | 10 --
 5 files changed, 21 deletions(-)
 delete mode 100644 tests/qapi-schema/alternate-good.err
 delete mode 100644 tests/qapi-schema/alternate-good.exit
 delete mode 100644 tests/qapi-schema/alternate-good.json
 delete mode 100644 tests/qapi-schema/alternate-good.out

diff --git a/tests/Makefile b/tests/Makefile
index 209eca9..9a6601d 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -230,7 +230,6 @@ qapi-schema += alternate-clash.json
 qapi-schema += alternate-conflict-dict.json
 qapi-schema += alternate-conflict-string.json
 qapi-schema += alternate-empty.json
-qapi-schema += alternate-good.json
 qapi-schema += alternate-nested.json
 qapi-schema += alternate-unknown.json
 qapi-schema += args-alternate.json
diff --git a/tests/qapi-schema/alternate-good.err 
b/tests/qapi-schema/alternate-good.err
deleted file mode 100644
index e69de29..000
diff --git a/tests/qapi-schema/alternate-good.exit 
b/tests/qapi-schema/alternate-good.exit
deleted file mode 100644
index 573541a..000
--- a/tests/qapi-schema/alternate-good.exit
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/tests/qapi-schema/alternate-good.json 
b/tests/qapi-schema/alternate-good.json
deleted file mode 100644
index 3371770..000
--- a/tests/qapi-schema/alternate-good.json
+++ /dev/null
@@ -1,9 +0,0 @@
-# Working example of alternate
-{ 'struct': 'Data',
-  'data': { '*number': 'int', '*name': 'str' } }
-{ 'enum': 'Enum',
-  'data': [ 'hello', 'world' ] }
-{ 'alternate': 'Alt',
-  'data': { 'value': 'int',
-'string': 'Enum',
-'struct': 'Data' } }
diff --git a/tests/qapi-schema/alternate-good.out 
b/tests/qapi-schema/alternate-good.out
deleted file mode 100644
index 65af727..000
--- a/tests/qapi-schema/alternate-good.out
+++ /dev/null
@@ -1,10 +0,0 @@
-object :empty
-alternate Alt
-case value: int
-case string: Enum
-case struct: Data
-enum AltKind ['value', 'string', 'struct']
-object Data
-member number: int optional=True
-member name: str optional=True
-enum Enum ['hello', 'world']
-- 
2.4.3




[Qemu-devel] [PATCH v8 06/18] qapi: Drop redundant flat-union-reverse-define test

2015-10-12 Thread Eric Blake
As of commit 8c3f8e77, we test compilation of forward references
for a struct base type (UserDefOne), flat union base type
(UserDefUnionBase), and flat union branch type
(UserDefFlatUnion2). The only remaining forward reference being
tested for parsing in flat-union-reverse-define was a forward
enum declaration.  Once we make sure that always compiles,
the smaller parse-only test is redundant and can be deleted.

Signed-off-by: Eric Blake 

---
v8: (no v7) hoist from subset C into B
v6: new patch; could be hoisted earlier alongside subset B v7 3/14
---
 tests/Makefile   |  1 -
 tests/qapi-schema/flat-union-reverse-define.err  |  0
 tests/qapi-schema/flat-union-reverse-define.exit |  1 -
 tests/qapi-schema/flat-union-reverse-define.json | 17 -
 tests/qapi-schema/flat-union-reverse-define.out  | 13 -
 tests/qapi-schema/qapi-schema-test.json  | 11 +++
 6 files changed, 7 insertions(+), 36 deletions(-)
 delete mode 100644 tests/qapi-schema/flat-union-reverse-define.err
 delete mode 100644 tests/qapi-schema/flat-union-reverse-define.exit
 delete mode 100644 tests/qapi-schema/flat-union-reverse-define.json
 delete mode 100644 tests/qapi-schema/flat-union-reverse-define.out

diff --git a/tests/Makefile b/tests/Makefile
index 3512f8c..35a63f3 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -286,7 +286,6 @@ qapi-schema += flat-union-invalid-branch-key.json
 qapi-schema += flat-union-invalid-discriminator.json
 qapi-schema += flat-union-no-base.json
 qapi-schema += flat-union-optional-discriminator.json
-qapi-schema += flat-union-reverse-define.json
 qapi-schema += flat-union-string-discriminator.json
 qapi-schema += funny-char.json
 qapi-schema += ident-with-escape.json
diff --git a/tests/qapi-schema/flat-union-reverse-define.err 
b/tests/qapi-schema/flat-union-reverse-define.err
deleted file mode 100644
index e69de29..000
diff --git a/tests/qapi-schema/flat-union-reverse-define.exit 
b/tests/qapi-schema/flat-union-reverse-define.exit
deleted file mode 100644
index 573541a..000
--- a/tests/qapi-schema/flat-union-reverse-define.exit
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/tests/qapi-schema/flat-union-reverse-define.json 
b/tests/qapi-schema/flat-union-reverse-define.json
deleted file mode 100644
index 648bbfe..000
--- a/tests/qapi-schema/flat-union-reverse-define.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{ 'union': 'TestUnion',
-  'base': 'TestBase',
-  'discriminator': 'enum1',
-  'data': { 'value1': 'TestTypeA',
-'value2': 'TestTypeB' } }
-
-{ 'struct': 'TestBase',
-  'data': { 'enum1': 'TestEnum' } }
-
-{ 'enum': 'TestEnum',
-  'data': [ 'value1', 'value2' ] }
-
-{ 'struct': 'TestTypeA',
-  'data': { 'string': 'str' } }
-
-{ 'struct': 'TestTypeB',
-  'data': { 'integer': 'int' } }
diff --git a/tests/qapi-schema/flat-union-reverse-define.out 
b/tests/qapi-schema/flat-union-reverse-define.out
deleted file mode 100644
index a5a9134..000
--- a/tests/qapi-schema/flat-union-reverse-define.out
+++ /dev/null
@@ -1,13 +0,0 @@
-object :empty
-object TestBase
-member enum1: TestEnum optional=False
-enum TestEnum ['value1', 'value2']
-object TestTypeA
-member string: str optional=False
-object TestTypeB
-member integer: int optional=False
-object TestUnion
-base TestBase
-tag enum1
-case value1: TestTypeA
-case value2: TestTypeB
diff --git a/tests/qapi-schema/qapi-schema-test.json 
b/tests/qapi-schema/qapi-schema-test.json
index 67c6bca..b48c6bd 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -4,10 +4,9 @@
 # parse and compile correctly.

 # for testing enums
-{ 'enum': 'EnumOne',
-  'data': [ 'value1', 'value2', 'value3' ] }
 { 'struct': 'NestedEnumsOne',
-  'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', 
'*enum4': 'EnumOne' } }
+  'data': { 'enum1': 'EnumOne',   # Intentional forward reference
+'*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }

 # An empty enum, although unusual, is currently acceptable
 { 'enum': 'MyEnum', 'data': [ ] }
@@ -20,7 +19,11 @@
 # for testing nested structs
 { 'struct': 'UserDefOne',
   'base': 'UserDefZero',# intentional forward reference
-  'data': { 'string': 'str', '*enum1': 'EnumOne' } }
+  'data': { 'string': 'str',
+'*enum1': 'EnumOne' } }   # intentional forward reference
+
+{ 'enum': 'EnumOne',
+  'data': [ 'value1', 'value2', 'value3' ] }

 { 'struct': 'UserDefZero',
   'data': { 'integer': 'int' } }
-- 
2.4.3




Re: [Qemu-devel] [PATCH v7 11/14] qapi: Move duplicate member checks to schema check()

2015-10-12 Thread Eric Blake
On 10/12/2015 10:22 AM, Eric Blake wrote:

> 
>>> +def check(self, schema, info, tag_type, seen, flat):
>>>  QAPISchemaObjectTypeMember.check(self, schema, info, [], seen)

seen gets modified here...

>>>  assert self.name in tag_type.values
>>> +if flat:
>>> +# For flat unions, check that each QMP member does not
>>> +# collide with any non-variant members. No type can
>>> +# contain itself as a flat variant
>>> +self.type.check(schema)
>>> +assert not self.type.variants# not implemented
>>> +for m in self.type.members:
>>> +if m.c_name() in seen:

...and it is the modified seen here that causes...

>>  union-clash-data.json:6: Member 'data' of branch 'data' collides with 
>> 'data' (branch of TestUnion)

...the incorrect error.

>>
>> The FIXME in union-clash-data.json actually asks for an error, because
>> 'data' clashes with our stupid filler to avoid empty unions.  But that's
>> not what this error message reports!  I think what happens is this:
>> QAPISchemaObjectTypeVariant.check() adds the case name self.name (here:
>> 'data') to seen.  When we then check the case's 'data': 'int' member, it
>> finds the with the case name, and reports a clash.  I can't see why it
>> should.
>>
>> This clashing business is awfully confusing, because we have to consider
>> (flat unions, simple unions, alternates) times (QMP, C).
>>
>> It would be simpler if we could make C clash only when QMP clashes.
> 
> If a QMP clash always caused a C clash, life would be a bit simpler. We
> aren't going to get there (because in a flat union, hiding the members
> of the branch type behind a single pointer means those members don't
> clash with any C names of the overall union), but I can certainly try to
> make the comments explain what is going on.

I've managed to fix it with a dict(seen) and some comments, and will
post a v8.  Great catch, by the way.

> 
>>
>> We might want to separate out alternates.  Dunno.
> 
> And to some extent, subset C already does some of that separation
> (because I try to convert from 'FooKind type' to 'qtype_code type'
> without even creating an implicit 'FooKind' enum).  It sounds like
> you're okay with any well-documented TODO warts related to alternates
> for the purposes of this subset B, especially if I can then clean those
> warts back up in subset C.  But what v8 of subset B needs to avoid is
> any warts based on simple vs. flat unions.  I can live with that.
> 
> I'm still trying to figure out if hoisting the kind=>type rename into
> subset B makes life easier or harder (it certainly causes me more rebase
> churn, but that's not necessarily a bad thing).

At this point, it was easier to live with a temporary hack for
QAPISchemaObjectTypeUnionTag than it was to rebase my kind=>type rename
patch to be this early in the overall series. We'll get there, but I
agree with the approach we've been taking of one subset at a time.

-- 
Eric Blake   eblake redhat com+1-919-301-3266
Libvirt virtualization library http://libvirt.org



signature.asc
Description: OpenPGP digital signature


Re: [Qemu-devel] [PATCH 5/5] qga: guest-exec simple stdin/stdout/stderr redirection

2015-10-12 Thread Michael Roth
Quoting Denis V. Lunev (2015-10-07 05:32:21)
> From: Yuri Pudgorodskiy 
> 
> Implemented with base64-encoded strings in qga json protocol.
> Glib portable GIOChannel is used for data I/O.
> 
> Optinal stdin parameter of guest-exec command is now used as
> stdin content for spawned subprocess.
> 
> If capture-output bool flag is specified, guest-exec redirects out/err
> file descriptiors internally to pipes and collects subprocess
> output.
> 
> Guest-exe-status is modified to return this collected data to requestor
> in base64 encoding.
> 
> Signed-off-by: Yuri Pudgorodskiy 
> Signed-off-by: Denis V. Lunev 
> CC: Michael Roth 

For capture-output mode, win32 guests appear to spin forever on EOF and
the exec'd process never gets reaped as a result. The below patch
seems to fix this issue. If this seems reasonable I can squash it
into the patch directly, but you might want to check I didn't break one
of your !capture-output use-cases (I assume this is still mainly focused
on redirecting to virtio-serial for stdio).

Another issue I noticed is that glib relies on
gspawn-win{32,64}-helper[-console].exe for g_spawn*() interface, so guest
exec won't work for .msi distributables unless those are added. This can
probably be addressed during soft-freeze though.

diff --git a/qga/commands.c b/qga/commands.c
index 27c06c5..fbf8abd 100644
--- a/qga/commands.c
+++ b/qga/commands.c
@@ -318,7 +318,7 @@ static gboolean guest_exec_output_watch(GIOChannel *ch,
 struct GuestExecIOData *p = (struct GuestExecIOData *)p_;
 gsize bytes_read = 0;
 
-if (cond == G_IO_HUP) {
+if (cond == G_IO_HUP || cond == G_IO_ERR) {
 g_io_channel_unref(ch);
 g_atomic_int_set(&p->closed, 1);
 return FALSE;
@@ -330,10 +330,18 @@ static gboolean guest_exec_output_watch(GIOChannel *ch,
 t = g_try_realloc(p->data, p->size + GUEST_EXEC_IO_SIZE);
 }
 if (t == NULL) {
+GIOStatus gstatus = 0;
 p->truncated = true;
 /* ignore truncated output */
 gchar buf[GUEST_EXEC_IO_SIZE];
-g_io_channel_read_chars(ch, buf, sizeof(buf), &bytes_read, NULL);
+gstatus = g_io_channel_read_chars(ch, buf, sizeof(buf),
+  &bytes_read, NULL);
+if (gstatus == G_IO_STATUS_EOF || gstatus == G_IO_STATUS_ERROR) {
+g_io_channel_unref(ch);
+g_atomic_int_set(&p->closed, 1);
+return false;
+}
+
 return TRUE;
 }
 p->size += GUEST_EXEC_IO_SIZE;
@@ -342,8 +350,14 @@ static gboolean guest_exec_output_watch(GIOChannel *ch,
 
 /* Calling read API once.
  * On next available data our callback will be called again */
-g_io_channel_read_chars(ch, (gchar *)p->data + p->length,
+GIOStatus gstatus = 0;
+gstatus = g_io_channel_read_chars(ch, (gchar *)p->data + p->length,
 p->size - p->length, &bytes_read, NULL);
+if (gstatus == G_IO_STATUS_EOF || gstatus == G_IO_STATUS_ERROR) {
+g_io_channel_unref(ch);
+g_atomic_int_set(&p->closed, 1);
+return false;
+}

> ---
>  qga/commands.c   | 175 
> ---
>  qga/qapi-schema.json |  11 +++-
>  2 files changed, 175 insertions(+), 11 deletions(-)
> 
> diff --git a/qga/commands.c b/qga/commands.c
> index b487324..740423f 100644
> --- a/qga/commands.c
> +++ b/qga/commands.c
> @@ -15,6 +15,11 @@
>  #include "qga-qmp-commands.h"
>  #include "qapi/qmp/qerror.h"
> 
> +/* Maximum captured guest-exec out_data/err_data - 16MB */
> +#define GUEST_EXEC_MAX_OUTPUT (16*1024*1024)
> +/* Allocation and I/O buffer for reading guest-exec out_data/err_data - 4KB 
> */
> +#define GUEST_EXEC_IO_SIZE (4*1024)
> +
>  /* Note: in some situations, like with the fsfreeze, logging may be
>   * temporarilly disabled. if it is necessary that a command be able
>   * to log for accounting purposes, check ga_logging_enabled() beforehand,
> @@ -71,10 +76,23 @@ struct GuestAgentInfo *qmp_guest_info(Error **errp)
>  return info;
>  }
> 
> +struct GuestExecIOData {
> +guchar *data;
> +gsize size;
> +gsize length;
> +gint closed;
> +bool truncated;
> +const char *name;
> +};
> +
>  struct GuestExecInfo {
>  GPid pid;
>  gint status;
> -bool finished;
> +bool has_output;
> +gint finished;
> +struct GuestExecIOData in;
> +struct GuestExecIOData out;
> +struct GuestExecIOData err;
>  QTAILQ_ENTRY(GuestExecInfo) next;
>  };
>  typedef struct GuestExecInfo GuestExecInfo;
> @@ -123,9 +141,18 @@ GuestExecStatus *qmp_guest_exec_status(int64_t pid, 
> Error **err)
>  }
> 
>  ges = g_new0(GuestExecStatus, 1);
> -ges->exited = gei->finished;
> 
> -if (gei->finished) {
> +bool finished = g_atomic_int_get(&gei->finished);
> +
> +/* need to wait till output channels are closed
> + * to be sure we captured all output at this point 

Re: [Qemu-devel] [PATCH v3 14/32] pc-dimm: drop the prefix of pc-dimm

2015-10-12 Thread Xiao Guangrong



On 10/13/2015 12:43 AM, Eric Blake wrote:

On 10/10/2015 09:52 PM, Xiao Guangrong wrote:

This patch is generated by this script:

find ./ -name "*.[ch]" -o -name "*.json" -o -name "trace-events" -type f \
| xargs sed -i "s/PC_DIMM/DIMM/g"

find ./ -name "*.[ch]" -o -name "*.json" -o -name "trace-events" -type f \
| xargs sed -i "s/PCDIMM/DIMM/g"

find ./ -name "*.[ch]" -o -name "*.json" -o -name "trace-events" -type f \
| xargs sed -i "s/pc_dimm/dimm/g"

find ./ -name "trace-events" -type f | xargs sed -i "s/pc-dimm/dimm/g"

It prepares the work which abstracts dimm device type for both pc-dimm and
nvdimm

Signed-off-by: Xiao Guangrong 
---
  hmp.c   |   2 +-



+++ b/qapi-schema.json
@@ -3684,9 +3684,9 @@
  { 'command': 'query-memdev', 'returns': ['Memdev'] }

  ##
-# @PCDIMMDeviceInfo:
+# @DIMMDeviceInfo:
  #
-# PCDIMMDevice state information
+# DIMMDevice state information
  #
  # @id: #optional device's ID
  #
@@ -3706,7 +3706,7 @@
  #
  # Since: 2.1
  ##
-{ 'struct': 'PCDIMMDeviceInfo',
+{ 'struct': 'DIMMDeviceInfo',
'data': { '*id': 'str',
  'addr': 'int',
  'size': 'int',
@@ -3725,7 +3725,7 @@
  #
  # Since: 2.1
  ##
-{ 'union': 'MemoryDeviceInfo', 'data': {'dimm': 'PCDIMMDeviceInfo'} }
+{ 'union': 'MemoryDeviceInfo', 'data': {'dimm': 'DIMMDeviceInfo'} }


Struct names are not ABI, so this change is safe.

I have not reviewed the rest of the patch, but I don't see any problems
from the qapi perspective.


Thanks for your review, Eric! :)



Re: [Qemu-devel] [PATCH v3 08/32] exec: allow memory to be allocated from any kind of path

2015-10-12 Thread Xiao Guangrong



On 10/12/2015 06:08 PM, Michael S. Tsirkin wrote:

On Sun, Oct 11, 2015 at 11:52:40AM +0800, Xiao Guangrong wrote:

Currently file_ram_alloc() is designed for hugetlbfs, however, the memory
of nvdimm can come from either raw pmem device eg, /dev/pmem, or the file
locates at DAX enabled filesystem

So this patch let it work on any kind of path

Signed-off-by: Xiao Guangrong 


This conflicts with map alloc rework.
Please rebase this on top of my tree.



Okay, thanks for your reminder. I did it based on upstream QEMU tree,
will do it on pci branch on your tree instead.




---
  exec.c | 55 ++-
  1 file changed, 14 insertions(+), 41 deletions(-)

diff --git a/exec.c b/exec.c
index 7d90a52..70cb0ef 100644
--- a/exec.c
+++ b/exec.c
@@ -1154,32 +1154,6 @@ void qemu_mutex_unlock_ramlist(void)
  }

  #ifdef __linux__
-
-#include 
-
-#define HUGETLBFS_MAGIC   0x958458f6
-
-static long gethugepagesize(const char *path, Error **errp)
-{
-struct statfs fs;
-int ret;
-
-do {
-ret = statfs(path, &fs);
-} while (ret != 0 && errno == EINTR);
-
-if (ret != 0) {
-error_setg_errno(errp, errno, "failed to get page size of file %s",
- path);
-return 0;
-}
-
-if (fs.f_type != HUGETLBFS_MAGIC)
-fprintf(stderr, "Warning: path not on HugeTLBFS: %s\n", path);
-
-return fs.f_bsize;


What this *actually* is trying to warn against is that
mapping a regular file (as opposed to hugetlbfs)
means transparent huge pages don't work.

So I don't think we should drop this warning completely.
Either let's add the nvdimm magic, or simply check the
page size.


Check the page size sounds good, will check:
if (pagesize != getpagesize()) {
...print something...
}

I agree with you that showing the info is needed, however,
'Warning' might scare some users, how about drop this word or
just show “Memory is not allocated from HugeTlbfs”?




Re: [Qemu-devel] [PATCH v3 00/32] implement vNVDIMM

2015-10-12 Thread Xiao Guangrong



On 10/13/2015 12:36 AM, Dan Williams wrote:

On Sun, Oct 11, 2015 at 9:33 PM, Xiao Guangrong
 wrote:



On 10/11/2015 05:17 AM, Dan Williams wrote:


On Sat, Oct 10, 2015 at 8:52 PM, Xiao Guangrong
 wrote:
[..]


== Test ==
In host
1) create memory backed file, e.g # dd if=zero of=/tmp/nvdimm bs=1G
count=10
2) append "-object memory-backend-file,share,id=mem1,
 mem-path=/tmp/nvdimm -device nvdimm,memdev=mem1,reserve-label-data,
 id=nv1" in QEMU command line

In guest, download the latest upsteam kernel (4.2 merge window) and
enable
ACPI_NFIT, LIBNVDIMM and BLK_DEV_PMEM.
1) insmod drivers/nvdimm/libnvdimm.ko
2) insmod drivers/acpi/nfit.ko
3) insmod drivers/nvdimm/nd_btt.ko
4) insmod drivers/nvdimm/nd_pmem.ko
You can see the whole nvdimm device used as a single namespace and
/dev/pmem0
appears. You can do whatever on /dev/pmem0 including DAX access.

Currently Linux NVDIMM driver does not support namespace operation on
this
kind of PMEM, apply below changes to support dynamical namespace:

@@ -798,7 +823,8 @@ static int acpi_nfit_register_dimms(struct
acpi_nfit_desc *a
  continue;
  }

-   if (nfit_mem->bdw && nfit_mem->memdev_pmem)
+   //if (nfit_mem->bdw && nfit_mem->memdev_pmem)
+   if (nfit_mem->memdev_pmem)
  flags |= NDD_ALIASING;



This is just for testing purposes, right?  I expect guests can



It's used to validate NVDIMM _DSM method and static namespace following
NVDIMM specs...


Static namespaces can be emitted without a label.  Linux needs this to
support existing "label-less" bare metal NVDIMMs.


This is Linux specific? As i did not see it has been documented in the
spec...




sub-divide persistent memory capacity by partitioning the resulting
block device(s).



I understand that it's a Linux design... Hmm, can the same expectation
apply to PBLK?


BLK-mode is a bit different as those namespaces have both configurable
sector-size and an optional BTT.  It is possible to expect multiple
BLK namespaces per a given region with different settings.


Okay, thanks for your nice explanation, Dan!




Re: [Qemu-devel] [PATCH v3 07/16] block: Convert bs->backing_hd to BdrvChild

2015-10-12 Thread Jeff Cody
On Fri, Oct 09, 2015 at 02:15:32PM +0200, Kevin Wolf wrote:
> This is the final step in converting all of the BlockDriverState
> pointers that block drivers use to BdrvChild.
> 
> After this patch, bs->children contains the full list of child nodes
> that are referenced by a given BDS, and these children are only
> referenced through BdrvChild, so that updating the pointer in there is
> enough for changing edges in the graph.
> 
> Signed-off-by: Kevin Wolf 
> ---
>  block.c   | 105 
> +++---
>  block/io.c|  24 +--
>  block/mirror.c|   6 +--
>  block/qapi.c  |   8 ++--
>  block/qcow.c  |   4 +-
>  block/qcow2-cluster.c |   4 +-
>  block/qcow2.c |   6 +--
>  block/qed.c   |  12 +++---
>  block/stream.c|   8 ++--
>  block/vmdk.c  |  21 +-
>  block/vvfat.c |   6 +--
>  blockdev.c|   4 +-
>  include/block/block_int.h |  12 --
>  qemu-img.c|   4 +-
>  14 files changed, 115 insertions(+), 109 deletions(-)
> 

[...]

> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index 98936c9..90971c0 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -378,8 +378,7 @@ struct BlockDriverState {
>  QDict *full_open_options;
>  char exact_filename[PATH_MAX];
>  
> -BlockDriverState *backing_hd;
> -BdrvChild *backing_child;
> +BdrvChild *backing;
>  BdrvChild *file;
>  
>  NotifierList close_notifiers;
> @@ -458,6 +457,11 @@ struct BlockDriverState {
>  NotifierWithReturn write_threshold_notifier;
>  };
>  
> +static inline BlockDriverState *backing_bs(BlockDriverState *bs)
> +{
> +return bs->backing ? bs->backing->bs : NULL;
> +}
> +

Is there a good guideline regarding when you prefer backing_bs() to be
used, over accessing bs->backing->bs directly?  There seems to be a
lot of mixed usage left in this patch, and I'm not sure if I am just
missing the intended distinction.

Thanks,
Jeff





Re: [Qemu-devel] [PATCH v3 06/16] block: Remove bdrv_open_image()

2015-10-12 Thread Jeff Cody
On Fri, Oct 09, 2015 at 02:15:31PM +0200, Kevin Wolf wrote:
> It is unused now.
> 
> Signed-off-by: Kevin Wolf 
> Reviewed-by: Max Reitz 
> Reviewed-by: Alberto Garcia 
> Reviewed-by: Fam Zheng 
> ---
>  block.c   | 34 --
>  include/block/block.h |  4 
>  2 files changed, 38 deletions(-)
> 
> diff --git a/block.c b/block.c
> index 8fd345b..33ecd93 100644
> --- a/block.c
> +++ b/block.c
> @@ -1279,40 +1279,6 @@ done:
>  return c;
>  }
>  
> -/*
> - * This is a version of bdrv_open_child() that returns 0/-EINVAL instead of
> - * a BdrvChild object.
> - *
> - * If allow_none is true, no image will be opened if filename is false and no
> - * BlockdevRef is given. *pbs will remain unchanged and 0 will be returned.
> - *
> - * To conform with the behavior of bdrv_open(), *pbs has to be NULL.
> - */
> -int bdrv_open_image(BlockDriverState **pbs, const char *filename,
> -QDict *options, const char *bdref_key,
> -BlockDriverState* parent, const BdrvChildRole 
> *child_role,
> -bool allow_none, Error **errp)
> -{
> -Error *local_err = NULL;
> -BdrvChild *c;
> -
> -assert(pbs);
> -assert(*pbs == NULL);
> -
> -c = bdrv_open_child(filename, options, bdref_key, parent, child_role,
> -allow_none, &local_err);
> -if (local_err) {
> -error_propagate(errp, local_err);
> -return -EINVAL;
> -}
> -
> -if (c != NULL) {
> -*pbs = c->bs;
> -}
> -
> -return 0;
> -}
> -
>  int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
>  {
>  /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
> diff --git a/include/block/block.h b/include/block/block.h
> index 7ebb35d..c6854a6 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -205,10 +205,6 @@ void bdrv_swap(BlockDriverState *bs_new, 
> BlockDriverState *bs_old);
>  void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
>  int bdrv_parse_cache_flags(const char *mode, int *flags);
>  int bdrv_parse_discard_flags(const char *mode, int *flags);
> -int bdrv_open_image(BlockDriverState **pbs, const char *filename,
> -QDict *options, const char *bdref_key,
> -BlockDriverState* parent, const BdrvChildRole 
> *child_role,
> -bool allow_none, Error **errp);
>  BdrvChild *bdrv_open_child(const char *filename,
> QDict *options, const char *bdref_key,
> BlockDriverState* parent,
> -- 
> 1.8.3.1
>

Reviewed-by: Jeff Cody 



Re: [Qemu-devel] [PATCH v3 05/16] block: Convert bs->file to BdrvChild

2015-10-12 Thread Jeff Cody
On Fri, Oct 09, 2015 at 02:15:30PM +0200, Kevin Wolf wrote:
> This patch removes the temporary duplication between bs->file and
> bs->file_child by converting everything to BdrvChild.
> 
> Signed-off-by: Kevin Wolf 
> Reviewed-by: Max Reitz 
> Reviewed-by: Alberto Garcia 
> Reviewed-by: Fam Zheng 
> ---
>  block.c   | 63 
> ++-
>  block/blkdebug.c  | 32 +---
>  block/blkverify.c | 33 ++---
>  block/bochs.c |  8 +++---
>  block/cloop.c | 10 
>  block/dmg.c   | 20 +++
>  block/io.c| 50 ++---
>  block/parallels.c | 38 ++--
>  block/qapi.c  |  2 +-
>  block/qcow.c  | 42 ---
>  block/qcow2-cache.c   | 11 +
>  block/qcow2-cluster.c | 38 
>  block/qcow2-refcount.c| 45 +
>  block/qcow2-snapshot.c| 30 +++---
>  block/qcow2.c | 62 --
>  block/qed-table.c |  4 +--
>  block/qed.c   | 32 
>  block/raw_bsd.c   | 40 +++---
>  block/snapshot.c  | 12 -
>  block/vdi.c   | 17 +++--
>  block/vhdx-log.c  | 25 ++-
>  block/vhdx.c  | 36 ++-
>  block/vmdk.c  | 27 ++--
>  block/vpc.c   | 34 +
>  include/block/block.h |  8 +-
>  include/block/block_int.h |  3 +--
>  26 files changed, 378 insertions(+), 344 deletions(-)
>

[snip lots of code]

> diff --git a/block/blkdebug.c b/block/blkdebug.c
> index bc247f4..117fce6 100644
> --- a/block/blkdebug.c
> +++ b/block/blkdebug.c
> @@ -427,10 +427,10 @@ static int blkdebug_open(BlockDriverState *bs, QDict 
> *options, int flags,
>  s->state = 1;
>  
>  /* Open the backing file */
> -assert(bs->file == NULL);
> -ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, 
> "image",
> -  bs, &child_file, false, &local_err);
> -if (ret < 0) {
> +bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, 
> "image",
> +   bs, &child_file, false, &local_err);
> +if (local_err) {
> +ret = -EINVAL;
>  error_propagate(errp, local_err);
>  goto out;
>  }
> @@ -449,7 +449,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict 
> *options, int flags,
>  goto out;
>  
>  fail_unref:
> -bdrv_unref(bs->file);
> +bdrv_unref(bs->file->bs);


Would it be better to use bdrv_unref_child() here?

[snip lots of code]

> diff --git a/block/qcow.c b/block/qcow.c
> index 6e35db1..4d20cd5 100644
> --- a/block/qcow.c
> +++ b/block/qcow.c
> @@ -100,7 +100,7 @@ static int qcow_open(BlockDriverState *bs, QDict 
> *options, int flags,
>  int ret;
>  QCowHeader header;
>  
> -ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
> +ret = bdrv_pread(bs->file->bs, 0, &header, sizeof(header));
>  if (ret < 0) {
>  goto fail;
>  }
> @@ -193,7 +193,7 @@ static int qcow_open(BlockDriverState *bs, QDict 
> *options, int flags,
>  goto fail;
>  }
>  
> -ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
> +ret = bdrv_pread(bs->file->bs, s->l1_table_offset, s->l1_table,
> s->l1_size * sizeof(uint64_t));
>  if (ret < 0) {
>  goto fail;
> @@ -205,7 +205,7 @@ static int qcow_open(BlockDriverState *bs, QDict 
> *options, int flags,
>  
>  /* alloc L2 cache (max. 64k * 16 * 8 = 8 MB) */
>  s->l2_cache =
> -qemu_try_blockalign(bs->file,
> +qemu_try_blockalign(bs->file->bs,
>  s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
>  if (s->l2_cache == NULL) {
>  error_setg(errp, "Could not allocate L2 table cache");
> @@ -224,7 +224,7 @@ static int qcow_open(BlockDriverState *bs, QDict 
> *options, int flags,
>  ret = -EINVAL;
>  goto fail;
>  }
> -ret = bdrv_pread(bs->file, header.backing_file_offset,
> +ret = bdrv_pread(bs->file->bs, header.backing_file_offset,
> bs->backing_file, len);
>  if (ret < 0) {
>  goto fail;
> @@ -369,13 +369,13 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
>  if (!allocate)
>  return 0;
>  /* allocate a new l2 entry */
> -l2_offset = bdrv_getlength(bs->file);
> +l2_offset = bdrv_getlength(bs->file->bs);
>  /* round to cluster size */
>  l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 
> 1);
>  /* update the L1 entry */
>  s->l1_tabl

Re: [Qemu-devel] [PATCH] block: qemu-iotests - fix vmdk test 059.out

2015-10-12 Thread Fam Zheng
On Mon, 10/12 20:18, Jeff Cody wrote:
> In commit fe646693acc13ac48b98435d14149ab04dc597bc, the option
> printout format changed.
> 
> This updates the VMDK test 059.out to the correct output.
> 
> Signed-off-by: Jeff Cody 
> ---
>  tests/qemu-iotests/059.out | 12 ++--
>  1 file changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
> index 67e3cf5..00057fe 100644
> --- a/tests/qemu-iotests/059.out
> +++ b/tests/qemu-iotests/059.out
> @@ -16,17 +16,17 @@ qemu-io: can't open device TEST_DIR/t.vmdk: L1 size too 
> big
>  no file open, try 'help open'
>  
>  === Testing monolithicFlat creation and opening ===
> -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
> +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 
> subformat=monolithicFlat
>  image: TEST_DIR/t.IMGFMT
>  file format: IMGFMT
>  virtual size: 2.0G (2147483648 bytes)
>  
>  === Testing monolithicFlat with zeroed_grain ===
>  qemu-img: TEST_DIR/t.IMGFMT: Flat image can't enable zeroed grain
> -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
> +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 
> subformat=monolithicFlat
>  
>  === Testing big twoGbMaxExtentFlat ===
> -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000
> +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 
> subformat=twoGbMaxExtentFlat
>  image: TEST_DIR/t.vmdk
>  file format: vmdk
>  virtual size: 1.0T (1073741824000 bytes)
> @@ -2043,7 +2043,7 @@ RW 12582912 VMFS "dummy.IMGFMT" 1
>  
>  
>  === Testing truncated sparse ===
> -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400
> +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 
> subformat=monolithicSparse
>  qemu-img: Could not open 'TEST_DIR/t.IMGFMT': File truncated, expecting at 
> least 13172736 bytes
>  
>  === Converting to streamOptimized from image with small cluster size===
> @@ -2054,7 +2054,7 @@ wrote 512/512 bytes at offset 10240
>  512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
>  
>  === Testing monolithicFlat with internally generated JSON file name ===
> -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
> +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
> subformat=monolithicFlat
>  qemu-io: can't open: Cannot use relative extent paths with VMDK descriptor 
> file 'json:{"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, 
> "driver": "blkdebug", "inject-error.0.event": "read_aio"}'
>  
>  === Testing version 3 ===
> @@ -2264,7 +2264,7 @@ read 512/512 bytes at offset 64931328
>  512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
>  
>  === Testing 4TB monolithicFlat creation and IO ===
> -Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104
> +Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104 
> subformat=monolithicFlat
>  image: TEST_DIR/iotest-version3.IMGFMT
>  file format: IMGFMT
>  virtual size: 4.0T (4398046511104 bytes)
> -- 
> 1.9.3
> 

Reviewed-by: Fam Zheng 



Re: [Qemu-devel] [PATCH v3 04/16] quorum: Convert to BdrvChild

2015-10-12 Thread Jeff Cody
On Fri, Oct 09, 2015 at 02:15:29PM +0200, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf 
> Reviewed-by: Max Reitz 
> Reviewed-by: Alberto Garcia 
> Reviewed-by: Fam Zheng 
> ---
>  block/quorum.c | 65 
> ++
>  1 file changed, 34 insertions(+), 31 deletions(-)
> 
> diff --git a/block/quorum.c b/block/quorum.c
> index 8fe53b4..b9ba028 100644
> --- a/block/quorum.c
> +++ b/block/quorum.c
> @@ -64,7 +64,7 @@ typedef struct QuorumVotes {
>  
>  /* the following structure holds the state of one quorum instance */
>  typedef struct BDRVQuorumState {
> -BlockDriverState **bs; /* children BlockDriverStates */
> +BdrvChild **children;  /* children BlockDriverStates */
>  int num_children;  /* children count */
>  int threshold; /* if less than threshold children reads gave the
>  * same result a quorum error occurs.
> @@ -336,7 +336,7 @@ static void quorum_report_bad_versions(BDRVQuorumState *s,
>  continue;
>  }
>  QLIST_FOREACH(item, &version->items, next) {
> -quorum_report_bad(acb, s->bs[item->index]->node_name, 0);
> +quorum_report_bad(acb, s->children[item->index]->bs->node_name, 
> 0);
>  }
>  }
>  }
> @@ -369,8 +369,9 @@ static bool quorum_rewrite_bad_versions(BDRVQuorumState 
> *s, QuorumAIOCB *acb,
>  continue;
>  }
>  QLIST_FOREACH(item, &version->items, next) {
> -bdrv_aio_writev(s->bs[item->index], acb->sector_num, acb->qiov,
> -acb->nb_sectors, quorum_rewrite_aio_cb, acb);
> +bdrv_aio_writev(s->children[item->index]->bs, acb->sector_num,
> +acb->qiov, acb->nb_sectors, 
> quorum_rewrite_aio_cb,
> +acb);
>  }
>  }
>  
> @@ -639,13 +640,13 @@ static BlockAIOCB *read_quorum_children(QuorumAIOCB 
> *acb)
>  int i;
>  
>  for (i = 0; i < s->num_children; i++) {
> -acb->qcrs[i].buf = qemu_blockalign(s->bs[i], acb->qiov->size);
> +acb->qcrs[i].buf = qemu_blockalign(s->children[i]->bs, 
> acb->qiov->size);
>  qemu_iovec_init(&acb->qcrs[i].qiov, acb->qiov->niov);
>  qemu_iovec_clone(&acb->qcrs[i].qiov, acb->qiov, acb->qcrs[i].buf);
>  }
>  
>  for (i = 0; i < s->num_children; i++) {
> -bdrv_aio_readv(s->bs[i], acb->sector_num, &acb->qcrs[i].qiov,
> +bdrv_aio_readv(s->children[i]->bs, acb->sector_num, 
> &acb->qcrs[i].qiov,
> acb->nb_sectors, quorum_aio_cb, &acb->qcrs[i]);
>  }
>  
> @@ -656,12 +657,12 @@ static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb)
>  {
>  BDRVQuorumState *s = acb->common.bs->opaque;
>  
> -acb->qcrs[acb->child_iter].buf = qemu_blockalign(s->bs[acb->child_iter],
> - acb->qiov->size);
> +acb->qcrs[acb->child_iter].buf =
> +qemu_blockalign(s->children[acb->child_iter]->bs, acb->qiov->size);
>  qemu_iovec_init(&acb->qcrs[acb->child_iter].qiov, acb->qiov->niov);
>  qemu_iovec_clone(&acb->qcrs[acb->child_iter].qiov, acb->qiov,
>   acb->qcrs[acb->child_iter].buf);
> -bdrv_aio_readv(s->bs[acb->child_iter], acb->sector_num,
> +bdrv_aio_readv(s->children[acb->child_iter]->bs, acb->sector_num,
> &acb->qcrs[acb->child_iter].qiov, acb->nb_sectors,
> quorum_aio_cb, &acb->qcrs[acb->child_iter]);
>  
> @@ -702,8 +703,8 @@ static BlockAIOCB *quorum_aio_writev(BlockDriverState *bs,
>  int i;
>  
>  for (i = 0; i < s->num_children; i++) {
> -acb->qcrs[i].aiocb = bdrv_aio_writev(s->bs[i], sector_num, qiov,
> - nb_sectors, &quorum_aio_cb,
> +acb->qcrs[i].aiocb = bdrv_aio_writev(s->children[i]->bs, sector_num,
> + qiov, nb_sectors, 
> &quorum_aio_cb,
>   &acb->qcrs[i]);
>  }
>  
> @@ -717,12 +718,12 @@ static int64_t quorum_getlength(BlockDriverState *bs)
>  int i;
>  
>  /* check that all file have the same length */
> -result = bdrv_getlength(s->bs[0]);
> +result = bdrv_getlength(s->children[0]->bs);
>  if (result < 0) {
>  return result;
>  }
>  for (i = 1; i < s->num_children; i++) {
> -int64_t value = bdrv_getlength(s->bs[i]);
> +int64_t value = bdrv_getlength(s->children[i]->bs);
>  if (value < 0) {
>  return value;
>  }
> @@ -741,7 +742,7 @@ static void quorum_invalidate_cache(BlockDriverState *bs, 
> Error **errp)
>  int i;
>  
>  for (i = 0; i < s->num_children; i++) {
> -bdrv_invalidate_cache(s->bs[i], &local_err);
> +bdrv_invalidate_cache(s->children[i]->bs, &local_err);
>  if (local_err) {
>  error_propagate(errp, local_err);
>  return;
> @@ -762,7 +763

Re: [Qemu-devel] [PATCH v3 03/16] blkverify: Convert s->test_file to BdrvChild

2015-10-12 Thread Jeff Cody
On Fri, Oct 09, 2015 at 02:15:28PM +0200, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf 
> Reviewed-by: Max Reitz 
> Reviewed-by: Alberto Garcia 
> Reviewed-by: Fam Zheng 
> ---
>  block/blkverify.c | 41 +
>  1 file changed, 21 insertions(+), 20 deletions(-)
> 
> diff --git a/block/blkverify.c b/block/blkverify.c
> index d277e63..6b71622 100644
> --- a/block/blkverify.c
> +++ b/block/blkverify.c
> @@ -14,7 +14,7 @@
>  #include "qapi/qmp/qstring.h"
>  
>  typedef struct {
> -BlockDriverState *test_file;
> +BdrvChild *test_file;
>  } BDRVBlkverifyState;
>  
>  typedef struct BlkverifyAIOCB BlkverifyAIOCB;
> @@ -132,12 +132,12 @@ static int blkverify_open(BlockDriverState *bs, QDict 
> *options, int flags,
>  }
>  
>  /* Open the test file */
> -assert(s->test_file == NULL);
> -ret = bdrv_open_image(&s->test_file, qemu_opt_get(opts, "x-image"), 
> options,
> -  "test", bs, &child_format, false, &local_err);
> -if (ret < 0) {
> +s->test_file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options,
> +   "test", bs, &child_format, false,
> +   &local_err);
> +if (local_err) {
> +ret = -EINVAL;
>  error_propagate(errp, local_err);
> -s->test_file = NULL;
>  goto fail;
>  }
>  
> @@ -151,7 +151,7 @@ static void blkverify_close(BlockDriverState *bs)
>  {
>  BDRVBlkverifyState *s = bs->opaque;
>  
> -bdrv_unref(s->test_file);
> +bdrv_unref_child(bs, s->test_file);
>  s->test_file = NULL;
>  }
>  
> @@ -159,7 +159,7 @@ static int64_t blkverify_getlength(BlockDriverState *bs)
>  {
>  BDRVBlkverifyState *s = bs->opaque;
>  
> -return bdrv_getlength(s->test_file);
> +return bdrv_getlength(s->test_file->bs);
>  }
>  
>  static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
> @@ -242,7 +242,7 @@ static BlockAIOCB *blkverify_aio_readv(BlockDriverState 
> *bs,
>  qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
>  qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
>  
> -bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors,
> +bdrv_aio_readv(s->test_file->bs, sector_num, qiov, nb_sectors,
> blkverify_aio_cb, acb);
>  bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
> blkverify_aio_cb, acb);
> @@ -257,7 +257,7 @@ static BlockAIOCB *blkverify_aio_writev(BlockDriverState 
> *bs,
>  BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
>  nb_sectors, cb, opaque);
>  
> -bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors,
> +bdrv_aio_writev(s->test_file->bs, sector_num, qiov, nb_sectors,
>  blkverify_aio_cb, acb);
>  bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
>  blkverify_aio_cb, acb);
> @@ -271,7 +271,7 @@ static BlockAIOCB *blkverify_aio_flush(BlockDriverState 
> *bs,
>  BDRVBlkverifyState *s = bs->opaque;
>  
>  /* Only flush test file, the raw file is not important */
> -return bdrv_aio_flush(s->test_file, cb, opaque);
> +return bdrv_aio_flush(s->test_file->bs, cb, opaque);
>  }
>  
>  static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
> @@ -285,7 +285,7 @@ static bool 
> blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
>  return true;
>  }
>  
> -return bdrv_recurse_is_first_non_filter(s->test_file, candidate);
> +return bdrv_recurse_is_first_non_filter(s->test_file->bs, candidate);
>  }
>  
>  /* Propagate AioContext changes to ->test_file */
> @@ -293,7 +293,7 @@ static void blkverify_detach_aio_context(BlockDriverState 
> *bs)
>  {
>  BDRVBlkverifyState *s = bs->opaque;
>  
> -bdrv_detach_aio_context(s->test_file);
> +bdrv_detach_aio_context(s->test_file->bs);
>  }
>  
>  static void blkverify_attach_aio_context(BlockDriverState *bs,
> @@ -301,7 +301,7 @@ static void blkverify_attach_aio_context(BlockDriverState 
> *bs,
>  {
>  BDRVBlkverifyState *s = bs->opaque;
>  
> -bdrv_attach_aio_context(s->test_file, new_context);
> +bdrv_attach_aio_context(s->test_file->bs, new_context);
>  }
>  
>  static void blkverify_refresh_filename(BlockDriverState *bs)
> @@ -309,24 +309,25 @@ static void blkverify_refresh_filename(BlockDriverState 
> *bs)
>  BDRVBlkverifyState *s = bs->opaque;
>  
>  /* bs->file has already been refreshed */
> -bdrv_refresh_filename(s->test_file);
> +bdrv_refresh_filename(s->test_file->bs);
>  
> -if (bs->file->full_open_options && s->test_file->full_open_options) {
> +if (bs->file->full_open_options && s->test_file->bs->full_open_options) {
>  QDict *opts = qdict_new();
>  qdict_put_obj(opts, "driver", 
> QOBJECT(qstring_from_str("blkverify")));
>  
>  QINCREF(bs->file->full_open_options);
>  qdict_

[Qemu-devel] [Bug 1465935] Re: kvm_irqchip_commit_routes: Assertion `ret == 0' failed

2015-10-12 Thread Li Chengyuan
@Stefan Bader,
The host OS is ubuntu 12.04, and we upgraded the QEMU to 2.0.0 from ubuntu 
cloud-archive repo.
https://wiki.ubuntu.com/ServerTeam/CloudArchive

-- 
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1465935

Title:
  kvm_irqchip_commit_routes: Assertion `ret == 0' failed

Status in QEMU:
  New
Status in qemu package in Ubuntu:
  Fix Released
Status in qemu source package in Precise:
  New
Status in qemu source package in Trusty:
  New
Status in qemu source package in Utopic:
  Won't Fix
Status in qemu source package in Vivid:
  New

Bug description:
  Several my QEMU instances crashed, and in the  qemu log, I can see
  this assertion failure,

 qemu-system-x86_64: /build/buildd/qemu-2.0.0+dfsg/kvm-all.c:984:
  kvm_irqchip_commit_routes: Assertion `ret == 0' failed.

  The QEMU version is 2.0.0, HV OS is ubuntu 12.04, kernel 3.2.0-38.
  Guest OS is RHEL 6.3.

To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1465935/+subscriptions



Re: [Qemu-devel] [PATCH v3 02/16] vmdk: Use BdrvChild instead of BDS for references to extents

2015-10-12 Thread Jeff Cody
On Fri, Oct 09, 2015 at 02:15:27PM +0200, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf 
> Reviewed-by: Max Reitz 
> Reviewed-by: Alberto Garcia 
> Reviewed-by: Fam Zheng 
> ---
>  block/vmdk.c | 99 
> +++-
>  1 file changed, 51 insertions(+), 48 deletions(-)
> 
> diff --git a/block/vmdk.c b/block/vmdk.c
> index be0d640..9702132 100644
> --- a/block/vmdk.c
> +++ b/block/vmdk.c
> @@ -87,7 +87,7 @@ typedef struct {
>  #define L2_CACHE_SIZE 16
>  
>  typedef struct VmdkExtent {
> -BlockDriverState *file;
> +BdrvChild *file;
>  bool flat;
>  bool compressed;
>  bool has_marker;
> @@ -221,8 +221,8 @@ static void vmdk_free_extents(BlockDriverState *bs)
>  g_free(e->l2_cache);
>  g_free(e->l1_backup_table);
>  g_free(e->type);
> -if (e->file != bs->file) {
> -bdrv_unref(e->file);
> +if (e->file != bs->file_child) {
> +bdrv_unref_child(bs, e->file);
>  }
>  }
>  g_free(s->extents);
> @@ -367,7 +367,7 @@ static int vmdk_parent_open(BlockDriverState *bs)
>  /* Create and append extent to the extent array. Return the added VmdkExtent
>   * address. return NULL if allocation failed. */
>  static int vmdk_add_extent(BlockDriverState *bs,
> -   BlockDriverState *file, bool flat, int64_t 
> sectors,
> +   BdrvChild *file, bool flat, int64_t sectors,
> int64_t l1_offset, int64_t l1_backup_offset,
> uint32_t l1_size,
> int l2_size, uint64_t cluster_sectors,
> @@ -392,7 +392,7 @@ static int vmdk_add_extent(BlockDriverState *bs,
>  return -EFBIG;
>  }
>  
> -nb_sectors = bdrv_nb_sectors(file);
> +nb_sectors = bdrv_nb_sectors(file->bs);
>  if (nb_sectors < 0) {
>  return nb_sectors;
>  }
> @@ -439,14 +439,14 @@ static int vmdk_init_tables(BlockDriverState *bs, 
> VmdkExtent *extent,
>  return -ENOMEM;
>  }
>  
> -ret = bdrv_pread(extent->file,
> +ret = bdrv_pread(extent->file->bs,
>   extent->l1_table_offset,
>   extent->l1_table,
>   l1_size);
>  if (ret < 0) {
>  error_setg_errno(errp, -ret,
>   "Could not read l1 table from extent '%s'",
> - extent->file->filename);
> + extent->file->bs->filename);
>  goto fail_l1;
>  }
>  for (i = 0; i < extent->l1_size; i++) {
> @@ -459,14 +459,14 @@ static int vmdk_init_tables(BlockDriverState *bs, 
> VmdkExtent *extent,
>  ret = -ENOMEM;
>  goto fail_l1;
>  }
> -ret = bdrv_pread(extent->file,
> +ret = bdrv_pread(extent->file->bs,
>   extent->l1_backup_table_offset,
>   extent->l1_backup_table,
>   l1_size);
>  if (ret < 0) {
>  error_setg_errno(errp, -ret,
>   "Could not read l1 backup table from extent 
> '%s'",
> - extent->file->filename);
> + extent->file->bs->filename);
>  goto fail_l1b;
>  }
>  for (i = 0; i < extent->l1_size; i++) {
> @@ -485,7 +485,7 @@ static int vmdk_init_tables(BlockDriverState *bs, 
> VmdkExtent *extent,
>  }
>  
>  static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
> - BlockDriverState *file,
> + BdrvChild *file,
>   int flags, Error **errp)
>  {
>  int ret;
> @@ -493,11 +493,11 @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
>  VMDK3Header header;
>  VmdkExtent *extent;
>  
> -ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
> +ret = bdrv_pread(file->bs, sizeof(magic), &header, sizeof(header));
>  if (ret < 0) {
>  error_setg_errno(errp, -ret,
>   "Could not read header from file '%s'",
> - file->filename);
> + file->bs->filename);
>  return ret;
>  }
>  ret = vmdk_add_extent(bs, file, false,
> @@ -559,7 +559,7 @@ static char *vmdk_read_desc(BlockDriverState *file, 
> uint64_t desc_offset,
>  }
>  
>  static int vmdk_open_vmdk4(BlockDriverState *bs,
> -   BlockDriverState *file,
> +   BdrvChild *file,
> int flags, QDict *options, Error **errp)
>  {
>  int ret;
> @@ -570,17 +570,17 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
>  BDRVVmdkState *s = bs->opaque;
>  int64_t l1_backup_offset = 0;
>  
> -ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
> +ret = bdrv_pread(file->bs, sizeof(magic), &header, sizeof(header));
>  if (ret < 0) {
>  error_setg_

Re: [Qemu-devel] [PATCH v3 01/16] block: Introduce BDS.file_child

2015-10-12 Thread Jeff Cody
On Fri, Oct 09, 2015 at 02:15:26PM +0200, Kevin Wolf wrote:
> Store the BdrvChild for bs->file. At this point, bs->file_child->bs just
> duplicates the bs->file pointer. Later, it will completely replace it.
> 
> Signed-off-by: Kevin Wolf 
> Reviewed-by: Max Reitz 
> Reviewed-by: Alberto Garcia 
> Reviewed-by: Fam Zheng 
> ---
>  block.c   | 12 +---
>  include/block/block_int.h |  1 +
>  2 files changed, 10 insertions(+), 3 deletions(-)
> 
> diff --git a/block.c b/block.c
> index 1f90b47..75afed1 100644
> --- a/block.c
> +++ b/block.c
> @@ -1487,11 +1487,17 @@ static int bdrv_open_inherit(BlockDriverState **pbs, 
> const char *filename,
>  
>  assert(file == NULL);
>  bs->open_flags = flags;
> -ret = bdrv_open_image(&file, filename, options, "file",
> -  bs, &child_file, true, &local_err);
> -if (ret < 0) {
> +
> +bs->file_child = bdrv_open_child(filename, options, "file", bs,
> + &child_file, true, &local_err);
> +if (local_err) {
> +ret = -EINVAL;
>  goto fail;
>  }
> +
> +if (bs->file_child) {
> +file = bs->file_child->bs;
> +}
>  }
>  
>  /* Image format probing */
> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index 14ad4c3..d0dd93e 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -381,6 +381,7 @@ struct BlockDriverState {
>  BlockDriverState *backing_hd;
>  BdrvChild *backing_child;
>  BlockDriverState *file;
> +BdrvChild *file_child;
>  
>  NotifierList close_notifiers;
>  
> -- 
> 1.8.3.1
> 

Reviewed-by: Jeff Cody 



[Qemu-devel] [PATCH] block: qemu-iotests - fix vmdk test 059.out

2015-10-12 Thread Jeff Cody
In commit fe646693acc13ac48b98435d14149ab04dc597bc, the option
printout format changed.

This updates the VMDK test 059.out to the correct output.

Signed-off-by: Jeff Cody 
---
 tests/qemu-iotests/059.out | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
index 67e3cf5..00057fe 100644
--- a/tests/qemu-iotests/059.out
+++ b/tests/qemu-iotests/059.out
@@ -16,17 +16,17 @@ qemu-io: can't open device TEST_DIR/t.vmdk: L1 size too big
 no file open, try 'help open'
 
 === Testing monolithicFlat creation and opening ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 
subformat=monolithicFlat
 image: TEST_DIR/t.IMGFMT
 file format: IMGFMT
 virtual size: 2.0G (2147483648 bytes)
 
 === Testing monolithicFlat with zeroed_grain ===
 qemu-img: TEST_DIR/t.IMGFMT: Flat image can't enable zeroed grain
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 
subformat=monolithicFlat
 
 === Testing big twoGbMaxExtentFlat ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 
subformat=twoGbMaxExtentFlat
 image: TEST_DIR/t.vmdk
 file format: vmdk
 virtual size: 1.0T (1073741824000 bytes)
@@ -2043,7 +2043,7 @@ RW 12582912 VMFS "dummy.IMGFMT" 1
 
 
 === Testing truncated sparse ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 
subformat=monolithicSparse
 qemu-img: Could not open 'TEST_DIR/t.IMGFMT': File truncated, expecting at 
least 13172736 bytes
 
 === Converting to streamOptimized from image with small cluster size===
@@ -2054,7 +2054,7 @@ wrote 512/512 bytes at offset 10240
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 
 === Testing monolithicFlat with internally generated JSON file name ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
subformat=monolithicFlat
 qemu-io: can't open: Cannot use relative extent paths with VMDK descriptor 
file 'json:{"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, 
"driver": "blkdebug", "inject-error.0.event": "read_aio"}'
 
 === Testing version 3 ===
@@ -2264,7 +2264,7 @@ read 512/512 bytes at offset 64931328
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 
 === Testing 4TB monolithicFlat creation and IO ===
-Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104
+Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104 
subformat=monolithicFlat
 image: TEST_DIR/iotest-version3.IMGFMT
 file format: IMGFMT
 virtual size: 4.0T (4398046511104 bytes)
-- 
1.9.3




Re: [Qemu-devel] [PULL 04/26] target-*: Introduce and use cpu_breakpoint_test

2015-10-12 Thread Richard Henderson

On 10/10/2015 12:34 AM, Sergey Fedorov wrote:

@@ -2936,6 +2927,10 @@ static inline void 
gen_intermediate_code_internal(AlphaCPU *cpu,
  tcg_gen_insn_start(ctx.pc);
  num_insns++;

+if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
+gen_excp(&ctx, EXCP_DEBUG, 0);
+break;
+}


Actually, control logic has changed here. The old code used a break
statement to exit from QTAILQ_FOREACH loop and continue with instruction
translation thus translating at least one instruction. The break
statement in the new code makes exit from the translation loop itself,
effectively producing zero-length TB which won't get invalidated when
clearing the breakpoint. Seems like we should remove the break statement
here and in similar cases below, right?


Why do you believe that a zero-length TB won't be cleared?
The TB still has a start address, which is contained within
a given page, which is invalidated.

Some target-*/translate.c takes care to advance the PC, but I believe that this 
is only required when the breakpoint instruction *itself* could span a page 
boundary.  I.e. the TB needs to be marked to span two pages.  This situation 
can never be true for many RISC targets.


We did discuss this exact situation during review of the patch set, though it's 
probably true that there are outstanding errors in some translators.



r~



[Qemu-devel] [PATCH v3 4/4] qemu-iotests: update tests for generated node-names

2015-10-12 Thread Jeff Cody
Signed-off-by: Jeff Cody 
---
 tests/qemu-iotests/041 | 4 ++--
 tests/qemu-iotests/051 | 3 ++-
 tests/qemu-iotests/051.out | 2 +-
 tests/qemu-iotests/067 | 3 ++-
 tests/qemu-iotests/067.out | 5 +
 tests/qemu-iotests/081 | 3 ++-
 tests/qemu-iotests/081.out | 2 +-
 7 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
index 59c1a76..05b5962 100755
--- a/tests/qemu-iotests/041
+++ b/tests/qemu-iotests/041
@@ -780,7 +780,7 @@ class TestRepairQuorum(iotests.QMPTestCase):
 # here we check that the last registered quorum file has not been
 # swapped out and unref
 result = self.vm.qmp('query-named-block-nodes')
-self.assert_qmp(result, 'return[0]/file', quorum_img3)
+self.assert_qmp(result, 'return[1]/file', quorum_img3)
 self.vm.shutdown()
 
 def test_cancel_after_ready(self):
@@ -799,7 +799,7 @@ class TestRepairQuorum(iotests.QMPTestCase):
 result = self.vm.qmp('query-named-block-nodes')
 # here we check that the last registered quorum file has not been
 # swapped out and unref
-self.assert_qmp(result, 'return[0]/file', quorum_img3)
+self.assert_qmp(result, 'return[1]/file', quorum_img3)
 self.vm.shutdown()
 self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
 'target image does not match source after mirroring')
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 4a8055b..17dbf04 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -108,7 +108,8 @@ echo
 echo === Overriding backing file ===
 echo
 
-echo "info block" | run_qemu -drive 
file="$TEST_IMG",driver=qcow2,backing.file.filename="$TEST_IMG.orig" -nodefaults
+echo "info block" | run_qemu -drive 
file="$TEST_IMG",driver=qcow2,backing.file.filename="$TEST_IMG.orig" 
-nodefaults\
+  | _filter_generated_node_ids
 
 # Drivers that don't support backing files
 run_qemu -drive 
file="$TEST_IMG",driver=raw,backing.file.filename="$TEST_IMG.orig"
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index 0429be2..7765aa0 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -59,7 +59,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
 Testing: -drive 
file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig 
-nodefaults
 QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) iininfinfoinfo 
info binfo 
blinfo bloinfo 
blocinfo block
-ide0-hd0: TEST_DIR/t.qcow2 (qcow2)
+ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
 Cache mode:   writeback
 Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1)
 (qemu) qququiquit
diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067
index 3e9a053..3788534 100755
--- a/tests/qemu-iotests/067
+++ b/tests/qemu-iotests/067
@@ -48,7 +48,8 @@ function do_run_qemu()
 function run_qemu()
 {
 do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | _filter_qemu \
-  | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g'
+  | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' \
+  | _filter_generated_node_ids
 }
 
 size=128M
diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out
index 5fbc881..27ad56f 100644
--- a/tests/qemu-iotests/067.out
+++ b/tests/qemu-iotests/067.out
@@ -40,6 +40,7 @@ Testing: -drive 
file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
 },
 "iops_wr": 0,
 "ro": false,
+"node-name": "NODE_NAME",
 "backing_file_depth": 0,
 "drv": "qcow2",
 "iops": 0,
@@ -151,6 +152,7 @@ Testing: -drive 
file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
 },
 "iops_wr": 0,
 "ro": false,
+"node-name": "NODE_NAME",
 "backing_file_depth": 0,
 "drv": "qcow2",
 "iops": 0,
@@ -270,6 +272,7 @@ Testing:
 },
 "iops_wr": 0,
 "ro": false,
+"node-name": "NODE_NAME",
 "backing_file_depth": 0,
 "drv": "qcow2",
 "iops": 0,
@@ -390,6 +393,7 @@ Testing:
 },
 "iops_wr": 0,
 "ro": false,
+"node-name": "NODE_NAME",
 "backing_file_depth": 0,
 "drv": "qcow2",
 "iops": 0,
@@ -480,6 +484,7 @@ Testing:
 },
 "iops_wr": 0,
 "ro": false,
+"node-name": "NODE_NAME",
 "backing_file_depth": 0,
  

[Qemu-devel] [PATCH v3 2/4] block: auto-generated node-names

2015-10-12 Thread Jeff Cody
If a node-name is not specified, automatically generate the node-name.

Generated node-names will use the "block" sub-system identifier.

Reviewed-by: Eric Blake 
Reviewed-by: John Snow 
Signed-off-by: Jeff Cody 
---
 block.c | 19 ---
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/block.c b/block.c
index 1f90b47..5947704 100644
--- a/block.c
+++ b/block.c
@@ -763,12 +763,15 @@ static void bdrv_assign_node_name(BlockDriverState *bs,
   const char *node_name,
   Error **errp)
 {
+char *gen_node_name = NULL;
+
 if (!node_name) {
-return;
-}
-
-/* Check for empty string or invalid characters */
-if (!id_wellformed(node_name)) {
+node_name = gen_node_name = id_generate(ID_BLOCK);
+} else if (!id_wellformed(node_name)) {
+/*
+ * Check for empty string or invalid characters, but not if it is
+ * generated (generated names use characters not available to the user)
+ */
 error_setg(errp, "Invalid node name");
 return;
 }
@@ -777,18 +780,20 @@ static void bdrv_assign_node_name(BlockDriverState *bs,
 if (blk_by_name(node_name)) {
 error_setg(errp, "node-name=%s is conflicting with a device id",
node_name);
-return;
+goto out;
 }
 
 /* takes care of avoiding duplicates node names */
 if (bdrv_find_node(node_name)) {
 error_setg(errp, "Duplicate node name");
-return;
+goto out;
 }
 
 /* copy node name into the bs and insert it into the graph list */
 pstrcpy(bs->node_name, sizeof(bs->node_name), node_name);
 QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs, node_list);
+out:
+g_free(gen_node_name);
 }
 
 static QemuOptsList bdrv_runtime_opts = {
-- 
1.9.3




[Qemu-devel] [PATCH v3 3/4] block: add filter for generated node-names

2015-10-12 Thread Jeff Cody
Signed-off-by: Jeff Cody 
---
 tests/qemu-iotests/common.filter | 5 +
 1 file changed, 5 insertions(+)

diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index d6d05de..cfdb633 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -128,6 +128,11 @@ _filter_date()
 -e 's/[A-Z][a-z][a-z] [A-z][a-z][a-z]  *[0-9][0-9]* 
[0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]$/DATE/'
 }
 
+_filter_generated_node_ids()
+{
+ sed -re 's/\#block[0-9]{3,}/NODE_NAME/'
+}
+
 # replace occurrences of the actual TEST_DIR value with TEST_DIR
 _filter_testdir()
 {
-- 
1.9.3




[Qemu-devel] [PATCH v3 1/4] util - add automated ID generation utility

2015-10-12 Thread Jeff Cody
Multiple sub-systems in QEMU may find it useful to generate IDs
for objects that a user may reference via QMP or HMP.  This patch
presents a standardized way to do it, so that automatic ID generation
follows the same rules.

This patch enforces the following rules when generating an ID:

1.) Guarantee no collisions with a user-specified ID
2.) Identify the sub-system the ID belongs to
3.) Guarantee of uniqueness
4.) Spoiling predictability, to avoid creating an assumption
of object ordering and parsing (i.e., we don't want users to think
they can guess the next ID based on prior behavior).

The scheme for this is as follows (no spaces):

# subsys D RR
Reserved char --||   | |
Subsystem String |   | |
Unique number (64-bit) --| |
Two-digit random number ---|

For example, a generated node-name for the block sub-system may look
like this:

#block076

The caller of id_generate() is responsible for freeing the generated
node name string with g_free().

Reviewed-by: John Snow 
Reviewed-by: Eric Blake 
Reviewed-by: Alberto Garcia 
Signed-off-by: Jeff Cody 
---
 include/qemu-common.h |  8 
 util/id.c | 37 +
 2 files changed, 45 insertions(+)

diff --git a/include/qemu-common.h b/include/qemu-common.h
index 0bd212b..2f74540 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -246,6 +246,14 @@ int64_t qemu_strtosz_suffix_unit(const char *nptr, char 
**end,
 #define STR_OR_NULL(str) ((str) ? (str) : "null")
 
 /* id.c */
+
+typedef enum IdSubSystems {
+ID_QDEV,
+ID_BLOCK,
+ID_MAX  /* last element, used as array size */
+} IdSubSystems;
+
+char *id_generate(IdSubSystems id);
 bool id_wellformed(const char *id);
 
 /* path.c */
diff --git a/util/id.c b/util/id.c
index 09b22fb..bcc64d8 100644
--- a/util/id.c
+++ b/util/id.c
@@ -26,3 +26,40 @@ bool id_wellformed(const char *id)
 }
 return true;
 }
+
+#define ID_SPECIAL_CHAR '#'
+
+static const char *const id_subsys_str[] = {
+[ID_QDEV]  = "qdev",
+[ID_BLOCK] = "block",
+};
+
+/*
+ *  Generates an ID of the form PREFIX SUBSYSTEM NUMBER
+ *  where:
+ *
+ *  - PREFIX is the reserved character '#'
+ *  - SUBSYSTEM identifies the subsystem creating the ID
+ *  - NUMBER is a decimal number unique within SUBSYSTEM.
+ *
+ *Example: "#block146"
+ *
+ * Note that these IDs do not satisfy id_wellformed().
+ *
+ * The caller is responsible for freeing the returned string with g_free()
+ */
+char *id_generate(IdSubSystems id)
+{
+static uint64_t id_counters[ID_MAX];
+uint32_t rnd;
+
+assert(id < ID_MAX);
+assert(id_subsys_str[id]);
+
+rnd = g_random_int_range(0, 100);
+
+return g_strdup_printf("%c%s%" PRIu64 "%02" PRId32, ID_SPECIAL_CHAR,
+id_subsys_str[id],
+id_counters[id]++,
+rnd);
+}
-- 
1.9.3




[Qemu-devel] [PATCH v3 0/4]

2015-10-12 Thread Jeff Cody
Changes from v2:

Patch 1:  Fixed prototype for id_generate() (thanks Alberto)
  Used *const instead of * const (thanks Eric, Markus)
  Updated function comment (thanks Markus)
  Made random in range 0-99 instead of 0-98 (thanks, Marksu)

Patch 2: Cleaned up comments (thanks Markus)
 use else if instead of nested if (thanks Markus)
 assign node_name on same line as gen_node_name (thanks Markus)

Patch 3,4: new - fix iotests (thanks Kevin)


Changes from RFC v1:

Patch 1: Several typos / grammatical errors (thanks Eric, John)
 Make id_subsys_str[] const pointer to const strings (thanks Eric)
 Moved id_subsys_str[] out from  id_generate() (thanks John)
 Assert on null string for given id (thanks Eric)
 Zero-pad the 2-digit random # (thanks John)

Patch 2: None

Born from the conversation on qemu-devel, this generation scheme uses the
format ultimately proposed by Kevin, after list discussion.

It attempts to keep the ID strings as small as possible, while fulfilling:

1.) Guarantee no collisions with a user-specified ID
2.) Identify the sub-system the ID belongs to
3.) Guarantee of uniqueness
4.) Spoiling predictibility, to avoid creating an assumption
of object ordering and parsing (i.e., we don't want users to think
they can guess the next ID based on prior behavior).

See patch 1 for the generation scheme details.

Jeff Cody (4):
  util - add automated ID generation utility
  block: auto-generated node-names
  block: add filter for generated node-names
  qemu-iotests: update tests for generated node-names

 block.c  | 19 ---
 include/qemu-common.h|  8 
 tests/qemu-iotests/041   |  4 ++--
 tests/qemu-iotests/051   |  3 ++-
 tests/qemu-iotests/051.out   |  2 +-
 tests/qemu-iotests/067   |  3 ++-
 tests/qemu-iotests/067.out   |  5 +
 tests/qemu-iotests/081   |  3 ++-
 tests/qemu-iotests/081.out   |  2 +-
 tests/qemu-iotests/common.filter |  5 +
 util/id.c| 37 +
 11 files changed, 77 insertions(+), 14 deletions(-)

-- 
1.9.3




Re: [Qemu-devel] [RFC 3/4] ahci: Add allwinner AHCI

2015-10-12 Thread John Snow
Is there any spec or documentation I can cross-reference this against?

I gather this exists within the vendor-specific reserved region from
0xA0 to 0xFF just prior to the port registers, so this all /looks/ like
it's right, I just don't have any way to verify it.

On 10/11/2015 12:21 PM, Peter Crosthwaite wrote:
> Add a Sysbus AHCI subclass for the Allwinner AHCI. It has a few extra
> vendor specific registers that are used for phy and power init.
> 
> Signed-off-by: Peter Crosthwaite 
> ---
>  hw/ide/ahci.c | 98 
> +++
>  hw/ide/ahci.h | 16 ++
>  2 files changed, 114 insertions(+)
> 
> diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
> index eff01b2..a7fa147 100644
> --- a/hw/ide/ahci.c
> +++ b/hw/ide/ahci.c
> @@ -1692,9 +1692,107 @@ static const TypeInfo sysbus_ahci_info = {
>  .class_init= sysbus_ahci_class_init,
>  };
>  
> +#define ALLWINNER_AHCI_MMIO_OFF  0x80
> +#define ALLWINNER_AHCI_MMIO_SIZE 0x80
> +
> +#define ALLWINNER_AHCI_BISTAFR((0xa0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_BISTCR ((0xa4 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_BISTFCTR   ((0xa8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_BISTSR ((0xac - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_BISTDECR   ((0xb0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_DIAGNR0((0xb4 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_DIAGNR1((0xb8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_OOBR   ((0xbc - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_PHYCS0R((0xc0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_PHYCS1R((0xc4 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_PHYCS2R((0xc8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_TIMER1MS   ((0xe0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_GPARAM1R   ((0xe8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_GPARAM2R   ((0xec - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_PPARAMR((0xf0 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_TESTR  ((0xf4 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_VERSIONR   ((0xf8 - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_IDR((0xfc - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +#define ALLWINNER_AHCI_RWCR   ((0xfc - ALLWINNER_AHCI_MMIO_OFF) / 4)
> +
> +static uint64_t allwinner_ahci_mem_read(void *opaque, hwaddr addr,
> +unsigned size)
> +{
> +AllwinnerAHCIState *a = opaque;
> +uint64_t val = a->regs[addr/4];
> +
> +switch (addr / 4) {
> +case ALLWINNER_AHCI_PHYCS0R:
> +val |= 0x2 << 28;
> +break;
> +case ALLWINNER_AHCI_PHYCS2R:
> +val &= ~(0x1 << 24);
> +break;
> +}
> +DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n",
> +addr, val, size);
> +return  val;
> +}
> +
> +static void allwinner_ahci_mem_write(void *opaque, hwaddr addr,
> + uint64_t val, unsigned size)
> +{
> +AllwinnerAHCIState *a = opaque;
> +
> +DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n",
> +addr, val, size);
> +a->regs[addr/4] = val;
> +}
> +
> +static const MemoryRegionOps allwinner_ahci_mem_ops = {
> +.read = allwinner_ahci_mem_read,
> +.write = allwinner_ahci_mem_write,
> +.valid.min_access_size = 4,
> +.valid.max_access_size = 4,

Are you sure devices won't try to read individual bytes for error codes
out of these vendor registers?

> +.endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void allwinner_ahci_init(Object *obj)
> +{
> +SysbusAHCIState *s = SYSBUS_AHCI(obj);
> +AllwinnerAHCIState *a = ALLWINNER_AHCI(obj);
> +
> +memory_region_init_io(&a->mmio, OBJECT(obj), &allwinner_ahci_mem_ops, a,
> +  "allwinner_ahci", ALLWINNER_AHCI_MMIO_SIZE);
> +memory_region_add_subregion(&s->ahci.mem, ALLWINNER_AHCI_MMIO_OFF,
> +&a->mmio);
> +}
> +
> +static const VMStateDescription vmstate_allwinner_ahci = {
> +.name = "a10.pic",
> +.version_id = 1,
> +.minimum_version_id = 1,
> +.fields = (VMStateField[]) {
> +VMSTATE_UINT32_ARRAY(regs, AllwinnerAHCIState,
> + ALLWINNER_AHCI_MMIO_SIZE/4),
> +VMSTATE_END_OF_LIST()
> +}
> +};
> +
> +static void allwinner_ahci_class_init(ObjectClass *klass, void *data)
> +{
> +DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +dc->vmsd = &vmstate_allwinner_ahci;
> +}
> +
> +static const TypeInfo allwinner_ahci_info = {
> +.name  = TYPE_ALLWINNER_AHCI,
> +.parent= TYPE_SYSBUS_AHCI,
> +.instance_size = sizeof(AllwinnerAHCIState),
> +.instance_init = allwinner_ahci_init,
> +.class_init= allwinner_ahci_class_init,
> +};
> +
>  static void sysbus_ahci_register_type

Re: [Qemu-devel] [PATCH v2] README: fill out some useful quickstart information

2015-10-12 Thread John Snow


On 10/12/2015 01:41 PM, Daniel P. Berrange wrote:
> The README file is usually the first thing consulted when a user
> or developer obtains a copy of the QEMU source. The current QEMU
> README is lacking immediately useful information and so not very
> friendly for first time encounters. It either redirects users to
> qemu-doc.html (which does not exist until they've actually
> compiled QEMU), or the website (which assumes the user has
> convenient internet access at time of reading).
> 
> This fills out the README file as simple quick-start guide on
> the topics of building source, submitting patches, licensing
> and how to contact the QEMU community. It does not intend to be
> comprehensive, instead referring people to an appropriate web
> page to obtain more detailed information. The intent is to give
> users quick guidance to get them going in the right direction.
> 
> Signed-off-by: Daniel P. Berrange 
> ---
> 
> Changed in v2:
> 
>  - Rewrote initial introduction to explain userspace emulators
>as well as system emulators
>  - Reformatted to 72 char line width
>  - Illustrate VPATH build instead of in-tree build
>  - Remove duplicated licensing info pointing to LICENSE file
> 
> I've not yet attempted to deal with the possible qemu-tech.texi
> changes discussed in the previous thread, as I figure that's best
> done separately.
> 
>  README | 108 
> +++--
>  1 file changed, 106 insertions(+), 2 deletions(-)
> 
> diff --git a/README b/README
> index c7c990d..819c985 100644
> --- a/README
> +++ b/README
> @@ -1,3 +1,107 @@
> -Read the documentation in qemu-doc.html or on http://wiki.qemu-project.org
> + QEMU README
> +  ===
>  
> -- QEMU team
> +QEMU is a generic and open source machine & userspace emulator and
> +virtualizer.
> +
> +QEMU is capable of emulating a complete machine in software without any
> +need for hardware virtualization support. By using dynamic translation,
> +it achieves very good performance. QEMU can also integrate with the Xen
> +and KVM hypervisors to provide emulated hardware while allowing the
> +hypervisor to manage the CPU. With hypervisor support, QEMU can achieve
> +near native performance for CPUs. When QEMU emulates CPUs directly it is
> +capable of running operating systems made for one machine (e.g. an ARMv7
> +board) on a different machine (e.g. an x86_64 PC board).
> +
> +QEMU is also capable of providing userspace API virtualization for Linux
> +and BSD kernel interfaces. This allows binaries compiled against one
> +architecture ABI (e.g. the Linux PPC64 ABI) to be run on a host using a
> +different architecture ABI (e.g. the Linux x86_64 ABI). This does not
> +involve any hardware emulation, simply CPU and syscall emulation.
> +
> +QEMU aims to fit into a variety of use cases. It can be invoked directly
> +by users wishing to have full control over its behaviour and settings.
> +It also aims to facilitate integration into higher level management
> +layers, by providing a stable command line interface and monitor API.
> +It is commonly invoked indirectly via the libvirt library when using
> +open source applications such as oVirt, OpenStack and virt-manager.
> +
> +QEMU as a whole is released under the GNU General Public License,
> +version 2. For full licensing details, consult the LICENSE file.
> +
> +
> +Building
> +
> +
> +QEMU is multi-platform software intended to be buildable on all modern
> +Linux platforms, OS-X, Win32 (via the Mingw64 toolchain) and a variety
> +of other UNIX targets. The simple steps to build QEMU are:
> +
> +  mkdir build
> +  cd build
> +  ./configure
> +  make
> +
> +Complete details of the process for building and configuring QEMU for
> +all supported host platforms can be found in the qemu-tech.html file.
> +Additional information can also be found online via the QEMU website:
> +
> +  http://qemu-project.org/Hosts/Linux
> +  http://qemu-project.org/Hosts/W32
> +
> +
> +Submitting patches
> +==
> +
> +The QEMU source code is maintained under the GIT version control system.
> +
> +   git clone git://git.qemu-project.org/qemu.git
> +
> +When submitting patches, the preferred approach is to use 'git
> +format-patch' and/or 'git send-email' to format & send the mail to the
> +qemu-devel@nongnu.org mailing list. All patches submitted must contain
> +a 'Signed-off-by' line from the author. Patches should follow the
> +guidelines set out in the HACKING and CODING_STYLE files.
> +
> +Additional information on submitting patches can be found online via
> +the QEMU website
> +
> +  http://qemu-project.org/Contribute/SubmitAPatch
> +  http://qemu-project.org/Contribute/TrivialPatches
> +
> +
> +Bug reporting
> +=
> +
> +The QEMU project uses Launchpad as its primary upstream bug tracker. Bugs
> +found when running code built from QEMU git or upstream released sources
> +should be reported via:
> +
> +  https://bugs.launchpa

Re: [Qemu-devel] [RFC 4/4] arm: allwinner-a10: Add SATA

2015-10-12 Thread John Snow


On 10/11/2015 12:21 PM, Peter Crosthwaite wrote:
> Add the Allwinner A10 AHCI controller module to the SoC.
> 
> Signed-off-by: Peter Crosthwaite 
> ---
>  hw/arm/allwinner-a10.c | 11 +++
>  include/hw/arm/allwinner-a10.h |  5 +
>  2 files changed, 16 insertions(+)
> 
> diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c
> index 56e924d..145038d 100644
> --- a/hw/arm/allwinner-a10.c
> +++ b/hw/arm/allwinner-a10.c
> @@ -42,6 +42,9 @@ static void aw_a10_init(Object *obj)
>  
>  object_initialize(&s->ccm, sizeof(s->ccm), TYPE_AW_A10_CCM);
>  qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
> +
> +object_initialize(&s->sata, sizeof(s->sata), TYPE_ALLWINNER_AHCI);
> +qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default());
>  }
>  
>  static void aw_a10_realize(DeviceState *dev, Error **errp)
> @@ -104,6 +107,14 @@ static void aw_a10_realize(DeviceState *dev, Error 
> **errp)
>  sysbusdev = SYS_BUS_DEVICE(&s->ccm);
>  sysbus_mmio_map(sysbusdev, 0, AW_A10_CCM_REG_BASE);
>  
> +object_property_set_bool(OBJECT(&s->sata), true, "realized", &err);
> +if (err) {
> +error_propagate(errp, err);
> +return;
> +}
> +sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, AW_A10_SATA_BASE);
> +sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, s->irq[56]);
> +
>  /* FIXME use a qdev chardev prop instead of serial_hds[] */
>  serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2, s->irq[1],
> 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
> diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h
> index 88632c0..e0daff8 100644
> --- a/include/hw/arm/allwinner-a10.h
> +++ b/include/hw/arm/allwinner-a10.h
> @@ -8,6 +8,8 @@
>  #include "hw/intc/allwinner-a10-pic.h"
>  #include "hw/net/allwinner_emac.h"
>  #include "hw/misc/allwinner-a10-ccm.h"
> +#include "hw/ide/pci.h"
> +#include "hw/ide/ahci.h"
>  
>  #include "sysemu/sysemu.h"
>  #include "exec/address-spaces.h"
> @@ -18,6 +20,7 @@
>  #define AW_A10_PIT_REG_BASE 0x01c20c00
>  #define AW_A10_UART0_REG_BASE   0x01c28000
>  #define AW_A10_EMAC_BASE0x01c0b000
> +#define AW_A10_SATA_BASE0x01c18000
>  
>  #define AW_A10_SDRAM_BASE   0x4000
>  
> @@ -35,6 +38,8 @@ typedef struct AwA10State {
>  AwA10PICState intc;
>  AwEmacState emac;
>  AwA10CCMState ccm;
> +
> +AllwinnerAHCIState sata;
>  } AwA10State;
>  
>  #define ALLWINNER_H_
> 

Does this series have a pre-requisite patchset for this to apply cleanly?

--js



Re: [Qemu-devel] [PATCH v3] arm_mptimer: Convert to use ptimer

2015-10-12 Thread Dmitry Osipenko
I referred to 
https://lists.nongnu.org/archive/html/qemu-devel/2014-09/msg00279.html in V3, 
but probably it was a different issue. Anyway, I tested VExpress SMP with 4.3 
linux kernel and it doesn't work without V3 fix and with old TimerBlock variant.


--
Dmitry



Re: [Qemu-devel] [PATCH] target-i386: fix pcmpxstrx equal-ordered (strstr) mode

2015-10-12 Thread Richard Henderson

On 10/12/2015 08:50 PM, Paolo Bonzini wrote:

In this mode, referring an invalid element of the source forces the
result to false (table 4-7, last column) but referring an invalid
element of the destination forces the result to true, so the outer
loop should still be run even if some elements of the destination
will be invalid.  They will be culled in the inner loop, which
correctly bounds "i" to validd.

This fix tst_strstr in glibc 2.17.

Reported-by: Florian Weimer 
Cc: Richard Henderson 
Cc: Eduardo Habkost 
Signed-off-by: Paolo Bonzini 
---
  target-i386/ops_sse.h | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h
index 7aa693a..268f3e1 100644
--- a/target-i386/ops_sse.h
+++ b/target-i386/ops_sse.h
@@ -2037,7 +2037,7 @@ static inline unsigned pcmpxstrx(CPUX86State *env, Reg 
*d, Reg *s,
  }
  break;
  case 3:
-for (j = valids - validd; j >= 0; j--) {
+for (j = valids; j >= 0; j--) {
  res <<= 1;
  v = 1;
  for (i = MIN(upper - j, validd); i >= 0; i--) {


I don't see how the bounding is properly done.  In particular,


v &= (pcmp_val(s, ctrl, i + j) == pcmp_val(d, ctrl, i));


We're bounding j by valids, but accessing i+j?

I think this would be a lot simpler if we simply followed the pseudocode in 
table 4-3, doing overrideIfDataInvalid after comparison.



r~



[Qemu-devel] [PATCH v3] arm_mptimer: Convert to use ptimer

2015-10-12 Thread Dmitry Osipenko
Current ARM MPTimer implementation uses QEMUTimer for the actual timer,
this implementation isn't complete and mostly tries to duplicate of what
generic ptimer is already doing fine.

Conversion to ptimer brings the following benefits and fixes:
- Simple timer pausing implementation
- Fixes counter value preservation after stopping the timer
- Code simplification and reduction
- Fixes starting the timer with load = 0

Bump VMSD to version 3, since VMState is changed and is not compatible
with the previuos implementation.

Signed-off-by: Dmitry Osipenko 
---

Changelog:
V2: Fixed changing periodic timer conter value "on the fly". I added a
test to the gist to cover that issue.
V3: Fixed starting the timer with load = 0 and counter != 0, added tests
to the gist for this issue.

Turned out, this is a long-standing issue with linux kernel boot on
SMP QEMU machine. With this fix it is booting and working fine.
https://lists.nongnu.org/archive/html/qemu-devel/2014-09/msg00279.html

Changed vmstate version for all VMSD's, since loadvm doesn't check
version of nested VMSD.

Tests: https://gist.github.com/digetx/dbd46109503b1a91941a

 hw/timer/arm_mptimer.c | 113 -
 include/hw/timer/arm_mptimer.h |   4 +-
 2 files changed, 56 insertions(+), 61 deletions(-)

diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c
index 3e59c2a..f708895 100644
--- a/hw/timer/arm_mptimer.c
+++ b/hw/timer/arm_mptimer.c
@@ -19,8 +19,9 @@
  * with this program; if not, see .
  */
 
+#include "hw/ptimer.h"
 #include "hw/timer/arm_mptimer.h"
-#include "qemu/timer.h"
+#include "qemu/main-loop.h"
 #include "qom/cpu.h"
 
 /* This device implements the per-cpu private timer and watchdog block
@@ -47,28 +48,10 @@ static inline uint32_t timerblock_scale(TimerBlock *tb)
 return (((tb->control >> 8) & 0xff) + 1) * 10;
 }
 
-static void timerblock_reload(TimerBlock *tb, int restart)
-{
-if (tb->count == 0) {
-return;
-}
-if (restart) {
-tb->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-}
-tb->tick += (int64_t)tb->count * timerblock_scale(tb);
-timer_mod(tb->timer, tb->tick);
-}
-
 static void timerblock_tick(void *opaque)
 {
 TimerBlock *tb = (TimerBlock *)opaque;
 tb->status = 1;
-if (tb->control & 2) {
-tb->count = tb->load;
-timerblock_reload(tb, 0);
-} else {
-tb->count = 0;
-}
 timerblock_update_irq(tb);
 }
 
@@ -76,21 +59,11 @@ static uint64_t timerblock_read(void *opaque, hwaddr addr,
 unsigned size)
 {
 TimerBlock *tb = (TimerBlock *)opaque;
-int64_t val;
 switch (addr) {
 case 0: /* Load */
 return tb->load;
 case 4: /* Counter.  */
-if (((tb->control & 1) == 0) || (tb->count == 0)) {
-return 0;
-}
-/* Slow and ugly, but hopefully won't happen too often.  */
-val = tb->tick - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-val /= timerblock_scale(tb);
-if (val < 0) {
-val = 0;
-}
-return val;
+return ptimer_get_count(tb->timer);
 case 8: /* Control.  */
 return tb->control;
 case 12: /* Interrupt status.  */
@@ -108,33 +81,59 @@ static void timerblock_write(void *opaque, hwaddr addr,
 switch (addr) {
 case 0: /* Load */
 tb->load = value;
-/* Fall through.  */
+/* Setting load to 0 for the running timer stops it without
+ * triggering the interrupt.  */
+if (value == 0) {
+ptimer_stop(tb->timer);
+}
+ptimer_set_limit(tb->timer, value, 0);
+ptimer_set_count(tb->timer, value);
+if ((tb->control & 1) && (value != 0)) {
+ptimer_run(tb->timer, !(tb->control & 2));
+}
+break;
 case 4: /* Counter.  */
-if ((tb->control & 1) && tb->count) {
-/* Cancel the previous timer.  */
-timer_del(tb->timer);
+/* Setting counter to 0 for the timer running in one-shot mode
+ * stops it without triggering the interrupt.  */
+if (!(tb->control & 2) && (value == 0)) {
+ptimer_stop(tb->timer);
+}
+/* While in the periodic mode, the running timer should restart
+ * counting without triggering the interrupt. Do it by setting
+ * the counter to the load value.  */
+if (((tb->control & 3) == 3) && (value == 0)) {
+ptimer_set_count(tb->timer, tb->load);
+break;
 }
-tb->count = value;
-if (tb->control & 1) {
-timerblock_reload(tb, 1);
+ptimer_set_count(tb->timer, value);
+/* Run the timer only if it is enabled and if mode is one-shot
+ * and counter != 0.  */
+if (((tb->control & 1) == 1) && (value != 0)) {
+ptim

[Qemu-devel] [PATCH 1/3] tcg/ppc: Adjust exit_tb for change in prologue placement

2015-10-12 Thread Richard Henderson
Changing the prologue to the beginning of the code_gen_buffer
changes the direction of the "return" branch.  Need to change
the logic to match.

Signed-off-by: Richard Henderson 
---
 tcg/ppc/tcg-target.c | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index 92ef719..fd7a3e0 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -1855,12 +1855,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 
const TCGArg *args,
 if (USE_REG_RA) {
 ptrdiff_t disp = tcg_pcrel_diff(s, tb_ret_addr);
 
-/* If we can use a direct branch, otherwise use the value in RA.
-   Note that the direct branch is always forward.  If it's in
-   range now, it'll still be in range after the movi.  Don't
-   bother about the 20 bytes where the test here fails but it
-   would succeed below.  */
-if (!in_range_b(disp)) {
+/* Use a direct branch if we can, otherwise use the value in RA.
+   Note that the direct branch is always backward, thus we need
+   to account for the possibility of 5 insns from the movi.  */
+if (!in_range_b(disp - 20)) {
 tcg_out32(s, MTSPR | RS(TCG_REG_RA) | CTR);
 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R3, args[0]);
 tcg_out32(s, BCCTR | BO_ALWAYS);
-- 
2.4.3




[Qemu-devel] [PATCH 0/3] powerpc tcg backend improvements

2015-10-12 Thread Richard Henderson
I happened to notice the ppc backend had a dependency on the placement
of the prologue, which has just changed.  There is a 32 byte window at
code_gen_buffer + 16MB where we might do the wrong thing.

The second patch reduces the code size reserved for performing goto_tb
from 7 insns to 4.  We probably haven't emitted all 7 insns for quite
some time, since the TCG_REG_RA patch went in.  But in the process,
allow for the atomic update of the insns, something that I could see
being required eventually.

The third patch is a guess.  But it matches the preferences in gcc,
giving out-of-order processors a tad more freedom by avoiding cr0
when possible.

Anyway, I've been running an alpha guest on a ppc64le host with these
patches for a week now.


r~


Richard Henderson (3):
  tcg/ppc: Adjust exit_tb for change in prologue placement
  tcg/ppc: Revise goto_tb implementation
  tcg/ppc: Prefer mask over andi.

 tcg/ppc/tcg-target.c | 79 ++--
 translate-all.c  |  2 ++
 2 files changed, 54 insertions(+), 27 deletions(-)

-- 
2.4.3




[Qemu-devel] [PATCH 3/3] tcg/ppc: Prefer mask over andi.

2015-10-12 Thread Richard Henderson
Prefer the instruction that isn't required to modify cr0.

Signed-off-by: Richard Henderson 
---
 tcg/ppc/tcg-target.c | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index cee13e0..2c72565 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -700,14 +700,14 @@ static void tcg_out_andi32(TCGContext *s, TCGReg dst, 
TCGReg src, uint32_t c)
 {
 int mb, me;
 
-if ((c & 0x) == c) {
+if (mask_operand(c, &mb, &me)) {
+tcg_out_rlw(s, RLWINM, dst, src, 0, mb, me);
+} else if ((c & 0x) == c) {
 tcg_out32(s, ANDI | SAI(src, dst, c));
 return;
 } else if ((c & 0x) == c) {
 tcg_out32(s, ANDIS | SAI(src, dst, c >> 16));
 return;
-} else if (mask_operand(c, &mb, &me)) {
-tcg_out_rlw(s, RLWINM, dst, src, 0, mb, me);
 } else {
 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R0, c);
 tcg_out32(s, AND | SAB(src, dst, TCG_REG_R0));
@@ -719,18 +719,18 @@ static void tcg_out_andi64(TCGContext *s, TCGReg dst, 
TCGReg src, uint64_t c)
 int mb, me;
 
 assert(TCG_TARGET_REG_BITS == 64);
-if ((c & 0x) == c) {
-tcg_out32(s, ANDI | SAI(src, dst, c));
-return;
-} else if ((c & 0x) == c) {
-tcg_out32(s, ANDIS | SAI(src, dst, c >> 16));
-return;
-} else if (mask64_operand(c, &mb, &me)) {
+if (mask64_operand(c, &mb, &me)) {
 if (mb == 0) {
 tcg_out_rld(s, RLDICR, dst, src, 0, me);
 } else {
 tcg_out_rld(s, RLDICL, dst, src, 0, mb);
 }
+} else if ((c & 0x) == c) {
+tcg_out32(s, ANDI | SAI(src, dst, c));
+return;
+} else if ((c & 0x) == c) {
+tcg_out32(s, ANDIS | SAI(src, dst, c >> 16));
+return;
 } else {
 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R0, c);
 tcg_out32(s, AND | SAB(src, dst, TCG_REG_R0));
-- 
2.4.3




[Qemu-devel] [PATCH 2/3] tcg/ppc: Revise goto_tb implementation

2015-10-12 Thread Richard Henderson
Restrict the size of code_gen_buffer to 2GB on ppc64, which
lets us assert that everything is reachable with addis+addi
from tb_ret_addr.  This lets us use a max of 4 insns for goto_tb
instead of 7.

Emit the indirect branch portion of goto_tb up front, which
means we only have to update two insns to update any link.
With a 64-bit store, we can update the link atomically, which
may be required in future.

Signed-off-by: Richard Henderson 
---
 tcg/ppc/tcg-target.c | 49 ++---
 translate-all.c  |  2 ++
 2 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index fd7a3e0..cee13e0 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -1239,11 +1239,36 @@ static void tcg_out_brcond2 (TCGContext *s, const 
TCGArg *args,
 
 void ppc_tb_set_jmp_target(uintptr_t jmp_addr, uintptr_t addr)
 {
-TCGContext s;
+tcg_insn_unit i1, i2;
+uint64_t pair;
+intptr_t diff = addr - jmp_addr;
 
-s.code_buf = s.code_ptr = (tcg_insn_unit *)jmp_addr;
-tcg_out_b(&s, 0, (tcg_insn_unit *)addr);
-flush_icache_range(jmp_addr, jmp_addr + tcg_current_code_size(&s));
+if (in_range_b(diff)) {
+i1 = B | (diff & 0x3fc);
+i2 = NOP;
+} else if (USE_REG_RA) {
+intptr_t lo, hi;
+diff = addr - (uintptr_t)tb_ret_addr;
+lo = (int16_t)diff;
+hi = (int32_t)(diff - lo);
+assert(diff == hi + lo);
+i1 = ADDIS | TAI(TCG_REG_TMP1, TCG_REG_RA, hi >> 16);
+i2 = ADDI | TAI(TCG_REG_TMP1, TCG_REG_TMP1, lo);
+} else {
+assert(TCG_TARGET_REG_BITS == 32 || addr == (int32_t)addr);
+i1 = ADDIS | TAI(TCG_REG_TMP1, 0, addr >> 16);
+i2 = ORI | SAI(TCG_REG_TMP1, TCG_REG_TMP1, addr);
+}
+#ifdef HOST_WORDS_BIGENDIAN
+pair = (uint64_t)i1 << 32 | i2;
+#else
+pair = (uint64_t)i2 << 32 | i1;
+#endif
+
+/* ??? __atomic_store_8, presuming there's some way to do that
+   for 32-bit, otherwise this is good enough for 64-bit.  */
+*(uint64_t *)jmp_addr = pair;
+flush_icache_range(jmp_addr, jmp_addr + 8);
 }
 
 static void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
@@ -1869,14 +1894,16 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 
const TCGArg *args,
 tcg_out_b(s, 0, tb_ret_addr);
 break;
 case INDEX_op_goto_tb:
-if (s->tb_jmp_offset) {
-/* Direct jump method.  */
-s->tb_jmp_offset[args[0]] = tcg_current_code_size(s);
-s->code_ptr += 7;
-} else {
-/* Indirect jump method.  */
-tcg_abort();
+tcg_debug_assert(s->tb_jmp_offset);
+/* Direct jump.  Ensure the next insns are 8-byte aligned. */
+if ((uintptr_t)s->code_ptr & 7) {
+tcg_out32(s, NOP);
 }
+s->tb_jmp_offset[args[0]] = tcg_current_code_size(s);
+/* To be replaced by either a branch+nop or a load into TMP1.  */
+s->code_ptr += 2;
+tcg_out32(s, MTSPR | RS(TCG_REG_TMP1) | CTR);
+tcg_out32(s, BCCTR | BO_ALWAYS);
 s->tb_next_offset[args[0]] = tcg_current_code_size(s);
 break;
 case INDEX_op_br:
diff --git a/translate-all.c b/translate-all.c
index 333eba4..20ce40e 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -468,6 +468,8 @@ static inline PageDesc *page_find(tb_page_addr_t index)
 # define MAX_CODE_GEN_BUFFER_SIZE  (2ul * 1024 * 1024 * 1024)
 #elif defined(__sparc__)
 # define MAX_CODE_GEN_BUFFER_SIZE  (2ul * 1024 * 1024 * 1024)
+#elif defined(__powerpc64__)
+# define MAX_CODE_GEN_BUFFER_SIZE  (2ul * 1024 * 1024 * 1024)
 #elif defined(__aarch64__)
 # define MAX_CODE_GEN_BUFFER_SIZE  (128ul * 1024 * 1024)
 #elif defined(__arm__)
-- 
2.4.3




Re: [Qemu-devel] [PATCH] hw/arm/virt: Allow zero address for PCI IO space

2015-10-12 Thread Peter Maydell
On 12 October 2015 at 21:55, Alexander Gordeev  wrote:
> Currently PCI IO address 0 is not allowed even though
> the IO space starts from 0. As result, PCI IO is not
> possible to use at all.

I don't see any reason for us not to allow 0 IO addresses,
but I'm not sure how your your conclusion follows. It
should be entirely possible to map PCI IO to some other
address than zero in the IO window, which is what I would
have expected the guest to do.

thanks
-- PMM



Re: [Qemu-devel] [RFC 0/4] AHCI patches + Allwinner SATA

2015-10-12 Thread Beniamino Galvani
On Sun, Oct 11, 2015 at 09:21:32AM -0700, Peter Crosthwaite wrote:
> Hi John and Beniamino,
> 
> This patch series adds bear-minimum Allwinner SATA support.

Hi Peter,

can you suggest a qemu command line to test this?

Beniamino



Re: [Qemu-devel] [PATCH v7 4/5] block: add a 'blockdev-snapshot' QMP command

2015-10-12 Thread Max Reitz
On 12.10.2015 11:16, Alberto Garcia wrote:
> One of the limitations of the 'blockdev-snapshot-sync' command is that
> it does not allow passing BlockdevOptions to the newly created
> snapshots, so they are always opened using the default values.
> 
> Extending the command to allow passing options is not a practical
> solution because there is overlap between those options and some of
> the existing parameters of the command.
> 
> This patch introduces a new 'blockdev-snapshot' command with a simpler
> interface: it just takes two references to existing block devices that
> will be used as the source and target for the snapshot.
> 
> Since the main difference between the two commands is that one of them
> creates and opens the target image, while the other uses an already
> opened one, the bulk of the implementation is shared.
> 
> Signed-off-by: Alberto Garcia 
> Cc: Eric Blake 
> Reviewed-by: Max Reitz 
> ---
>  blockdev.c   | 165 
> ---
>  qapi-schema.json |   2 +
>  qapi/block-core.json |  28 +
>  qmp-commands.hx  |  38 
>  4 files changed, 172 insertions(+), 61 deletions(-)
> 
> diff --git a/blockdev.c b/blockdev.c
> index 12741a0..b5470c9 100644
> --- a/blockdev.c
> +++ b/blockdev.c

[...]

> @@ -1521,58 +1533,48 @@ typedef struct ExternalSnapshotState {

[...]

>  }
>  
>  /* start processing */
> -state->old_bs = bdrv_lookup_bs(has_device ? device : NULL,
> -   has_node_name ? node_name : NULL,
> -   &local_err);
> -if (local_err) {
> -error_propagate(errp, local_err);
> -return;
> -}
> -
> -if (has_node_name && !has_snapshot_node_name) {
> -error_setg(errp, "New snapshot node name missing");
> -return;
> -}
> -
> -if (has_snapshot_node_name &&
> -bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) {
> -error_setg(errp, "New snapshot node name already in use");

There's a difference from v6 here...

> +state->old_bs = bdrv_lookup_bs(device, node_name, errp);
> +if (!state->old_bs) {
>  return;
>  }
>  
> @@ -1602,35 +1604,70 @@ static void 
> external_snapshot_prepare(BlkTransactionState *common,
>  return;
>  }
>  
> -flags = state->old_bs->open_flags;
> +if (action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC) {
> +BlockdevSnapshotSync *s = action->blockdev_snapshot_sync;
> +const char *format = s->has_format ? s->format : "qcow2";
> +enum NewImageMode mode;
> +const char *snapshot_node_name =
> +s->has_snapshot_node_name ? s->snapshot_node_name : NULL;
>  
> -/* create new image w/backing file */
> -if (mode != NEW_IMAGE_MODE_EXISTING) {
> -bdrv_img_create(new_image_file, format,
> -state->old_bs->filename,
> -state->old_bs->drv->format_name,
> -NULL, -1, flags, &local_err, false);
> -if (local_err) {
> -error_propagate(errp, local_err);
> +if (node_name && !snapshot_node_name) {
> +error_setg(errp, "New snapshot node name missing");
>  return;
>  }
> -}
>  
> -options = qdict_new();
> -if (has_snapshot_node_name) {
> -qdict_put(options, "node-name",
> -  qstring_from_str(snapshot_node_name));
> +if (snapshot_node_name &&
> +bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) {
> +error_setg(errp, "New snapshot node name already in use");

...and here, but how to resolve the conflict resulting from the newly
added patch 1 was obvious, so my R-b stands, of course.

Anyway, this is not why I'm replying, that's further down:

> +return;
> +}
> +
> +flags = state->old_bs->open_flags;
> +
> +/* create new image w/backing file */
> +mode = s->has_mode ? s->mode : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
> +if (mode != NEW_IMAGE_MODE_EXISTING) {
> +bdrv_img_create(new_image_file, format,
> +state->old_bs->filename,
> +state->old_bs->drv->format_name,
> +NULL, -1, flags, &local_err, false);
> +if (local_err) {
> +error_propagate(errp, local_err);
> +return;
> +}
> +}
> +
> +options = qdict_new();
> +if (s->has_snapshot_node_name) {
> +qdict_put(options, "node-name",
> +  qstring_from_str(snapshot_node_name));
> +}
> +qdict_put(options, "driver", qstring_from_str(format));
> +
> +flags |= BDRV_O_NO_BACKING;
>  }
> -qdict_put(options, "driver", qstring_from_str(format));
>  
> -/* TODO Inherit bs->options or only take explicit options with an
> - * extended QMP command? */

[Qemu-devel] [PATCH v6 39/39] iotests: Add test for change-related QMP commands

2015-10-12 Thread Max Reitz
Signed-off-by: Max Reitz 
Reviewed-by: Eric Blake 
---
 tests/qemu-iotests/118 | 638 +
 tests/qemu-iotests/118.out |   5 +
 tests/qemu-iotests/group   |   1 +
 3 files changed, 644 insertions(+)
 create mode 100755 tests/qemu-iotests/118
 create mode 100644 tests/qemu-iotests/118.out

diff --git a/tests/qemu-iotests/118 b/tests/qemu-iotests/118
new file mode 100755
index 000..915e439
--- /dev/null
+++ b/tests/qemu-iotests/118
@@ -0,0 +1,638 @@
+#!/usr/bin/env python
+#
+# Test case for the QMP 'change' command and all other associated
+# commands
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see .
+#
+
+import os
+import stat
+import time
+import iotests
+from iotests import qemu_img
+
+old_img = os.path.join(iotests.test_dir, 'test0.img')
+new_img = os.path.join(iotests.test_dir, 'test1.img')
+
+class ChangeBaseClass(iotests.QMPTestCase):
+has_opened = False
+has_closed = False
+
+def process_events(self):
+for event in self.vm.get_qmp_events(wait=False):
+if (event['event'] == 'DEVICE_TRAY_MOVED' and
+event['data']['device'] == 'drive0'):
+if event['data']['tray-open'] == False:
+self.has_closed = True
+else:
+self.has_opened = True
+
+def wait_for_open(self):
+timeout = time.clock() + 3
+while not self.has_opened and time.clock() < timeout:
+self.process_events()
+if not self.has_opened:
+self.fail('Timeout while waiting for the tray to open')
+
+def wait_for_close(self):
+timeout = time.clock() + 3
+while not self.has_closed and time.clock() < timeout:
+self.process_events()
+if not self.has_opened:
+self.fail('Timeout while waiting for the tray to close')
+
+class GeneralChangeTestsBaseClass(ChangeBaseClass):
+def test_change(self):
+result = self.vm.qmp('change', device='drive0', target=new_img,
+   arg=iotests.imgfmt)
+self.assert_qmp(result, 'return', {})
+
+self.wait_for_open()
+self.wait_for_close()
+
+result = self.vm.qmp('query-block')
+self.assert_qmp(result, 'return[0]/tray_open', False)
+self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+def test_blockdev_change_medium(self):
+result = self.vm.qmp('blockdev-change-medium', device='drive0',
+   filename=new_img,
+   format=iotests.imgfmt)
+self.assert_qmp(result, 'return', {})
+
+self.wait_for_open()
+self.wait_for_close()
+
+result = self.vm.qmp('query-block')
+self.assert_qmp(result, 'return[0]/tray_open', False)
+self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+def test_eject(self):
+result = self.vm.qmp('eject', device='drive0', force=True)
+self.assert_qmp(result, 'return', {})
+
+self.wait_for_open()
+
+result = self.vm.qmp('query-block')
+self.assert_qmp(result, 'return[0]/tray_open', True)
+self.assert_qmp_absent(result, 'return[0]/inserted')
+
+def test_tray_eject_change(self):
+result = self.vm.qmp('eject', device='drive0', force=True)
+self.assert_qmp(result, 'return', {})
+
+self.wait_for_open()
+
+result = self.vm.qmp('query-block')
+self.assert_qmp(result, 'return[0]/tray_open', True)
+self.assert_qmp_absent(result, 'return[0]/inserted')
+
+result = self.vm.qmp('blockdev-change-medium', device='drive0',
+   filename=new_img,
+   format=iotests.imgfmt)
+self.assert_qmp(result, 'return', {})
+
+self.wait_for_close()
+
+result = self.vm.qmp('query-block')
+self.assert_qmp(result, 'return[0]/tray_open', False)
+self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+def test_tray_open_close(self):
+result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+self.assert_qmp(result, 'return', {})
+
+self.wait_for_open()
+
+r

[Qemu-devel] [PATCH v6 38/39] hmp: Add read-only-mode option to change command

2015-10-12 Thread Max Reitz
Expose the new read-only-mode option of 'blockdev-change-medium' for the
'change' HMP command.

Signed-off-by: Max Reitz 
Reviewed-by: Eric Blake 
---
 hmp-commands.hx | 20 +---
 hmp.c   | 22 +-
 2 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 3a4ae39..814ea86 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -194,8 +194,8 @@ ETEXI
 
 {
 .name   = "change",
-.args_type  = "device:B,target:F,arg:s?",
-.params = "device filename [format]",
+.args_type  = "device:B,target:F,arg:s?,read-only-mode:s?",
+.params = "device filename [format [read-only-mode]]",
 .help   = "change a removable medium, optional format",
 .mhandler.cmd = hmp_change,
 },
@@ -206,7 +206,7 @@ STEXI
 Change the configuration of a device.
 
 @table @option
-@item change @var{diskdevice} @var{filename} [@var{format}]
+@item change @var{diskdevice} @var{filename} [@var{format} 
[@var{read-only-mode}]]
 Change the medium for a removable disk device to point to @var{filename}. eg
 
 @example
@@ -215,6 +215,20 @@ Change the medium for a removable disk device to point to 
@var{filename}. eg
 
 @var{format} is optional.
 
+@var{read-only-mode} may be used to change the read-only status of the device.
+It accepts the following values:
+
+@table @var
+@item retain
+Retains the current status; this is the default.
+
+@item read-only
+Makes the device read-only.
+
+@item read-write
+Makes the device writable.
+@end table
+
 @item change vnc @var{display},@var{options}
 Change the configuration of the VNC server. The valid syntax for @var{display}
 and @var{options} are described at @ref{sec_invocation}. eg
diff --git a/hmp.c b/hmp.c
index 9e6b7e5..28caa7d 100644
--- a/hmp.c
+++ b/hmp.c
@@ -27,6 +27,7 @@
 #include "qapi/opts-visitor.h"
 #include "qapi/qmp/qerror.h"
 #include "qapi/string-output-visitor.h"
+#include "qapi/util.h"
 #include "qapi-visit.h"
 #include "ui/console.h"
 #include "block/qapi.h"
@@ -1336,9 +1337,16 @@ void hmp_change(Monitor *mon, const QDict *qdict)
 const char *device = qdict_get_str(qdict, "device");
 const char *target = qdict_get_str(qdict, "target");
 const char *arg = qdict_get_try_str(qdict, "arg");
+const char *read_only = qdict_get_try_str(qdict, "read-only-mode");
+BlockdevChangeReadOnlyMode read_only_mode = 0;
 Error *err = NULL;
 
 if (strcmp(device, "vnc") == 0) {
+if (read_only) {
+monitor_printf(mon,
+   "Parameter 'read-only-mode' is invalid for VNC");
+return;
+}
 if (strcmp(target, "passwd") == 0 ||
 strcmp(target, "password") == 0) {
 if (!arg) {
@@ -1348,7 +1356,19 @@ void hmp_change(Monitor *mon, const QDict *qdict)
 }
 qmp_change("vnc", target, !!arg, arg, &err);
 } else {
-qmp_blockdev_change_medium(device, target, !!arg, arg, false, 0, &err);
+if (read_only) {
+read_only_mode =
+qapi_enum_parse(BlockdevChangeReadOnlyMode_lookup,
+read_only, BLOCKDEV_CHANGE_READ_ONLY_MODE_MAX,
+BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, &err);
+if (err) {
+hmp_handle_error(mon, &err);
+return;
+}
+}
+
+qmp_blockdev_change_medium(device, target, !!arg, arg,
+   !!read_only, read_only_mode, &err);
 if (err &&
 error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
 error_free(err);
-- 
2.6.1




[Qemu-devel] [PATCH v6 35/39] qmp: Introduce blockdev-change-medium

2015-10-12 Thread Max Reitz
Introduce a new QMP command 'blockdev-change-medium' which is intended
to replace the 'change' command for block devices. The existing function
qmp_change_blockdev() is accordingly renamed to
qmp_blockdev_change_medium().

Signed-off-by: Max Reitz 
---
 blockdev.c|  7 ---
 include/sysemu/blockdev.h |  2 --
 qapi-schema.json  |  6 --
 qapi/block-core.json  | 23 +++
 qmp-commands.hx   | 31 +++
 qmp.c |  2 +-
 6 files changed, 63 insertions(+), 8 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index bcfc29d..4ca8a8d 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2108,8 +2108,9 @@ void qmp_blockdev_insert_medium(const char *device, const 
char *node_name,
 qmp_blockdev_insert_anon_medium(device, bs, errp);
 }
 
-void qmp_change_blockdev(const char *device, const char *filename,
- const char *format, Error **errp)
+void qmp_blockdev_change_medium(const char *device, const char *filename,
+bool has_format, const char *format,
+Error **errp)
 {
 BlockBackend *blk;
 BlockBackendRootState *blk_rs;
@@ -2133,7 +2134,7 @@ void qmp_change_blockdev(const char *device, const char 
*filename,
 bdrv_flags = blk_rs->read_only ? 0 : BDRV_O_RDWR;
 bdrv_flags |= blk_rs->open_flags & ~BDRV_O_RDWR;
 
-if (format) {
+if (has_format) {
 options = qdict_new();
 qdict_put(options, "driver", qstring_from_str(format));
 }
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
index a00be94..b06a060 100644
--- a/include/sysemu/blockdev.h
+++ b/include/sysemu/blockdev.h
@@ -63,8 +63,6 @@ DriveInfo *drive_new(QemuOpts *arg, BlockInterfaceType 
block_default_type);
 
 /* device-hotplug */
 
-void qmp_change_blockdev(const char *device, const char *filename,
- const char *format, Error **errp);
 void hmp_commit(Monitor *mon, const QDict *qdict);
 void hmp_drive_del(Monitor *mon, const QDict *qdict);
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index a386605..a9eda90 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1842,8 +1842,10 @@
 #  device's password.  The behavior of reads and writes to the block
 #  device between when these calls are executed is undefined.
 #
-# Notes:  It is strongly recommended that this interface is not used especially
-# for changing block devices.
+# Notes:  This interface is deprecated, and it is strongly recommended that you
+# avoid using it.  For changing block devices, use
+# blockdev-change-medium; for changing VNC parameters, use
+# change-vnc-password.
 #
 # Since: 0.14.0
 ##
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 81a1f19..b8cc18a 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1949,6 +1949,29 @@
 
 
 ##
+# @blockdev-change-medium:
+#
+# Changes the medium inserted into a block device by ejecting the current 
medium
+# and loading a new image file which is inserted as the new medium (this 
command
+# combines blockdev-open-tray, blockdev-remove-medium, blockdev-insert-medium
+# and blockdev-close-tray).
+#
+# @device:  block device name
+#
+# @filename:filename of the new image to be loaded
+#
+# @format:  #optional, format to open the new image with (defaults to
+#   the probed format)
+#
+# Since: 2.5
+##
+{ 'command': 'blockdev-change-medium',
+  'data': { 'device': 'str',
+'filename': 'str',
+'*format': 'str' } }
+
+
+##
 # @BlockErrorAction
 #
 # An enumeration of action that has been taken when a DISK I/O occurs
diff --git a/qmp-commands.hx b/qmp-commands.hx
index a9223ef..7a143a3 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -4139,6 +4139,37 @@ Example:
 EQMP
 
 {
+.name   = "blockdev-change-medium",
+.args_type  = "device:B,filename:F,format:s?",
+.mhandler.cmd_new = qmp_marshal_blockdev_change_medium,
+},
+
+SQMP
+blockdev-change-medium
+--
+
+Changes the medium inserted into a block device by ejecting the current medium
+and loading a new image file which is inserted as the new medium.
+
+Arguments:
+
+- "device": device name (json-string)
+- "filename": filename of the new image (json-string)
+- "format": format of the new image (json-string, optional)
+
+Examples:
+
+1. Change a removable medium
+
+-> { "execute": "blockdev-change-medium",
+ "arguments": { "device": "ide1-cd0",
+"filename": "/srv/images/Fedora-12-x86_64-DVD.iso",
+"format": "raw" } }
+<- { "return": {} }
+
+EQMP
+
+{
 .name   = "query-memdev",
 .args_type  = "",
 .mhandler.cmd_new = qmp_marshal_query_memdev,
diff --git a/qmp.c b/qmp.c
index ff54e5a..4e44f98 100644
--- a/qmp.c
+++ b/qmp.c
@@ -414,7 +414,7 @@ void qm

[Qemu-devel] [PATCH v6 34/39] block: Inquire tray state before tray-moved events

2015-10-12 Thread Max Reitz
blk_dev_change_media_cb() is called for all potential tray movements;
however, it is possible to request closing the tray but nothing actually
happening (on a floppy disk drive without a medium).

Thus, the actual tray status should be inquired before sending a
tray-moved event (and an event should be sent whenever the status
changed).

Checking @load is now superfluous; it was necessary because it was
possible to change a medium without having explicitly opened the tray
and closed it again (or it might have been possible, at least). This is
no longer possible, though.

Signed-off-by: Max Reitz 
Reviewed-by: Eric Blake 
---
 block/block-backend.c | 17 +++--
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index eb7409c..10e4d71 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -429,18 +429,15 @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps 
*ops,
 void blk_dev_change_media_cb(BlockBackend *blk, bool load)
 {
 if (blk->dev_ops && blk->dev_ops->change_media_cb) {
-bool tray_was_closed = !blk_dev_is_tray_open(blk);
+bool tray_was_open, tray_is_open;
 
+tray_was_open = blk_dev_is_tray_open(blk);
 blk->dev_ops->change_media_cb(blk->dev_opaque, load);
-if (tray_was_closed) {
-/* tray open */
-qapi_event_send_device_tray_moved(blk_name(blk),
-  true, &error_abort);
-}
-if (load) {
-/* tray close */
-qapi_event_send_device_tray_moved(blk_name(blk),
-  false, &error_abort);
+tray_is_open = blk_dev_is_tray_open(blk);
+
+if (tray_was_open != tray_is_open) {
+qapi_event_send_device_tray_moved(blk_name(blk), tray_is_open,
+  &error_abort);
 }
 }
 }
-- 
2.6.1




[Qemu-devel] [PATCH v6 30/39] blockdev: Add blockdev-remove-medium

2015-10-12 Thread Max Reitz
Signed-off-by: Max Reitz 
---
 blockdev.c   | 30 ++
 qapi/block-core.json | 15 +++
 qmp-commands.hx  | 45 +
 3 files changed, 90 insertions(+)

diff --git a/blockdev.c b/blockdev.c
index a4ce1df..6d0a5eb 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2131,6 +2131,36 @@ void qmp_blockdev_close_tray(const char *device, Error 
**errp)
 blk_dev_change_media_cb(blk, true);
 }
 
+void qmp_blockdev_remove_medium(const char *device, Error **errp)
+{
+BlockBackend *blk;
+bool has_device;
+
+blk = blk_by_name(device);
+if (!blk) {
+error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+  "Device '%s' not found", device);
+return;
+}
+
+/* For BBs without a device, we can exchange the BDS tree at will */
+has_device = blk_get_attached_dev(blk);
+
+if (has_device && !blk_dev_has_removable_media(blk)) {
+error_setg(errp, "Device '%s' is not removable", device);
+return;
+}
+
+if (has_device && !blk_dev_is_tray_open(blk)) {
+error_setg(errp, "Tray of device '%s' is not open", device);
+return;
+}
+
+if (blk_bs(blk)) {
+blk_remove_bs(blk);
+}
+}
+
 /* throttling disk I/O limits */
 void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
int64_t bps_wr,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 1a51829..8edf5d9 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1915,6 +1915,21 @@
 { 'command': 'blockdev-close-tray',
   'data': { 'device': 'str' } }
 
+##
+# @blockdev-remove-medium:
+#
+# Removes a medium (a block driver state tree) from a block device. That block
+# device's tray must currently be open.
+#
+# If the tray is open and there is no medium inserted, this will be a no-op.
+#
+# @device: block device name
+#
+# Since: 2.5
+##
+{ 'command': 'blockdev-remove-medium',
+  'data': { 'device': 'str' } }
+
 
 ##
 # @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index fae2d33..2d89e26 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3995,6 +3995,51 @@ Example:
 EQMP
 
 {
+.name   = "blockdev-remove-medium",
+.args_type  = "device:s",
+.mhandler.cmd_new = qmp_marshal_blockdev_remove_medium,
+},
+
+SQMP
+blockdev-remove-medium
+--
+
+Removes a medium (a block driver state tree) from a block device. That block
+device's tray must currently be open.
+
+If the tray is open and there is no medium inserted, this will be a no-op.
+
+Arguments:
+
+- "device": block device name (json-string)
+
+Example:
+
+-> { "execute": "blockdev-remove-medium",
+ "arguments": { "device": "ide1-cd0" } }
+
+<- { "error": { "class": "GenericError",
+"desc": "Tray of device 'ide1-cd0' is not open" } }
+
+-> { "execute": "blockdev-open-tray",
+ "arguments": { "device": "ide1-cd0" } }
+
+<- { "timestamp": { "seconds": 1418751627,
+"microseconds": 549958 },
+ "event": "DEVICE_TRAY_MOVED",
+ "data": { "device": "ide1-cd0",
+   "tray-open": true } }
+
+<- { "return": {} }
+
+-> { "execute": "blockdev-remove-medium",
+ "arguments": { "device": "ide1-cd0" } }
+
+<- { "return": {} }
+
+EQMP
+
+{
 .name   = "query-named-block-nodes",
 .args_type  = "",
 .mhandler.cmd_new = qmp_marshal_query_named_block_nodes,
-- 
2.6.1




[Qemu-devel] [PATCH] Limit memory r/w length to buffer size

2015-10-12 Thread P J P

   Hello,

An OOB r/w access issue was reported by Mr Gerben Lubbe(CC'd here).

The GDB(1) stub protocol supports commands 'm/M' to read & write 'len' bytes 
from/to the stub memory area. In that, the 'len' parameter value supplied by 
the host gdb(1) is not validated against the local buffer size. Which in turn 
could lead to OOB r/w memory access.


Below is a proposed patch to fix this issue.

===

From 88edb457a66f8ff96209a1603914171eade0658b Mon Sep 17 00:00:00 2001

From: Prasad J Pandit 
Date: Mon, 12 Oct 2015 22:56:41 +0530
Subject: Limit memory r/w length to buffer size

GDB(1) stub communication protocol supports commands m/M to read
and write 'len' bytes from/to the stub memory area.

   m addr,len: read 'len' bytes from address 'addr'
   M addr,len: : write 'len' bytes of 'data' to 'addr'

Qemu stub uses automatic buffers of size 'MAX_PACKET_LENGTH=4096'
to process these commands. Limit 'len' parameter value supplied
by the host gdb(1) to the maximum buffer size to avoid any OOB
buffer access.

Reported-by: Gerben van der Lubbe 
Signed-off-by: Prasad J Pandit 
---
 gdbstub.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/gdbstub.c b/gdbstub.c
index ffe7e6e..39da736 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -956,6 +956,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 if (*p == ',')
 p++;
 len = strtoull(p, NULL, 16);
+len = len > MAX_PACKET_LENGTH ? MAX_PACKET_LENGTH : len;
 if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, false) != 0) {
 put_packet (s, "E14");
 } else {
@@ -968,6 +969,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 if (*p == ',')
 p++;
 len = strtoull(p, (char **)&p, 16);
+len = len > MAX_PACKET_LENGTH ? MAX_PACKET_LENGTH : len;
 if (*p == ':')
 p++;
 hextomem(mem_buf, p, len);
--
2.4.3
===


Thank you.
--
Prasad J Pandit / Red Hat Product Security Team
47AF CE69 3A90 54AA 9045 1053 DD13 3D32 FE5B 041F



Re: [Qemu-devel] [PATCH v7 1/5] block: check for existing device IDs in external_snapshot_prepare()

2015-10-12 Thread Max Reitz
On 12.10.2015 11:16, Alberto Garcia wrote:
> The 'snapshot-node-name' parameter of blockdev-snapshot-sync allows
> setting the node name of the image that is going to be created.
> 
> Before creating the image, external_snapshot_prepare() checks that the
> name is not already being used. The check is however incomplete since
> it only considers existing node names, but node names must not clash
> with device IDs either because they share the same namespace.
> 
> If the user attempts to create a snapshot using the name of an
> existing device for the 'snapshot-node-name' parameter the operation
> will eventually fail, but only after the new image has been created.
> 
> This patch replaces bdrv_find_node() with bdrv_lookup_bs() to extend
> the check to existing device IDs, and thus detect possible name
> clashes before the new image is created.
> 
> Signed-off-by: Alberto Garcia 
> ---
>  blockdev.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)

Reviewed-by: Max Reitz 



signature.asc
Description: OpenPGP digital signature


[Qemu-devel] [PATCH v6 29/39] blockdev: Add blockdev-close-tray

2015-10-12 Thread Max Reitz
Signed-off-by: Max Reitz 
---
 blockdev.c   | 23 +++
 qapi/block-core.json | 16 
 qmp-commands.hx  | 35 +++
 3 files changed, 74 insertions(+)

diff --git a/blockdev.c b/blockdev.c
index b90b1d6..a4ce1df 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2108,6 +2108,29 @@ out:
 }
 }
 
+void qmp_blockdev_close_tray(const char *device, Error **errp)
+{
+BlockBackend *blk;
+
+blk = blk_by_name(device);
+if (!blk) {
+error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+  "Device '%s' not found", device);
+return;
+}
+
+if (!blk_dev_has_removable_media(blk)) {
+error_setg(errp, "Device '%s' is not removable", device);
+return;
+}
+
+if (!blk_dev_is_tray_open(blk)) {
+return;
+}
+
+blk_dev_change_media_cb(blk, true);
+}
+
 /* throttling disk I/O limits */
 void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
int64_t bps_wr,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index b9b4a24..1a51829 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1899,6 +1899,22 @@
   'data': { 'device': 'str',
 '*force': 'bool' } }
 
+##
+# @blockdev-close-tray:
+#
+# Closes a block device's tray. If there is a block driver state tree 
associated
+# with the block device (which is currently ejected), that tree will be loaded
+# as the medium.
+#
+# If the tray was already closed before, this will be a no-op.
+#
+# @device: block device name
+#
+# Since: 2.5
+##
+{ 'command': 'blockdev-close-tray',
+  'data': { 'device': 'str' } }
+
 
 ##
 # @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index f20681a..fae2d33 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3960,6 +3960,41 @@ Example:
 EQMP
 
 {
+.name   = "blockdev-close-tray",
+.args_type  = "device:s",
+.mhandler.cmd_new = qmp_marshal_blockdev_close_tray,
+},
+
+SQMP
+blockdev-close-tray
+---
+
+Closes a block device's tray. If there is a block driver state tree associated
+with the block device (which is currently ejected), that tree will be loaded as
+the medium.
+
+If the tray was already closed before, this will be a no-op.
+
+Arguments:
+
+- "device": block device name (json-string)
+
+Example:
+
+-> { "execute": "blockdev-close-tray",
+ "arguments": { "device": "ide1-cd0" } }
+
+<- { "timestamp": { "seconds": 1418751345,
+"microseconds": 272147 },
+ "event": "DEVICE_TRAY_MOVED",
+ "data": { "device": "ide1-cd0",
+   "tray-open": false } }
+
+<- { "return": {} }
+
+EQMP
+
+{
 .name   = "query-named-block-nodes",
 .args_type  = "",
 .mhandler.cmd_new = qmp_marshal_query_named_block_nodes,
-- 
2.6.1




[Qemu-devel] [PATCH v6 28/39] blockdev: Add blockdev-open-tray

2015-10-12 Thread Max Reitz
Signed-off-by: Max Reitz 
---
 blockdev.c   | 49 +
 qapi/block-core.json | 23 +++
 qmp-commands.hx  | 39 +++
 3 files changed, 111 insertions(+)

diff --git a/blockdev.c b/blockdev.c
index 69a6cb2..b90b1d6 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2059,6 +2059,55 @@ out:
 aio_context_release(aio_context);
 }
 
+void qmp_blockdev_open_tray(const char *device, bool has_force, bool force,
+Error **errp)
+{
+BlockBackend *blk;
+BlockDriverState *bs;
+AioContext *aio_context = NULL;
+
+if (!has_force) {
+force = false;
+}
+
+blk = blk_by_name(device);
+if (!blk) {
+error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+  "Device '%s' not found", device);
+return;
+}
+
+if (!blk_dev_has_removable_media(blk)) {
+error_setg(errp, "Device '%s' is not removable", device);
+return;
+}
+
+if (blk_dev_is_tray_open(blk)) {
+return;
+}
+
+bs = blk_bs(blk);
+if (bs) {
+aio_context = bdrv_get_aio_context(bs);
+aio_context_acquire(aio_context);
+
+if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
+goto out;
+}
+}
+
+if (blk_dev_is_medium_locked(blk)) {
+blk_dev_eject_request(blk, force);
+} else {
+blk_dev_change_media_cb(blk, false);
+}
+
+out:
+if (aio_context) {
+aio_context_release(aio_context);
+}
+}
+
 /* throttling disk I/O limits */
 void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
int64_t bps_wr,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 425fdab..b9b4a24 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1876,6 +1876,29 @@
 ##
 { 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
 
+##
+# @blockdev-open-tray:
+#
+# Opens a block device's tray. If there is a block driver state tree inserted 
as
+# a medium, it will become inaccessible to the guest (but it will remain
+# associated to the block device, so closing the tray will make it accessible
+# again).
+#
+# If the tray was already open before, this will be a no-op.
+#
+# @device: block device name
+#
+# @force:  #optional if false (the default), an eject request will be sent to
+#  the guest if it has locked the tray (and the tray will not be opened
+#  immediately); if true, the tray will be opened regardless of whether
+#  it is locked
+#
+# Since: 2.5
+##
+{ 'command': 'blockdev-open-tray',
+  'data': { 'device': 'str',
+'*force': 'bool' } }
+
 
 ##
 # @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 785ecf6..f20681a 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3921,6 +3921,45 @@ Example (2):
 EQMP
 
 {
+.name   = "blockdev-open-tray",
+.args_type  = "device:s,force:b?",
+.mhandler.cmd_new = qmp_marshal_blockdev_open_tray,
+},
+
+SQMP
+blockdev-open-tray
+--
+
+Opens a block device's tray. If there is a block driver state tree inserted as 
a
+medium, it will become inaccessible to the guest (but it will remain associated
+to the block device, so closing the tray will make it accessible again).
+
+If the tray was already open before, this will be a no-op.
+
+Arguments:
+
+- "device": block device name (json-string)
+- "force": if false (the default), an eject request will be sent to the guest 
if
+   it has locked the tray (and the tray will not be opened 
immediately);
+   if true, the tray will be opened regardless of whether it is locked
+   (json-bool, optional)
+
+Example:
+
+-> { "execute": "blockdev-open-tray",
+ "arguments": { "device": "ide1-cd0" } }
+
+<- { "timestamp": { "seconds": 1418751016,
+"microseconds": 716996 },
+ "event": "DEVICE_TRAY_MOVED",
+ "data": { "device": "ide1-cd0",
+   "tray-open": true } }
+
+<- { "return": {} }
+
+EQMP
+
+{
 .name   = "query-named-block-nodes",
 .args_type  = "",
 .mhandler.cmd_new = qmp_marshal_query_named_block_nodes,
-- 
2.6.1




[Qemu-devel] [PATCH v6 36/39] hmp: Use blockdev-change-medium for change command

2015-10-12 Thread Max Reitz
Use separate code paths for the two overloaded functions of the 'change'
HMP command, and invoke the 'blockdev-change-medium' QMP command if used
on a block device (by calling qmp_blockdev_change_medium()).

Signed-off-by: Max Reitz 
Reviewed-by: Eric Blake 
---
 hmp.c | 27 +++
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/hmp.c b/hmp.c
index 5048eee..b91821b 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1338,22 +1338,25 @@ void hmp_change(Monitor *mon, const QDict *qdict)
 const char *arg = qdict_get_try_str(qdict, "arg");
 Error *err = NULL;
 
-if (strcmp(device, "vnc") == 0 &&
-(strcmp(target, "passwd") == 0 ||
- strcmp(target, "password") == 0)) {
-if (!arg) {
-monitor_read_password(mon, hmp_change_read_arg, NULL);
+if (strcmp(device, "vnc") == 0) {
+if (strcmp(target, "passwd") == 0 ||
+strcmp(target, "password") == 0) {
+if (!arg) {
+monitor_read_password(mon, hmp_change_read_arg, NULL);
+return;
+}
+}
+qmp_change("vnc", target, !!arg, arg, &err);
+} else {
+qmp_blockdev_change_medium(device, target, !!arg, arg, &err);
+if (err &&
+error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
+error_free(err);
+monitor_read_block_device_key(mon, device, NULL, NULL);
 return;
 }
 }
 
-qmp_change(device, target, !!arg, arg, &err);
-if (err &&
-error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
-error_free(err);
-monitor_read_block_device_key(mon, device, NULL, NULL);
-return;
-}
 hmp_handle_error(mon, &err);
 }
 
-- 
2.6.1




[Qemu-devel] [PATCH v6 26/39] blockdev: Allow more options for BB-less BDS tree

2015-10-12 Thread Max Reitz
Most of the options which blockdev_init() parses for both the
BlockBackend and the root BDS are valid for just the root BDS as well
(e.g. read-only). This patch allows specifying these options even if not
creating a BlockBackend.

Signed-off-by: Max Reitz 
---
 blockdev.c | 160 ++---
 1 file changed, 154 insertions(+), 6 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index e0f04dd..69a6cb2 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -612,6 +612,65 @@ err_no_opts:
 return NULL;
 }
 
+static QemuOptsList qemu_root_bds_opts;
+
+/* Takes the ownership of bs_opts */
+static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
+{
+BlockDriverState *bs;
+QemuOpts *opts;
+Error *local_error = NULL;
+ThrottleConfig cfg;
+BlockdevDetectZeroesOptions detect_zeroes;
+const char *throttling_group = NULL;
+int ret;
+int bdrv_flags = 0;
+
+opts = qemu_opts_create(&qemu_root_bds_opts, NULL, 1, errp);
+if (!opts) {
+goto fail;
+}
+
+qemu_opts_absorb_qdict(opts, bs_opts, &local_error);
+if (local_error) {
+error_propagate(errp, local_error);
+goto fail;
+}
+
+extract_common_blockdev_options(opts, &bdrv_flags, &cfg, &detect_zeroes,
+&throttling_group, &local_error);
+if (local_error) {
+error_propagate(errp, local_error);
+goto fail;
+}
+
+bs = NULL;
+ret = bdrv_open(&bs, NULL, NULL, bs_opts, bdrv_flags, errp);
+if (ret < 0) {
+goto fail_no_bs_opts;
+}
+
+bs->detect_zeroes = detect_zeroes;
+
+/* disk I/O throttling */
+if (throttle_enabled(&cfg)) {
+if (!throttling_group) {
+throttling_group = bdrv_get_node_name(bs);
+}
+bdrv_io_limits_enable(bs, throttling_group);
+bdrv_set_io_limits(bs, &cfg);
+}
+
+fail_no_bs_opts:
+qemu_opts_del(opts);
+return bs;
+
+fail:
+qemu_opts_del(opts);
+QDECREF(bs_opts);
+return NULL;
+}
+
 static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to,
 Error **errp)
 {
@@ -3170,18 +3229,14 @@ void qmp_blockdev_add(BlockdevOptions *options, Error 
**errp)
 
 bs = blk_bs(blk);
 } else {
-int ret;
-
 if (!qdict_get_try_str(qdict, "node-name")) {
 error_setg(errp, "'id' and/or 'node-name' need to be specified for 
"
"the root node");
 goto fail;
 }
 
-bs = NULL;
-ret = bdrv_open(&bs, NULL, NULL, qdict, BDRV_O_RDWR | BDRV_O_CACHE_WB,
-errp);
-if (ret < 0) {
+bs = bds_tree_init(qdict, errp);
+if (!bs) {
 goto fail;
 }
 }
@@ -3336,6 +3391,99 @@ QemuOptsList qemu_common_drive_opts = {
 },
 };
 
+static QemuOptsList qemu_root_bds_opts = {
+.name = "root-bds",
+.head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),
+.desc = {
+{
+.name = "discard",
+.type = QEMU_OPT_STRING,
+.help = "discard operation (ignore/off, unmap/on)",
+},{
+.name = "cache.writeback",
+.type = QEMU_OPT_BOOL,
+.help = "enables writeback mode for any caches",
+},{
+.name = "cache.direct",
+.type = QEMU_OPT_BOOL,
+.help = "enables use of O_DIRECT (bypass the host page cache)",
+},{
+.name = "cache.no-flush",
+.type = QEMU_OPT_BOOL,
+.help = "ignore any flush requests for the device",
+},{
+.name = "aio",
+.type = QEMU_OPT_STRING,
+.help = "host AIO implementation (threads, native)",
+},{
+.name = "read-only",
+.type = QEMU_OPT_BOOL,
+.help = "open drive file as read-only",
+},{
+.name = "throttling.iops-total",
+.type = QEMU_OPT_NUMBER,
+.help = "limit total I/O operations per second",
+},{
+.name = "throttling.iops-read",
+.type = QEMU_OPT_NUMBER,
+.help = "limit read operations per second",
+},{
+.name = "throttling.iops-write",
+.type = QEMU_OPT_NUMBER,
+.help = "limit write operations per second",
+},{
+.name = "throttling.bps-total",
+.type = QEMU_OPT_NUMBER,
+.help = "limit total bytes per second",
+},{
+.name = "throttling.bps-read",
+.type = QEMU_OPT_NUMBER,
+.help = "limit read bytes per second",
+},{
+.name = "throttling.bps-write",
+.type = QEMU_OPT_NUMBER,
+.help = "limit write bytes per second",
+},{
+.name = "throttling.iops-total-max",
+.type = QEMU_OPT_NUMBER,
+.help = "I/O operations burst",
+},{
+  

[Qemu-devel] [PATCH v6 32/39] blockdev: Implement eject with basic operations

2015-10-12 Thread Max Reitz
Implement 'eject' by calling blockdev-open-tray and
blockdev-remove-medium.

Signed-off-by: Max Reitz 
---
 blockdev.c | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 706e7e1..ff3b353 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1952,16 +1952,15 @@ out:
 
 void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
 {
-BlockBackend *blk;
+Error *local_err = NULL;
 
-blk = blk_by_name(device);
-if (!blk) {
-error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
-  "Device '%s' not found", device);
+qmp_blockdev_open_tray(device, has_force, force, &local_err);
+if (local_err) {
+error_propagate(errp, local_err);
 return;
 }
 
-eject_device(blk, force, errp);
+qmp_blockdev_remove_medium(device, errp);
 }
 
 void qmp_block_passwd(bool has_device, const char *device,
-- 
2.6.1




[Qemu-devel] [PATCH v6 16/39] block: Move I/O status and error actions into BB

2015-10-12 Thread Max Reitz
These options are only relevant for the user of a whole BDS tree (like a
guest device or a block job) and should thus be moved into the
BlockBackend.

Signed-off-by: Max Reitz 
---
 block.c| 125 -
 block/backup.c |  17 --
 block/block-backend.c  | 116 --
 block/commit.c |   3 +-
 block/mirror.c |  17 --
 block/qapi.c   |   4 +-
 block/stream.c |   3 +-
 blockdev.c |   6 +-
 blockjob.c |   5 +-
 include/block/block.h  |  11 
 include/block/block_int.h  |   6 --
 include/sysemu/block-backend.h |   7 +++
 qmp.c  |   6 +-
 13 files changed, 158 insertions(+), 168 deletions(-)

diff --git a/block.c b/block.c
index 3e13b7f..48f7067 100644
--- a/block.c
+++ b/block.c
@@ -257,7 +257,6 @@ BlockDriverState *bdrv_new(void)
 for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
 QLIST_INIT(&bs->op_blockers[i]);
 }
-bdrv_iostatus_disable(bs);
 notifier_list_init(&bs->close_notifiers);
 notifier_with_return_list_init(&bs->before_write_notifiers);
 qemu_co_queue_init(&bs->throttled_reqs[0]);
@@ -1995,14 +1994,6 @@ static void bdrv_move_feature_fields(BlockDriverState 
*bs_dest,
 
 bs_dest->enable_write_cache = bs_src->enable_write_cache;
 
-/* r/w error */
-bs_dest->on_read_error  = bs_src->on_read_error;
-bs_dest->on_write_error = bs_src->on_write_error;
-
-/* i/o status */
-bs_dest->iostatus_enabled   = bs_src->iostatus_enabled;
-bs_dest->iostatus   = bs_src->iostatus;
-
 /* dirty bitmap */
 bs_dest->dirty_bitmaps  = bs_src->dirty_bitmaps;
 }
@@ -2489,82 +2480,6 @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t 
*nb_sectors_ptr)
 *nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
 }
 
-void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error,
-   BlockdevOnError on_write_error)
-{
-bs->on_read_error = on_read_error;
-bs->on_write_error = on_write_error;
-}
-
-BlockdevOnError bdrv_get_on_error(BlockDriverState *bs, bool is_read)
-{
-return is_read ? bs->on_read_error : bs->on_write_error;
-}
-
-BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int 
error)
-{
-BlockdevOnError on_err = is_read ? bs->on_read_error : bs->on_write_error;
-
-switch (on_err) {
-case BLOCKDEV_ON_ERROR_ENOSPC:
-return (error == ENOSPC) ?
-   BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT;
-case BLOCKDEV_ON_ERROR_STOP:
-return BLOCK_ERROR_ACTION_STOP;
-case BLOCKDEV_ON_ERROR_REPORT:
-return BLOCK_ERROR_ACTION_REPORT;
-case BLOCKDEV_ON_ERROR_IGNORE:
-return BLOCK_ERROR_ACTION_IGNORE;
-default:
-abort();
-}
-}
-
-static void send_qmp_error_event(BlockDriverState *bs,
- BlockErrorAction action,
- bool is_read, int error)
-{
-IoOperationType optype;
-
-optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
-qapi_event_send_block_io_error(bdrv_get_device_name(bs), optype, action,
-   bdrv_iostatus_is_enabled(bs),
-   error == ENOSPC, strerror(error),
-   &error_abort);
-}
-
-/* This is done by device models because, while the block layer knows
- * about the error, it does not know whether an operation comes from
- * the device or the block layer (from a job, for example).
- */
-void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action,
-   bool is_read, int error)
-{
-assert(error >= 0);
-
-if (action == BLOCK_ERROR_ACTION_STOP) {
-/* First set the iostatus, so that "info block" returns an iostatus
- * that matches the events raised so far (an additional error iostatus
- * is fine, but not a lost one).
- */
-bdrv_iostatus_set_err(bs, error);
-
-/* Then raise the request to stop the VM and the event.
- * qemu_system_vmstop_request_prepare has two effects.  First,
- * it ensures that the STOP event always comes after the
- * BLOCK_IO_ERROR event.  Second, it ensures that even if management
- * can observe the STOP event and do a "cont" before the STOP
- * event is issued, the VM will not stop.  In this case, vm_start()
- * also ensures that the STOP/RESUME pair of events is emitted.
- */
-qemu_system_vmstop_request_prepare();
-send_qmp_error_event(bs, action, is_read, error);
-qemu_system_vmstop_request(RUN_STATE_IO_ERROR);
-} else {
-send_qmp_error_event(bs, action, is_read, error);
-}
-}
-
 int bdrv_is_read_only(BlockDriverState *bs)
 {
 return bs->read_only;
@@ -3592,

[Qemu-devel] [PATCH v6 37/39] blockdev: read-only-mode for blockdev-change-medium

2015-10-12 Thread Max Reitz
Add an option to qmp_blockdev_change_medium() which allows changing the
read-only status of the block device whose medium is changed.

Some drives do not have a inherently fixed read-only status; for
instance, floppy disks can be set read-only or writable independently of
the drive. Some users may find it useful to be able to therefore change
the read-only status of a block device when changing the medium.

Signed-off-by: Max Reitz 
Reviewed-by: Eric Blake 
---
 blockdev.c   | 25 -
 hmp.c|  2 +-
 qapi/block-core.json | 24 +++-
 qmp-commands.hx  | 24 +++-
 qmp.c|  3 ++-
 5 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 4ca8a8d..2360c1f 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2110,6 +2110,8 @@ void qmp_blockdev_insert_medium(const char *device, const 
char *node_name,
 
 void qmp_blockdev_change_medium(const char *device, const char *filename,
 bool has_format, const char *format,
+bool has_read_only,
+BlockdevChangeReadOnlyMode read_only,
 Error **errp)
 {
 BlockBackend *blk;
@@ -2131,7 +2133,28 @@ void qmp_blockdev_change_medium(const char *device, 
const char *filename,
 }
 
 blk_rs = blk_get_root_state(blk);
-bdrv_flags = blk_rs->read_only ? 0 : BDRV_O_RDWR;
+
+if (!has_read_only) {
+read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
+}
+
+switch (read_only) {
+case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
+bdrv_flags = blk_rs->read_only ? 0 : BDRV_O_RDWR;
+break;
+
+case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
+bdrv_flags = 0;
+break;
+
+case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
+bdrv_flags = BDRV_O_RDWR;
+break;
+
+default:
+abort();
+}
+
 bdrv_flags |= blk_rs->open_flags & ~BDRV_O_RDWR;
 
 if (has_format) {
diff --git a/hmp.c b/hmp.c
index b91821b..9e6b7e5 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1348,7 +1348,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
 }
 qmp_change("vnc", target, !!arg, arg, &err);
 } else {
-qmp_blockdev_change_medium(device, target, !!arg, arg, &err);
+qmp_blockdev_change_medium(device, target, !!arg, arg, false, 0, &err);
 if (err &&
 error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
 error_free(err);
diff --git a/qapi/block-core.json b/qapi/block-core.json
index b8cc18a..5f12af7 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1949,6 +1949,24 @@
 
 
 ##
+# @BlockdevChangeReadOnlyMode:
+#
+# Specifies the new read-only mode of a block device subject to the
+# @blockdev-change-medium command.
+#
+# @retain:  Retains the current read-only mode
+#
+# @read-only:   Makes the device read-only
+#
+# @read-write:  Makes the device writable
+#
+# Since: 2.3
+##
+{ 'enum': 'BlockdevChangeReadOnlyMode',
+  'data': ['retain', 'read-only', 'read-write'] }
+
+
+##
 # @blockdev-change-medium:
 #
 # Changes the medium inserted into a block device by ejecting the current 
medium
@@ -1963,12 +1981,16 @@
 # @format:  #optional, format to open the new image with (defaults to
 #   the probed format)
 #
+# @read-only-mode:  #optional, change the read-only mode of the device; 
defaults
+#   to 'retain'
+#
 # Since: 2.5
 ##
 { 'command': 'blockdev-change-medium',
   'data': { 'device': 'str',
 'filename': 'str',
-'*format': 'str' } }
+'*format': 'str',
+'*read-only-mode': 'BlockdevChangeReadOnlyMode' } }
 
 
 ##
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 7a143a3..4f03d11 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -4140,7 +4140,7 @@ EQMP
 
 {
 .name   = "blockdev-change-medium",
-.args_type  = "device:B,filename:F,format:s?",
+.args_type  = "device:B,filename:F,format:s?,read-only-mode:s?",
 .mhandler.cmd_new = qmp_marshal_blockdev_change_medium,
 },
 
@@ -4156,6 +4156,8 @@ Arguments:
 - "device": device name (json-string)
 - "filename": filename of the new image (json-string)
 - "format": format of the new image (json-string, optional)
+- "read-only-mode": new read-only mode (json-string, optional)
+  - Possible values: "retain" (default), "read-only", "read-write"
 
 Examples:
 
@@ -4167,6 +4169,26 @@ Examples:
 "format": "raw" } }
 <- { "return": {} }
 
+2. Load a read-only medium into a writable drive
+
+-> { "execute": "blockdev-change-medium",
+ "arguments": { "device": "isa-fd0",
+"filename": "/srv/images/ro.img",
+"format": "raw",
+"read-only-mode": "retain" } }
+
+<- { "error":
+ { "class": "GenericError",
+  

[Qemu-devel] [PATCH v6 24/39] blockdev: Do not create BDS for empty drive

2015-10-12 Thread Max Reitz
Do not use "rudimentary" BDSs for empty drives any longer (for
freshly created drives).

After a follow-up patch, empty drives will generally use a NULL BDS, not
only the freshly created drives.

Signed-off-by: Max Reitz 
---
 blockdev.c | 72 ++
 1 file changed, 44 insertions(+), 28 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 35efe84..845a1c1 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -514,16 +514,44 @@ static BlockBackend *blockdev_init(const char *file, 
QDict *bs_opts,
 goto early_err;
 }
 
+if (snapshot) {
+/* always use cache=unsafe with snapshot */
+bdrv_flags &= ~BDRV_O_CACHE_MASK;
+bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
+}
+
+if (copy_on_read) {
+bdrv_flags |= BDRV_O_COPY_ON_READ;
+}
+
+if (runstate_check(RUN_STATE_INMIGRATE)) {
+bdrv_flags |= BDRV_O_INCOMING;
+}
+
+bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
+
 /* init */
 if ((!file || !*file) && !has_driver_specific_opts) {
-blk = blk_new_with_bs(qemu_opts_id(opts), errp);
+BlockBackendRootState *blk_rs;
+
+blk = blk_new(qemu_opts_id(opts), errp);
 if (!blk) {
 goto early_err;
 }
 
-bs = blk_bs(blk);
-bs->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
-bs->read_only = ro;
+blk_rs = blk_get_root_state(blk);
+blk_rs->open_flags= bdrv_flags;
+blk_rs->read_only = ro;
+blk_rs->detect_zeroes = detect_zeroes;
+
+if (throttle_enabled(&cfg)) {
+if (!throttling_group) {
+throttling_group = blk_name(blk);
+}
+blk_rs->throttle_group = g_strdup(throttling_group);
+blk_rs->throttle_state = throttle_group_incref(throttling_group);
+blk_rs->throttle_state->cfg = cfg;
+}
 
 QDECREF(bs_opts);
 } else {
@@ -531,42 +559,30 @@ static BlockBackend *blockdev_init(const char *file, 
QDict *bs_opts,
 file = NULL;
 }
 
-if (snapshot) {
-/* always use cache=unsafe with snapshot */
-bdrv_flags &= ~BDRV_O_CACHE_MASK;
-bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
-}
-
-if (copy_on_read) {
-bdrv_flags |= BDRV_O_COPY_ON_READ;
-}
-
-bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
-
 blk = blk_new_open(qemu_opts_id(opts), file, NULL, bs_opts, bdrv_flags,
errp);
 if (!blk) {
 goto err_no_bs_opts;
 }
 bs = blk_bs(blk);
-}
 
-bs->detect_zeroes = detect_zeroes;
+bs->detect_zeroes = detect_zeroes;
 
-blk_set_on_error(blk, on_read_error, on_write_error);
+/* disk I/O throttling */
+if (throttle_enabled(&cfg)) {
+if (!throttling_group) {
+throttling_group = blk_name(blk);
+}
+bdrv_io_limits_enable(bs, throttling_group);
+bdrv_set_io_limits(bs, &cfg);
+}
 
-/* disk I/O throttling */
-if (throttle_enabled(&cfg)) {
-if (!throttling_group) {
-throttling_group = blk_name(blk);
+if (bdrv_key_required(bs)) {
+autostart = 0;
 }
-bdrv_io_limits_enable(bs, throttling_group);
-bdrv_set_io_limits(bs, &cfg);
 }
 
-if (bdrv_key_required(bs)) {
-autostart = 0;
-}
+blk_set_on_error(blk, on_read_error, on_write_error);
 
 err_no_bs_opts:
 qemu_opts_del(opts);
-- 
2.6.1




[Qemu-devel] [PATCH v6 33/39] blockdev: Implement change with basic operations

2015-10-12 Thread Max Reitz
Implement 'change' on block devices by calling blockdev-open-tray,
blockdev-remove-medium, blockdev-insert-medium (a variation of that
which does not need a node-name) and blockdev-close-tray.

Signed-off-by: Max Reitz 
---
 blockdev.c | 180 +
 1 file changed, 74 insertions(+), 106 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index ff3b353..bcfc29d 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1915,41 +1915,6 @@ exit:
 }
 }
 
-
-static void eject_device(BlockBackend *blk, int force, Error **errp)
-{
-BlockDriverState *bs = blk_bs(blk);
-AioContext *aio_context;
-
-aio_context = blk_get_aio_context(blk);
-aio_context_acquire(aio_context);
-
-if (bs && bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
-goto out;
-}
-if (!blk_dev_has_removable_media(blk)) {
-error_setg(errp, "Device '%s' is not removable",
-   bdrv_get_device_name(bs));
-goto out;
-}
-
-if (blk_dev_is_medium_locked(blk) && !blk_dev_is_tray_open(blk)) {
-blk_dev_eject_request(blk, force);
-if (!force) {
-error_setg(errp, "Device '%s' is locked",
-   bdrv_get_device_name(bs));
-goto out;
-}
-}
-
-if (bs) {
-bdrv_close(bs);
-}
-
-out:
-aio_context_release(aio_context);
-}
-
 void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
 {
 Error *local_err = NULL;
@@ -1987,77 +1952,6 @@ void qmp_block_passwd(bool has_device, const char 
*device,
 aio_context_release(aio_context);
 }
 
-/* Assumes AioContext is held */
-static void qmp_bdrv_open_encrypted(BlockDriverState **pbs,
-const char *filename,
-int bdrv_flags, const char *format,
-const char *password, Error **errp)
-{
-BlockDriverState *bs;
-Error *local_err = NULL;
-QDict *options = NULL;
-int ret;
-
-if (format) {
-options = qdict_new();
-qdict_put(options, "driver", qstring_from_str(format));
-}
-
-ret = bdrv_open(pbs, filename, NULL, options, bdrv_flags, &local_err);
-if (ret < 0) {
-error_propagate(errp, local_err);
-return;
-}
-bs = *pbs;
-
-bdrv_add_key(bs, password, errp);
-}
-
-void qmp_change_blockdev(const char *device, const char *filename,
- const char *format, Error **errp)
-{
-BlockBackend *blk;
-BlockDriverState *bs;
-AioContext *aio_context;
-int bdrv_flags;
-bool new_bs;
-Error *err = NULL;
-
-blk = blk_by_name(device);
-if (!blk) {
-error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
-  "Device '%s' not found", device);
-return;
-}
-bs = blk_bs(blk);
-new_bs = !bs;
-
-aio_context = blk_get_aio_context(blk);
-aio_context_acquire(aio_context);
-
-eject_device(blk, 0, &err);
-if (err) {
-error_propagate(errp, err);
-goto out;
-}
-
-bdrv_flags = blk_is_read_only(blk) ? 0 : BDRV_O_RDWR;
-bdrv_flags |= blk_get_root_state(blk)->open_flags & ~BDRV_O_RDWR;
-
-qmp_bdrv_open_encrypted(&bs, filename, bdrv_flags, format, NULL, &err);
-if (err) {
-error_propagate(errp, err);
-} else if (new_bs) {
-blk_insert_bs(blk, bs);
-/* Has been sent automatically by bdrv_open() if blk_bs(blk) was not
- * NULL */
-blk_dev_change_media_cb(blk, true);
-}
-
-out:
-aio_context_release(aio_context);
-}
-
 void qmp_blockdev_open_tray(const char *device, bool has_force, bool force,
 Error **errp)
 {
@@ -2214,6 +2108,80 @@ void qmp_blockdev_insert_medium(const char *device, 
const char *node_name,
 qmp_blockdev_insert_anon_medium(device, bs, errp);
 }
 
+void qmp_change_blockdev(const char *device, const char *filename,
+ const char *format, Error **errp)
+{
+BlockBackend *blk;
+BlockBackendRootState *blk_rs;
+BlockDriverState *medium_bs = NULL;
+int bdrv_flags, ret;
+QDict *options = NULL;
+Error *err = NULL;
+
+blk = blk_by_name(device);
+if (!blk) {
+error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+  "Device '%s' not found", device);
+goto fail;
+}
+
+if (blk_bs(blk)) {
+blk_update_root_state(blk);
+}
+
+blk_rs = blk_get_root_state(blk);
+bdrv_flags = blk_rs->read_only ? 0 : BDRV_O_RDWR;
+bdrv_flags |= blk_rs->open_flags & ~BDRV_O_RDWR;
+
+if (format) {
+options = qdict_new();
+qdict_put(options, "driver", qstring_from_str(format));
+}
+
+assert(!medium_bs);
+ret = bdrv_open(&medium_bs, filename, NULL, options, bdrv_flags, errp);
+if (ret < 0) {
+goto fail;
+}
+
+medium_bs->detect_zeroes = blk_rs->detect_zeroes;
+if (blk_rs->throttle_group) {
+bdrv_io_limit

[Qemu-devel] [PATCH v6 15/39] block: Move BlockAcctStats into BlockBackend

2015-10-12 Thread Max Reitz
As the comment above bdrv_get_stats() says, BlockAcctStats is something
which belongs to the device instead of each BlockDriverState. This patch
therefore moves it into the BlockBackend.

Signed-off-by: Max Reitz 
Reviewed-by: Eric Blake 
Reviewed-by: Alberto Garcia 
Reviewed-by: Kevin Wolf 
---
 block.c   | 11 ---
 block/block-backend.c |  5 -
 block/io.c|  6 +-
 block/qapi.c  | 24 ++--
 include/block/block.h |  2 --
 include/block/block_int.h |  3 ---
 6 files changed, 23 insertions(+), 28 deletions(-)

diff --git a/block.c b/block.c
index baad2b4..3e13b7f 100644
--- a/block.c
+++ b/block.c
@@ -4143,14 +4143,3 @@ void bdrv_refresh_filename(BlockDriverState *bs)
 QDECREF(json);
 }
 }
-
-/* This accessor function purpose is to allow the device models to access the
- * BlockAcctStats structure embedded inside a BlockDriverState without being
- * aware of the BlockDriverState structure layout.
- * It will go away when the BlockAcctStats structure will be moved inside
- * the device models.
- */
-BlockAcctStats *bdrv_get_stats(BlockDriverState *bs)
-{
-return &bs->stats;
-}
diff --git a/block/block-backend.c b/block/block-backend.c
index 7bc2eb1..a52037b 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -34,6 +34,9 @@ struct BlockBackend {
 
 /* the block size for which the guest device expects atomicity */
 int guest_block_size;
+
+/* I/O stats (display with "info blockstats"). */
+BlockAcctStats stats;
 };
 
 typedef struct BlockBackendAIOCB {
@@ -892,7 +895,7 @@ void blk_io_unplug(BlockBackend *blk)
 
 BlockAcctStats *blk_get_stats(BlockBackend *blk)
 {
-return bdrv_get_stats(blk->bs);
+return &blk->stats;
 }
 
 void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
diff --git a/block/io.c b/block/io.c
index b80044b..2fd7a1d 100644
--- a/block/io.c
+++ b/block/io.c
@@ -23,6 +23,7 @@
  */
 
 #include "trace.h"
+#include "sysemu/block-backend.h"
 #include "block/blockjob.h"
 #include "block/block_int.h"
 #include "block/throttle-groups.h"
@@ -1905,7 +1906,10 @@ static int multiwrite_merge(BlockDriverState *bs, 
BlockRequest *reqs,
 }
 }
 
-block_acct_merge_done(&bs->stats, BLOCK_ACCT_WRITE, num_reqs - outidx - 1);
+if (bs->blk) {
+block_acct_merge_done(blk_get_stats(bs->blk), BLOCK_ACCT_WRITE,
+  num_reqs - outidx - 1);
+}
 
 return outidx + 1;
 }
diff --git a/block/qapi.c b/block/qapi.c
index 0360126..7c8209b 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -344,16 +344,20 @@ static BlockStats *bdrv_query_stats(const 
BlockDriverState *bs,
 }
 
 s->stats = g_malloc0(sizeof(*s->stats));
-s->stats->rd_bytes = bs->stats.nr_bytes[BLOCK_ACCT_READ];
-s->stats->wr_bytes = bs->stats.nr_bytes[BLOCK_ACCT_WRITE];
-s->stats->rd_operations = bs->stats.nr_ops[BLOCK_ACCT_READ];
-s->stats->wr_operations = bs->stats.nr_ops[BLOCK_ACCT_WRITE];
-s->stats->rd_merged = bs->stats.merged[BLOCK_ACCT_READ];
-s->stats->wr_merged = bs->stats.merged[BLOCK_ACCT_WRITE];
-s->stats->flush_operations = bs->stats.nr_ops[BLOCK_ACCT_FLUSH];
-s->stats->wr_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_WRITE];
-s->stats->rd_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_READ];
-s->stats->flush_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_FLUSH];
+if (bs->blk) {
+BlockAcctStats *stats = blk_get_stats(bs->blk);
+
+s->stats->rd_bytes = stats->nr_bytes[BLOCK_ACCT_READ];
+s->stats->wr_bytes = stats->nr_bytes[BLOCK_ACCT_WRITE];
+s->stats->rd_operations = stats->nr_ops[BLOCK_ACCT_READ];
+s->stats->wr_operations = stats->nr_ops[BLOCK_ACCT_WRITE];
+s->stats->rd_merged = stats->merged[BLOCK_ACCT_READ];
+s->stats->wr_merged = stats->merged[BLOCK_ACCT_WRITE];
+s->stats->flush_operations = stats->nr_ops[BLOCK_ACCT_FLUSH];
+s->stats->wr_total_time_ns = stats->total_time_ns[BLOCK_ACCT_WRITE];
+s->stats->rd_total_time_ns = stats->total_time_ns[BLOCK_ACCT_READ];
+s->stats->flush_total_time_ns = stats->total_time_ns[BLOCK_ACCT_FLUSH];
+}
 
 s->stats->wr_highest_offset = bs->wr_highest_offset;
 
diff --git a/include/block/block.h b/include/block/block.h
index f923a01..d19903a 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -621,6 +621,4 @@ void bdrv_io_plug(BlockDriverState *bs);
 void bdrv_io_unplug(BlockDriverState *bs);
 void bdrv_flush_io_queue(BlockDriverState *bs);
 
-BlockAcctStats *bdrv_get_stats(BlockDriverState *bs);
-
 #endif
diff --git a/include/block/block_int.h b/include/block/block_int.h
index b8e1c59..f9c7ec5 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -399,9 +399,6 @@ struct BlockDriverState {
 unsigned   pending_reqs[2];
 QLIST_ENTRY(BlockDriverState) round_robin;
 
-/* I/O stats (display with "info blockstats"

[Qemu-devel] [PATCH v6 31/39] blockdev: Add blockdev-insert-medium

2015-10-12 Thread Max Reitz
And a helper function for that, which directly takes a pointer to the
BDS to be inserted instead of its node-name (which will be used for
implementing 'change' using blockdev-insert-medium).

Signed-off-by: Max Reitz 
---
 blockdev.c   | 54 
 qapi/block-core.json | 17 +
 qmp-commands.hx  | 37 +++
 3 files changed, 108 insertions(+)

diff --git a/blockdev.c b/blockdev.c
index 6d0a5eb..706e7e1 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2161,6 +2161,60 @@ void qmp_blockdev_remove_medium(const char *device, 
Error **errp)
 }
 }
 
+static void qmp_blockdev_insert_anon_medium(const char *device,
+BlockDriverState *bs, Error **errp)
+{
+BlockBackend *blk;
+bool has_device;
+
+blk = blk_by_name(device);
+if (!blk) {
+error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+  "Device '%s' not found", device);
+return;
+}
+
+/* For BBs without a device, we can exchange the BDS tree at will */
+has_device = blk_get_attached_dev(blk);
+
+if (has_device && !blk_dev_has_removable_media(blk)) {
+error_setg(errp, "Device '%s' is not removable", device);
+return;
+}
+
+if (has_device && !blk_dev_is_tray_open(blk)) {
+error_setg(errp, "Tray of device '%s' is not open", device);
+return;
+}
+
+if (blk_bs(blk)) {
+error_setg(errp, "There already is a medium in device '%s'", device);
+return;
+}
+
+blk_insert_bs(blk, bs);
+}
+
+void qmp_blockdev_insert_medium(const char *device, const char *node_name,
+Error **errp)
+{
+BlockDriverState *bs;
+
+bs = bdrv_find_node(node_name);
+if (!bs) {
+error_setg(errp, "Node '%s' not found", node_name);
+return;
+}
+
+if (bs->blk) {
+error_setg(errp, "Node '%s' is already in use by '%s'", node_name,
+   blk_name(bs->blk));
+return;
+}
+
+qmp_blockdev_insert_anon_medium(device, bs, errp);
+}
+
 /* throttling disk I/O limits */
 void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
int64_t bps_wr,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 8edf5d9..81a1f19 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1930,6 +1930,23 @@
 { 'command': 'blockdev-remove-medium',
   'data': { 'device': 'str' } }
 
+##
+# @blockdev-insert-medium:
+#
+# Inserts a medium (a block driver state tree) into a block device. That block
+# device's tray must currently be open and there must be no medium inserted
+# already.
+#
+# @device:block device name
+#
+# @node-name: name of a node in the block driver state graph
+#
+# Since: 2.5
+##
+{ 'command': 'blockdev-insert-medium',
+  'data': { 'device': 'str',
+'node-name': 'str'} }
+
 
 ##
 # @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 2d89e26..a9223ef 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -4040,6 +4040,43 @@ Example:
 EQMP
 
 {
+.name   = "blockdev-insert-medium",
+.args_type  = "device:s,node-name:s",
+.mhandler.cmd_new = qmp_marshal_blockdev_insert_medium,
+},
+
+SQMP
+blockdev-insert-medium
+--
+
+Inserts a medium (a block driver state tree) into a block device. That block
+device's tray must currently be open and there must be no medium inserted
+already.
+
+Arguments:
+
+- "device": block device name (json-string)
+- "node-name": root node of the BDS tree to insert into the block device
+
+Example:
+
+-> { "execute": "blockdev-add",
+ "arguments": { "options": { "node-name": "node0",
+ "driver": "raw",
+ "file": { "driver": "file",
+   "filename": "fedora.iso" } } } }
+
+<- { "return": {} }
+
+-> { "execute": "blockdev-insert-medium",
+ "arguments": { "device": "ide1-cd0",
+"node-name": "node0" } }
+
+<- { "return": {} }
+
+EQMP
+
+{
 .name   = "query-named-block-nodes",
 .args_type  = "",
 .mhandler.cmd_new = qmp_marshal_query_named_block_nodes,
-- 
2.6.1




[Qemu-devel] [PATCH v6 21/39] block: Prepare remaining BB functions for NULL BDS

2015-10-12 Thread Max Reitz
There are several BlockBackend functions which, in theory, cannot fail.
This patch makes them cope with the BlockDriverState pointer being NULL
by making them fall back to some default action like ignoring the value
in setters and returning the default in getters.

Signed-off-by: Max Reitz 
---
 block/block-backend.c | 72 +++
 1 file changed, 56 insertions(+), 16 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 2779c22..a5c58c5 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -677,7 +677,11 @@ int64_t blk_getlength(BlockBackend *blk)
 
 void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr)
 {
-bdrv_get_geometry(blk->bs, nb_sectors_ptr);
+if (!blk->bs) {
+*nb_sectors_ptr = 0;
+} else {
+bdrv_get_geometry(blk->bs, nb_sectors_ptr);
+}
 }
 
 int64_t blk_nb_sectors(BlockBackend *blk)
@@ -813,7 +817,9 @@ int blk_flush_all(void)
 
 void blk_drain(BlockBackend *blk)
 {
-bdrv_drain(blk->bs);
+if (blk->bs) {
+bdrv_drain(blk->bs);
+}
 }
 
 void blk_drain_all(void)
@@ -909,6 +915,10 @@ int blk_is_read_only(BlockBackend *blk)
 
 int blk_is_sg(BlockBackend *blk)
 {
+if (!blk->bs) {
+return 0;
+}
+
 return bdrv_is_sg(blk->bs);
 }
 
@@ -956,12 +966,16 @@ bool blk_is_available(BlockBackend *blk)
 
 void blk_lock_medium(BlockBackend *blk, bool locked)
 {
-bdrv_lock_medium(blk->bs, locked);
+if (blk->bs) {
+bdrv_lock_medium(blk->bs, locked);
+}
 }
 
 void blk_eject(BlockBackend *blk, bool eject_flag)
 {
-bdrv_eject(blk->bs, eject_flag);
+if (blk->bs) {
+bdrv_eject(blk->bs, eject_flag);
+}
 }
 
 int blk_get_flags(BlockBackend *blk)
@@ -975,7 +989,11 @@ int blk_get_flags(BlockBackend *blk)
 
 int blk_get_max_transfer_length(BlockBackend *blk)
 {
-return blk->bs->bl.max_transfer_length;
+if (blk->bs) {
+return blk->bs->bl.max_transfer_length;
+} else {
+return 0;
+}
 }
 
 void blk_set_guest_block_size(BlockBackend *blk, int align)
@@ -990,22 +1008,32 @@ void *blk_blockalign(BlockBackend *blk, size_t size)
 
 bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp)
 {
+if (!blk->bs) {
+return false;
+}
+
 return bdrv_op_is_blocked(blk->bs, op, errp);
 }
 
 void blk_op_unblock(BlockBackend *blk, BlockOpType op, Error *reason)
 {
-bdrv_op_unblock(blk->bs, op, reason);
+if (blk->bs) {
+bdrv_op_unblock(blk->bs, op, reason);
+}
 }
 
 void blk_op_block_all(BlockBackend *blk, Error *reason)
 {
-bdrv_op_block_all(blk->bs, reason);
+if (blk->bs) {
+bdrv_op_block_all(blk->bs, reason);
+}
 }
 
 void blk_op_unblock_all(BlockBackend *blk, Error *reason)
 {
-bdrv_op_unblock_all(blk->bs, reason);
+if (blk->bs) {
+bdrv_op_unblock_all(blk->bs, reason);
+}
 }
 
 AioContext *blk_get_aio_context(BlockBackend *blk)
@@ -1025,15 +1053,19 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB 
*acb)
 
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
 {
-bdrv_set_aio_context(blk->bs, new_context);
+if (blk->bs) {
+bdrv_set_aio_context(blk->bs, new_context);
+}
 }
 
 void blk_add_aio_context_notifier(BlockBackend *blk,
 void (*attached_aio_context)(AioContext *new_context, void *opaque),
 void (*detach_aio_context)(void *opaque), void *opaque)
 {
-bdrv_add_aio_context_notifier(blk->bs, attached_aio_context,
-  detach_aio_context, opaque);
+if (blk->bs) {
+bdrv_add_aio_context_notifier(blk->bs, attached_aio_context,
+  detach_aio_context, opaque);
+}
 }
 
 void blk_remove_aio_context_notifier(BlockBackend *blk,
@@ -1042,23 +1074,31 @@ void blk_remove_aio_context_notifier(BlockBackend *blk,
  void (*detach_aio_context)(void *),
  void *opaque)
 {
-bdrv_remove_aio_context_notifier(blk->bs, attached_aio_context,
- detach_aio_context, opaque);
+if (blk->bs) {
+bdrv_remove_aio_context_notifier(blk->bs, attached_aio_context,
+ detach_aio_context, opaque);
+}
 }
 
 void blk_add_close_notifier(BlockBackend *blk, Notifier *notify)
 {
-bdrv_add_close_notifier(blk->bs, notify);
+if (blk->bs) {
+bdrv_add_close_notifier(blk->bs, notify);
+}
 }
 
 void blk_io_plug(BlockBackend *blk)
 {
-bdrv_io_plug(blk->bs);
+if (blk->bs) {
+bdrv_io_plug(blk->bs);
+}
 }
 
 void blk_io_unplug(BlockBackend *blk)
 {
-bdrv_io_unplug(blk->bs);
+if (blk->bs) {
+bdrv_io_unplug(blk->bs);
+}
 }
 
 BlockAcctStats *blk_get_stats(BlockBackend *blk)
-- 
2.6.1




[Qemu-devel] [PATCH v6 23/39] block: Prepare for NULL BDS

2015-10-12 Thread Max Reitz
blk_bs() will not necessarily return a non-NULL value any more (unless
blk_is_available() is true or it can be assumed to otherwise, e.g.
because it is called immediately after a successful blk_new_with_bs() or
blk_new_open()).

Signed-off-by: Max Reitz 
---
 block.c |   5 ++
 block/qapi.c|   4 +-
 blockdev.c  | 201 ++--
 hw/block/xen_disk.c |   4 +-
 migration/block.c   |   5 ++
 monitor.c   |   4 ++
 6 files changed, 153 insertions(+), 70 deletions(-)

diff --git a/block.c b/block.c
index 48f7067..e5f00e4 100644
--- a/block.c
+++ b/block.c
@@ -2673,6 +2673,11 @@ BlockDriverState *bdrv_lookup_bs(const char *device,
 blk = blk_by_name(device);
 
 if (blk) {
+if (!blk_bs(blk)) {
+error_setg(errp, "Device '%s' has no medium", device);
+return NULL;
+}
+
 return blk_bs(blk);
 }
 }
diff --git a/block/qapi.c b/block/qapi.c
index 3b46f97..ec0f513 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -306,12 +306,12 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo 
**p_info,
 info->io_status = blk_iostatus(blk);
 }
 
-if (!QLIST_EMPTY(&bs->dirty_bitmaps)) {
+if (bs && !QLIST_EMPTY(&bs->dirty_bitmaps)) {
 info->has_dirty_bitmaps = true;
 info->dirty_bitmaps = bdrv_query_dirty_bitmaps(bs);
 }
 
-if (bs->drv) {
+if (bs && bs->drv) {
 info->has_inserted = true;
 info->inserted = bdrv_block_device_info(bs, errp);
 if (info->inserted == NULL) {
diff --git a/blockdev.c b/blockdev.c
index 25959eb..35efe84 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -124,14 +124,16 @@ void blockdev_mark_auto_del(BlockBackend *blk)
 return;
 }
 
-aio_context = bdrv_get_aio_context(bs);
-aio_context_acquire(aio_context);
+if (bs) {
+aio_context = bdrv_get_aio_context(bs);
+aio_context_acquire(aio_context);
 
-if (bs->job) {
-block_job_cancel(bs->job);
-}
+if (bs->job) {
+block_job_cancel(bs->job);
+}
 
-aio_context_release(aio_context);
+aio_context_release(aio_context);
+}
 
 dinfo->auto_del = 1;
 }
@@ -229,8 +231,8 @@ bool drive_check_orphaned(void)
 dinfo->type != IF_NONE) {
 fprintf(stderr, "Warning: Orphaned drive without device: "
 "id=%s,file=%s,if=%s,bus=%d,unit=%d\n",
-blk_name(blk), blk_bs(blk)->filename, if_name[dinfo->type],
-dinfo->bus, dinfo->unit);
+blk_name(blk), blk_bs(blk) ? blk_bs(blk)->filename : "",
+if_name[dinfo->type], dinfo->bus, dinfo->unit);
 rs = true;
 }
 }
@@ -1040,6 +1042,10 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
 monitor_printf(mon, "Device '%s' not found\n", device);
 return;
 }
+if (!blk_is_available(blk)) {
+monitor_printf(mon, "Device '%s' has no medium\n", device);
+return;
+}
 ret = bdrv_commit(blk_bs(blk));
 }
 if (ret < 0) {
@@ -1119,7 +1125,9 @@ SnapshotInfo 
*qmp_blockdev_snapshot_delete_internal_sync(const char *device,
   "Device '%s' not found", device);
 return NULL;
 }
-bs = blk_bs(blk);
+
+aio_context = blk_get_aio_context(blk);
+aio_context_acquire(aio_context);
 
 if (!has_id) {
 id = NULL;
@@ -1131,11 +1139,14 @@ SnapshotInfo 
*qmp_blockdev_snapshot_delete_internal_sync(const char *device,
 
 if (!id && !name) {
 error_setg(errp, "Name or id must be provided");
-return NULL;
+goto out_aio_context;
 }
 
-aio_context = bdrv_get_aio_context(bs);
-aio_context_acquire(aio_context);
+if (!blk_is_available(blk)) {
+error_setg(errp, "Device '%s' has no medium", device);
+goto out_aio_context;
+}
+bs = blk_bs(blk);
 
 if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE, errp)) {
 goto out_aio_context;
@@ -1309,16 +1320,16 @@ static void 
internal_snapshot_prepare(BlkTransactionState *common,
   "Device '%s' not found", device);
 return;
 }
-bs = blk_bs(blk);
 
 /* AioContext is released in .clean() */
-state->aio_context = bdrv_get_aio_context(bs);
+state->aio_context = blk_get_aio_context(blk);
 aio_context_acquire(state->aio_context);
 
-if (!bdrv_is_inserted(bs)) {
+if (!blk_is_available(blk)) {
 error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
 return;
 }
+bs = blk_bs(blk);
 
 if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, errp)) {
 return;
@@ -1570,7 +1581,6 @@ typedef struct DriveBackupState {
 static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
 {
 DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common

[Qemu-devel] [PATCH v6 27/39] block: Add blk_remove_bs()

2015-10-12 Thread Max Reitz
This function removes the BlockDriverState associated with the given
BlockBackend from that BB and sets the BDS pointer in the BB to NULL.

Signed-off-by: Max Reitz 
---
 block/block-backend.c  | 12 
 include/sysemu/block-backend.h |  1 +
 2 files changed, 13 insertions(+)

diff --git a/block/block-backend.c b/block/block-backend.c
index 19fdaae..eb7409c 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -334,6 +334,18 @@ void blk_hide_on_behalf_of_hmp_drive_del(BlockBackend *blk)
 }
 
 /*
+ * Disassociates the currently associated BlockDriverState from @blk.
+ */
+void blk_remove_bs(BlockBackend *blk)
+{
+blk_update_root_state(blk);
+
+bdrv_unref(blk->bs);
+blk->bs->blk = NULL;
+blk->bs = NULL;
+}
+
+/*
  * Associates a new BlockDriverState with @blk.
  */
 void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 9306a52..14a6d32 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -72,6 +72,7 @@ BlockBackend *blk_by_name(const char *name);
 BlockBackend *blk_next(BlockBackend *blk);
 
 BlockDriverState *blk_bs(BlockBackend *blk);
+void blk_remove_bs(BlockBackend *blk);
 void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs);
 
 void blk_hide_on_behalf_of_hmp_drive_del(BlockBackend *blk);
-- 
2.6.1




[Qemu-devel] [PATCH v6 13/39] block: Move guest_block_size into BlockBackend

2015-10-12 Thread Max Reitz
guest_block_size is a guest device property so it should be moved into
the interface between block layer and guest devices, which is the
BlockBackend.

Signed-off-by: Max Reitz 
Reviewed-by: Eric Blake 
Reviewed-by: Alberto Garcia 
Reviewed-by: Kevin Wolf 
---
 block.c   | 7 ---
 block/block-backend.c | 7 +--
 include/block/block.h | 1 -
 include/block/block_int.h | 3 ---
 4 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/block.c b/block.c
index ccdef82..baad2b4 100644
--- a/block.c
+++ b/block.c
@@ -852,7 +852,6 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild 
*file,
 goto fail_opts;
 }
 
-bs->guest_block_size = 512;
 bs->request_alignment = 512;
 bs->zero_beyond_eof = true;
 open_flags = bdrv_open_flags(bs, flags);
@@ -1992,7 +1991,6 @@ static void bdrv_move_feature_fields(BlockDriverState 
*bs_dest,
 /* move some fields that need to stay attached to the device */
 
 /* dev info */
-bs_dest->guest_block_size   = bs_src->guest_block_size;
 bs_dest->copy_on_read   = bs_src->copy_on_read;
 
 bs_dest->enable_write_cache = bs_src->enable_write_cache;
@@ -3197,11 +3195,6 @@ void bdrv_lock_medium(BlockDriverState *bs, bool locked)
 }
 }
 
-void bdrv_set_guest_block_size(BlockDriverState *bs, int align)
-{
-bs->guest_block_size = align;
-}
-
 BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
 {
 BdrvDirtyBitmap *bm;
diff --git a/block/block-backend.c b/block/block-backend.c
index c7e0f7b..7bc2eb1 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -31,6 +31,9 @@ struct BlockBackend {
 /* TODO change to DeviceState when all users are qdevified */
 const BlockDevOps *dev_ops;
 void *dev_opaque;
+
+/* the block size for which the guest device expects atomicity */
+int guest_block_size;
 };
 
 typedef struct BlockBackendAIOCB {
@@ -351,7 +354,7 @@ void blk_detach_dev(BlockBackend *blk, void *dev)
 blk->dev = NULL;
 blk->dev_ops = NULL;
 blk->dev_opaque = NULL;
-bdrv_set_guest_block_size(blk->bs, 512);
+blk->guest_block_size = 512;
 blk_unref(blk);
 }
 
@@ -806,7 +809,7 @@ int blk_get_max_transfer_length(BlockBackend *blk)
 
 void blk_set_guest_block_size(BlockBackend *blk, int align)
 {
-bdrv_set_guest_block_size(blk->bs, align);
+blk->guest_block_size = align;
 }
 
 void *blk_blockalign(BlockBackend *blk, size_t size)
diff --git a/include/block/block.h b/include/block/block.h
index cb3e312..f923a01 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -466,7 +466,6 @@ void bdrv_img_create(const char *filename, const char *fmt,
 size_t bdrv_min_mem_align(BlockDriverState *bs);
 /* Returns optimal alignment in bytes for bounce buffer */
 size_t bdrv_opt_mem_align(BlockDriverState *bs);
-void bdrv_set_guest_block_size(BlockDriverState *bs, int align);
 void *qemu_blockalign(BlockDriverState *bs, size_t size);
 void *qemu_blockalign0(BlockDriverState *bs, size_t size);
 void *qemu_try_blockalign(BlockDriverState *bs, size_t size);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 40d40df..e79d8c0 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -411,9 +411,6 @@ struct BlockDriverState {
 /* Alignment requirement for offset/length of I/O requests */
 unsigned int request_alignment;
 
-/* the block size for which the guest device expects atomicity */
-int guest_block_size;
-
 /* do we need to tell the quest if we have a volatile write cache? */
 int enable_write_cache;
 
-- 
2.6.1




[Qemu-devel] [PATCH v6 20/39] block: Fail requests to empty BlockBackend

2015-10-12 Thread Max Reitz
If there is no BlockDriverState in a BlockBackend or if the tray of the
guest device is open, fail all requests (where that is possible) with
-ENOMEDIUM.

The reason the status of the guest device is taken into account is
because once the guest device's tray is opened, any request on the same
BlockBackend as the guest uses should fail. If the BDS tree is supposed
to be usable even after ejecting it from the guest, a different
BlockBackend must be used.

Signed-off-by: Max Reitz 
Reviewed-by: Eric Blake 
---
 block/block-backend.c | 55 ++-
 1 file changed, 54 insertions(+), 1 deletion(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index d790870..2779c22 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -529,7 +529,7 @@ static int blk_check_byte_request(BlockBackend *blk, 
int64_t offset,
 return -EIO;
 }
 
-if (!blk_is_inserted(blk)) {
+if (!blk_is_available(blk)) {
 return -ENOMEDIUM;
 }
 
@@ -668,6 +668,10 @@ int blk_pwrite(BlockBackend *blk, int64_t offset, const 
void *buf, int count)
 
 int64_t blk_getlength(BlockBackend *blk)
 {
+if (!blk_is_available(blk)) {
+return -ENOMEDIUM;
+}
+
 return bdrv_getlength(blk->bs);
 }
 
@@ -678,6 +682,10 @@ void blk_get_geometry(BlockBackend *blk, uint64_t 
*nb_sectors_ptr)
 
 int64_t blk_nb_sectors(BlockBackend *blk)
 {
+if (!blk_is_available(blk)) {
+return -ENOMEDIUM;
+}
+
 return bdrv_nb_sectors(blk->bs);
 }
 
@@ -708,6 +716,10 @@ BlockAIOCB *blk_aio_writev(BlockBackend *blk, int64_t 
sector_num,
 BlockAIOCB *blk_aio_flush(BlockBackend *blk,
   BlockCompletionFunc *cb, void *opaque)
 {
+if (!blk_is_available(blk)) {
+return abort_aio_request(blk, cb, opaque, -ENOMEDIUM);
+}
+
 return bdrv_aio_flush(blk->bs, cb, opaque);
 }
 
@@ -749,12 +761,20 @@ int blk_aio_multiwrite(BlockBackend *blk, BlockRequest 
*reqs, int num_reqs)
 
 int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
 {
+if (!blk_is_available(blk)) {
+return -ENOMEDIUM;
+}
+
 return bdrv_ioctl(blk->bs, req, buf);
 }
 
 BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
   BlockCompletionFunc *cb, void *opaque)
 {
+if (!blk_is_available(blk)) {
+return abort_aio_request(blk, cb, opaque, -ENOMEDIUM);
+}
+
 return bdrv_aio_ioctl(blk->bs, req, buf, cb, opaque);
 }
 
@@ -770,11 +790,19 @@ int blk_co_discard(BlockBackend *blk, int64_t sector_num, 
int nb_sectors)
 
 int blk_co_flush(BlockBackend *blk)
 {
+if (!blk_is_available(blk)) {
+return -ENOMEDIUM;
+}
+
 return bdrv_co_flush(blk->bs);
 }
 
 int blk_flush(BlockBackend *blk)
 {
+if (!blk_is_available(blk)) {
+return -ENOMEDIUM;
+}
+
 return bdrv_flush(blk->bs);
 }
 
@@ -908,6 +936,11 @@ void blk_set_enable_write_cache(BlockBackend *blk, bool 
wce)
 
 void blk_invalidate_cache(BlockBackend *blk, Error **errp)
 {
+if (!blk->bs) {
+error_setg(errp, "Device '%s' has no medium", blk->name);
+return;
+}
+
 bdrv_invalidate_cache(blk->bs, errp);
 }
 
@@ -1063,6 +1096,10 @@ int blk_write_compressed(BlockBackend *blk, int64_t 
sector_num,
 
 int blk_truncate(BlockBackend *blk, int64_t offset)
 {
+if (!blk_is_available(blk)) {
+return -ENOMEDIUM;
+}
+
 return bdrv_truncate(blk->bs, offset);
 }
 
@@ -1079,21 +1116,37 @@ int blk_discard(BlockBackend *blk, int64_t sector_num, 
int nb_sectors)
 int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
  int64_t pos, int size)
 {
+if (!blk_is_available(blk)) {
+return -ENOMEDIUM;
+}
+
 return bdrv_save_vmstate(blk->bs, buf, pos, size);
 }
 
 int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size)
 {
+if (!blk_is_available(blk)) {
+return -ENOMEDIUM;
+}
+
 return bdrv_load_vmstate(blk->bs, buf, pos, size);
 }
 
 int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz)
 {
+if (!blk_is_available(blk)) {
+return -ENOMEDIUM;
+}
+
 return bdrv_probe_blocksizes(blk->bs, bsz);
 }
 
 int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo)
 {
+if (!blk_is_available(blk)) {
+return -ENOMEDIUM;
+}
+
 return bdrv_probe_geometry(blk->bs, geo);
 }
 
-- 
2.6.1




[Qemu-devel] [PATCH v6 22/39] block: Add blk_insert_bs()

2015-10-12 Thread Max Reitz
This function associates the given BlockDriverState with the given
BlockBackend.

Signed-off-by: Max Reitz 
---
 block/block-backend.c  | 11 +++
 include/sysemu/block-backend.h |  1 +
 2 files changed, 12 insertions(+)

diff --git a/block/block-backend.c b/block/block-backend.c
index a5c58c5..19fdaae 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -334,6 +334,17 @@ void blk_hide_on_behalf_of_hmp_drive_del(BlockBackend *blk)
 }
 
 /*
+ * Associates a new BlockDriverState with @blk.
+ */
+void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
+{
+assert(!blk->bs && !bs->blk);
+bdrv_ref(bs);
+blk->bs = bs;
+bs->blk = blk;
+}
+
+/*
  * Attach device model @dev to @blk.
  * Return 0 on success, -EBUSY when a device model is attached already.
  */
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 52e35a1..9306a52 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -72,6 +72,7 @@ BlockBackend *blk_by_name(const char *name);
 BlockBackend *blk_next(BlockBackend *blk);
 
 BlockDriverState *blk_bs(BlockBackend *blk);
+void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs);
 
 void blk_hide_on_behalf_of_hmp_drive_del(BlockBackend *blk);
 
-- 
2.6.1




[Qemu-devel] [PATCH v6 25/39] blockdev: Pull out blockdev option extraction

2015-10-12 Thread Max Reitz
Extract some of the blockdev option extraction code from blockdev_init()
into its own function. This simplifies blockdev_init() and will allow
reusing the code in a different function added in a follow-up patch.

Signed-off-by: Max Reitz 
Reviewed-by: Alberto Garcia 
---
 blockdev.c | 209 +
 1 file changed, 113 insertions(+), 96 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 845a1c1..e0f04dd 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -350,25 +350,128 @@ static bool check_throttle_config(ThrottleConfig *cfg, 
Error **errp)
 
 typedef enum { MEDIA_DISK, MEDIA_CDROM } DriveMediaType;
 
+static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags,
+ThrottleConfig *throttle_cfg, BlockdevDetectZeroesOptions *detect_zeroes,
+const char **throttling_group, Error **errp)
+{
+const char *discard;
+Error *local_error = NULL;
+#ifdef CONFIG_LINUX_AIO
+const char *aio;
+#endif
+
+if (!qemu_opt_get_bool(opts, "read-only", false)) {
+*bdrv_flags |= BDRV_O_RDWR;
+}
+if (qemu_opt_get_bool(opts, "copy-on-read", false)) {
+*bdrv_flags |= BDRV_O_COPY_ON_READ;
+}
+
+if ((discard = qemu_opt_get(opts, "discard")) != NULL) {
+if (bdrv_parse_discard_flags(discard, bdrv_flags) != 0) {
+error_setg(errp, "Invalid discard option");
+return;
+}
+}
+
+if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, true)) {
+*bdrv_flags |= BDRV_O_CACHE_WB;
+}
+if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
+*bdrv_flags |= BDRV_O_NOCACHE;
+}
+if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
+*bdrv_flags |= BDRV_O_NO_FLUSH;
+}
+
+#ifdef CONFIG_LINUX_AIO
+if ((aio = qemu_opt_get(opts, "aio")) != NULL) {
+if (!strcmp(aio, "native")) {
+*bdrv_flags |= BDRV_O_NATIVE_AIO;
+} else if (!strcmp(aio, "threads")) {
+/* this is the default */
+} else {
+   error_setg(errp, "invalid aio option");
+   return;
+}
+}
+#endif
+
+/* disk I/O throttling */
+memset(throttle_cfg, 0, sizeof(*throttle_cfg));
+throttle_cfg->buckets[THROTTLE_BPS_TOTAL].avg =
+qemu_opt_get_number(opts, "throttling.bps-total", 0);
+throttle_cfg->buckets[THROTTLE_BPS_READ].avg  =
+qemu_opt_get_number(opts, "throttling.bps-read", 0);
+throttle_cfg->buckets[THROTTLE_BPS_WRITE].avg =
+qemu_opt_get_number(opts, "throttling.bps-write", 0);
+throttle_cfg->buckets[THROTTLE_OPS_TOTAL].avg =
+qemu_opt_get_number(opts, "throttling.iops-total", 0);
+throttle_cfg->buckets[THROTTLE_OPS_READ].avg =
+qemu_opt_get_number(opts, "throttling.iops-read", 0);
+throttle_cfg->buckets[THROTTLE_OPS_WRITE].avg =
+qemu_opt_get_number(opts, "throttling.iops-write", 0);
+
+throttle_cfg->buckets[THROTTLE_BPS_TOTAL].max =
+qemu_opt_get_number(opts, "throttling.bps-total-max", 0);
+throttle_cfg->buckets[THROTTLE_BPS_READ].max  =
+qemu_opt_get_number(opts, "throttling.bps-read-max", 0);
+throttle_cfg->buckets[THROTTLE_BPS_WRITE].max =
+qemu_opt_get_number(opts, "throttling.bps-write-max", 0);
+throttle_cfg->buckets[THROTTLE_OPS_TOTAL].max =
+qemu_opt_get_number(opts, "throttling.iops-total-max", 0);
+throttle_cfg->buckets[THROTTLE_OPS_READ].max =
+qemu_opt_get_number(opts, "throttling.iops-read-max", 0);
+throttle_cfg->buckets[THROTTLE_OPS_WRITE].max =
+qemu_opt_get_number(opts, "throttling.iops-write-max", 0);
+
+throttle_cfg->op_size =
+qemu_opt_get_number(opts, "throttling.iops-size", 0);
+
+*throttling_group = qemu_opt_get(opts, "throttling.group");
+
+if (!check_throttle_config(throttle_cfg, errp)) {
+return;
+}
+
+*detect_zeroes =
+qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
+qemu_opt_get(opts, "detect-zeroes"),
+BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
+BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
+&local_error);
+if (local_error) {
+error_propagate(errp, local_error);
+return;
+}
+
+if (*detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
+!(*bdrv_flags & BDRV_O_UNMAP))
+{
+error_setg(errp, "setting detect-zeroes to unmap is not allowed "
+ "without setting discard operation to unmap");
+return;
+}
+}
+
 /* Takes the ownership of bs_opts */
 static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
Error **errp)
 {
 const char *buf;
-int ro = 0;
 int bdrv_flags = 0;
 int on_read_error, on_write_error;
 BlockBackend *blk;
 BlockDriverState *bs;
 ThrottleConfig cfg;
 int snapshot = 0;
-bool copy_on_read;
 Error *error = NULL;
 QemuO

[Qemu-devel] [PATCH v6 12/39] block: Fix BB AIOCB AioContext without BDS

2015-10-12 Thread Max Reitz
Fix the BlockBackend's AIOCB AioContext for aborting AIO in case there
is no BDS. If there is no implementation of AIOCBInfo::get_aio_context()
the AioContext is derived from the BDS the AIOCB belongs to. If that BDS
is NULL (because it has been removed from the BB) this will not work.

This patch makes blk_get_aio_context() fall back to the main loop
context if the BDS pointer is NULL and implements
AIOCBInfo::get_aio_context() (blk_aiocb_get_aio_context()) which invokes
blk_get_aio_context().

Signed-off-by: Max Reitz 
Reviewed-by: Eric Blake 
Reviewed-by: Alberto Garcia 
Reviewed-by: Kevin Wolf 
---
 block/block-backend.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 74642dc..c7e0f7b 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -18,6 +18,8 @@
 /* Number of coroutines to reserve per attached device model */
 #define COROUTINE_POOL_RESERVATION 64
 
+static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb);
+
 struct BlockBackend {
 char *name;
 int refcnt;
@@ -34,10 +36,12 @@ struct BlockBackend {
 typedef struct BlockBackendAIOCB {
 BlockAIOCB common;
 QEMUBH *bh;
+BlockBackend *blk;
 int ret;
 } BlockBackendAIOCB;
 
 static const AIOCBInfo block_backend_aiocb_info = {
+.get_aio_context = blk_aiocb_get_aio_context,
 .aiocb_size = sizeof(BlockBackendAIOCB),
 };
 
@@ -558,6 +562,7 @@ static BlockAIOCB *abort_aio_request(BlockBackend *blk, 
BlockCompletionFunc *cb,
 QEMUBH *bh;
 
 acb = blk_aio_get(&block_backend_aiocb_info, blk, cb, opaque);
+acb->blk = blk;
 acb->ret = ret;
 
 bh = aio_bh_new(blk_get_aio_context(blk), error_callback_bh, acb);
@@ -831,7 +836,17 @@ void blk_op_unblock_all(BlockBackend *blk, Error *reason)
 
 AioContext *blk_get_aio_context(BlockBackend *blk)
 {
-return bdrv_get_aio_context(blk->bs);
+if (blk->bs) {
+return bdrv_get_aio_context(blk->bs);
+} else {
+return qemu_get_aio_context();
+}
+}
+
+static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
+{
+BlockBackendAIOCB *blk_acb = DO_UPCAST(BlockBackendAIOCB, common, acb);
+return blk_get_aio_context(blk_acb->blk);
 }
 
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
-- 
2.6.1




[Qemu-devel] [PATCH v6 19/39] block: Make some BB functions fall back to BBRS

2015-10-12 Thread Max Reitz
If there is no BDS tree attached to a BlockBackend, functions that can
do so should fall back to the BlockBackendRootState structure.

Signed-off-by: Max Reitz 
---
 block/block-backend.c | 28 
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 6a3f0c7..d790870 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -872,7 +872,11 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction 
action,
 
 int blk_is_read_only(BlockBackend *blk)
 {
-return bdrv_is_read_only(blk->bs);
+if (blk->bs) {
+return bdrv_is_read_only(blk->bs);
+} else {
+return blk->root_state.read_only;
+}
 }
 
 int blk_is_sg(BlockBackend *blk)
@@ -882,12 +886,24 @@ int blk_is_sg(BlockBackend *blk)
 
 int blk_enable_write_cache(BlockBackend *blk)
 {
-return bdrv_enable_write_cache(blk->bs);
+if (blk->bs) {
+return bdrv_enable_write_cache(blk->bs);
+} else {
+return !!(blk->root_state.open_flags & BDRV_O_CACHE_WB);
+}
 }
 
 void blk_set_enable_write_cache(BlockBackend *blk, bool wce)
 {
-bdrv_set_enable_write_cache(blk->bs, wce);
+if (blk->bs) {
+bdrv_set_enable_write_cache(blk->bs, wce);
+} else {
+if (wce) {
+blk->root_state.open_flags |= BDRV_O_CACHE_WB;
+} else {
+blk->root_state.open_flags &= ~BDRV_O_CACHE_WB;
+}
+}
 }
 
 void blk_invalidate_cache(BlockBackend *blk, Error **errp)
@@ -917,7 +933,11 @@ void blk_eject(BlockBackend *blk, bool eject_flag)
 
 int blk_get_flags(BlockBackend *blk)
 {
-return bdrv_get_flags(blk->bs);
+if (blk->bs) {
+return bdrv_get_flags(blk->bs);
+} else {
+return blk->root_state.open_flags;
+}
 }
 
 int blk_get_max_transfer_length(BlockBackend *blk)
-- 
2.6.1




[Qemu-devel] [PATCH v6 18/39] block: Add BlockBackendRootState

2015-10-12 Thread Max Reitz
This structure will store some of the state of the root BDS if the BDS
tree is removed, so that state can be restored once a new BDS tree is
inserted.

Signed-off-by: Max Reitz 
---
 block/block-backend.c  | 40 
 include/block/block_int.h  | 10 ++
 include/qemu/typedefs.h|  1 +
 include/sysemu/block-backend.h |  2 ++
 4 files changed, 53 insertions(+)

diff --git a/block/block-backend.c b/block/block-backend.c
index 2708ad1..6a3f0c7 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -13,6 +13,7 @@
 #include "sysemu/block-backend.h"
 #include "block/block_int.h"
 #include "block/blockjob.h"
+#include "block/throttle-groups.h"
 #include "sysemu/blockdev.h"
 #include "sysemu/sysemu.h"
 #include "qapi-event.h"
@@ -37,6 +38,10 @@ struct BlockBackend {
 /* the block size for which the guest device expects atomicity */
 int guest_block_size;
 
+/* If the BDS tree is removed, some of its options are stored here (which
+ * can be used to restore those options in the new BDS on insert) */
+BlockBackendRootState root_state;
+
 /* I/O stats (display with "info blockstats"). */
 BlockAcctStats stats;
 
@@ -161,6 +166,10 @@ static void blk_delete(BlockBackend *blk)
 bdrv_unref(blk->bs);
 blk->bs = NULL;
 }
+if (blk->root_state.throttle_state) {
+g_free(blk->root_state.throttle_group);
+throttle_group_unref(blk->root_state.throttle_state);
+}
 /* Avoid double-remove after blk_hide_on_behalf_of_hmp_drive_del() */
 if (blk->name[0]) {
 QTAILQ_REMOVE(&blk_backends, blk, link);
@@ -1067,3 +1076,34 @@ int blk_probe_geometry(BlockBackend *blk, HDGeometry 
*geo)
 {
 return bdrv_probe_geometry(blk->bs, geo);
 }
+
+/*
+ * Updates the BlockBackendRootState object with data from the currently
+ * attached BlockDriverState.
+ */
+void blk_update_root_state(BlockBackend *blk)
+{
+assert(blk->bs);
+
+blk->root_state.open_flags= blk->bs->open_flags;
+blk->root_state.read_only = blk->bs->read_only;
+blk->root_state.detect_zeroes = blk->bs->detect_zeroes;
+
+if (blk->root_state.throttle_group) {
+g_free(blk->root_state.throttle_group);
+throttle_group_unref(blk->root_state.throttle_state);
+}
+if (blk->bs->throttle_state) {
+const char *name = throttle_group_get_name(blk->bs);
+blk->root_state.throttle_group = g_strdup(name);
+blk->root_state.throttle_state = throttle_group_incref(name);
+} else {
+blk->root_state.throttle_group = NULL;
+blk->root_state.throttle_state = NULL;
+}
+}
+
+BlockBackendRootState *blk_get_root_state(BlockBackend *blk)
+{
+return &blk->root_state;
+}
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 009d6ea..e472a03 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -26,6 +26,7 @@
 
 #include "block/accounting.h"
 #include "block/block.h"
+#include "block/throttle-groups.h"
 #include "qemu/option.h"
 #include "qemu/queue.h"
 #include "block/coroutine.h"
@@ -449,6 +450,15 @@ struct BlockDriverState {
 NotifierWithReturn write_threshold_notifier;
 };
 
+struct BlockBackendRootState {
+int open_flags;
+bool read_only;
+BlockdevDetectZeroesOptions detect_zeroes;
+
+char *throttle_group;
+ThrottleState *throttle_state;
+};
+
 static inline BlockDriverState *backing_bs(BlockDriverState *bs)
 {
 return bs->backing ? bs->backing->bs : NULL;
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index ee1ce1d..2e39751 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -11,6 +11,7 @@ typedef struct AddressSpace AddressSpace;
 typedef struct AioContext AioContext;
 typedef struct AudioState AudioState;
 typedef struct BlockBackend BlockBackend;
+typedef struct BlockBackendRootState BlockBackendRootState;
 typedef struct BlockDriverState BlockDriverState;
 typedef struct BusClass BusClass;
 typedef struct BusState BusState;
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index eafcef0..52e35a1 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -163,6 +163,8 @@ void blk_add_close_notifier(BlockBackend *blk, Notifier 
*notify);
 void blk_io_plug(BlockBackend *blk);
 void blk_io_unplug(BlockBackend *blk);
 BlockAcctStats *blk_get_stats(BlockBackend *blk);
+BlockBackendRootState *blk_get_root_state(BlockBackend *blk);
+void blk_update_root_state(BlockBackend *blk);
 
 void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
   BlockCompletionFunc *cb, void *opaque);
-- 
2.6.1




[Qemu-devel] [PATCH v6 06/39] block: Add blk_is_available()

2015-10-12 Thread Max Reitz
blk_is_available() returns true iff the BDS is inserted (which means
blk_bs() is not NULL and bdrv_is_inserted() returns true) and if the
tray of the guest device is closed.

blk_is_inserted() is changed to return true only if blk_bs() is not
NULL.

Signed-off-by: Max Reitz 
Reviewed-by: Eric Blake 
Reviewed-by: Alberto Garcia 
Reviewed-by: Kevin Wolf 
---
 block/block-backend.c  | 7 ++-
 include/sysemu/block-backend.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 1db002c..74642dc 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -771,7 +771,12 @@ void blk_invalidate_cache(BlockBackend *blk, Error **errp)
 
 bool blk_is_inserted(BlockBackend *blk)
 {
-return bdrv_is_inserted(blk->bs);
+return blk->bs && bdrv_is_inserted(blk->bs);
+}
+
+bool blk_is_available(BlockBackend *blk)
+{
+return blk_is_inserted(blk) && !blk_dev_is_tray_open(blk);
 }
 
 void blk_lock_medium(BlockBackend *blk, bool locked)
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 8f2bf10..1e19d1b 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -131,6 +131,7 @@ int blk_enable_write_cache(BlockBackend *blk);
 void blk_set_enable_write_cache(BlockBackend *blk, bool wce);
 void blk_invalidate_cache(BlockBackend *blk, Error **errp);
 bool blk_is_inserted(BlockBackend *blk);
+bool blk_is_available(BlockBackend *blk);
 void blk_lock_medium(BlockBackend *blk, bool locked);
 void blk_eject(BlockBackend *blk, bool eject_flag);
 int blk_get_flags(BlockBackend *blk);
-- 
2.6.1




[Qemu-devel] [PATCH v6 09/39] block: Invoke change media CB before NULLing drv

2015-10-12 Thread Max Reitz
In order to handle host device passthrough, some guest device models
may call blk_is_inserted() to check whether the medium is inserted on
the host, when checking the guest tray status.

This tray status is inquired by blk_dev_change_media_cb(); because
bdrv_is_inserted() (invoked by blk_is_inserted()) always returns false
for BDS with drv set to NULL, blk_dev_change_media_cb() should therefore
be called before drv is set to NULL.

Signed-off-by: Max Reitz 
Reviewed-by: Eric Blake 
Reviewed-by: Alberto Garcia 
Reviewed-by: Kevin Wolf 
---
 block.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/block.c b/block.c
index 363088c..ccdef82 100644
--- a/block.c
+++ b/block.c
@@ -1902,6 +1902,10 @@ void bdrv_close(BlockDriverState *bs)
 bdrv_drain(bs); /* in case flush left pending I/O */
 notifier_list_notify(&bs->close_notifiers, bs);
 
+if (bs->blk) {
+blk_dev_change_media_cb(bs->blk, false);
+}
+
 if (bs->drv) {
 BdrvChild *child, *next;
 
@@ -1940,10 +1944,6 @@ void bdrv_close(BlockDriverState *bs)
 bs->full_open_options = NULL;
 }
 
-if (bs->blk) {
-blk_dev_change_media_cb(bs->blk, false);
-}
-
 QLIST_FOREACH_SAFE(ban, &bs->aio_notifiers, list, ban_next) {
 g_free(ban);
 }
-- 
2.6.1




[Qemu-devel] [PATCH v6 17/39] block/throttle-groups: Make incref/decref public

2015-10-12 Thread Max Reitz
Throttle groups are not necessarily referenced by BDSs alone; a later
patch will essentially allow BBs to reference them, too. Make the
ref/unref functions public so that reference can be properly accounted
for.

Their interface is slightly adjusted in that they return and take a
ThrottleState pointer, respectively, instead of a ThrottleGroup pointer.
Functionally, they are equivalent, but since ThrottleGroup is not meant
to be used outside of block/throttle-groups.c, ThrottleState is easier
to handle.

Signed-off-by: Max Reitz 
---
 block/throttle-groups.c | 19 +++
 include/block/throttle-groups.h |  3 +++
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index 1abc6fc..20cb216 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -76,9 +76,9 @@ static QTAILQ_HEAD(, ThrottleGroup) throttle_groups =
  * created.
  *
  * @name: the name of the ThrottleGroup
- * @ret:  the ThrottleGroup
+ * @ret:  the ThrottleState member of the ThrottleGroup
  */
-static ThrottleGroup *throttle_group_incref(const char *name)
+ThrottleState *throttle_group_incref(const char *name)
 {
 ThrottleGroup *tg = NULL;
 ThrottleGroup *iter;
@@ -108,7 +108,7 @@ static ThrottleGroup *throttle_group_incref(const char 
*name)
 
 qemu_mutex_unlock(&throttle_groups_lock);
 
-return tg;
+return &tg->ts;
 }
 
 /* Decrease the reference count of a ThrottleGroup.
@@ -116,10 +116,12 @@ static ThrottleGroup *throttle_group_incref(const char 
*name)
  * When the reference count reaches zero the ThrottleGroup is
  * destroyed.
  *
- * @tg:  The ThrottleGroup to unref
+ * @ts:  The ThrottleGroup to unref, given by its ThrottleState member
  */
-static void throttle_group_unref(ThrottleGroup *tg)
+void throttle_group_unref(ThrottleState *ts)
 {
+ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
+
 qemu_mutex_lock(&throttle_groups_lock);
 if (--tg->refcount == 0) {
 QTAILQ_REMOVE(&throttle_groups, tg, list);
@@ -401,7 +403,8 @@ static void write_timer_cb(void *opaque)
 void throttle_group_register_bs(BlockDriverState *bs, const char *groupname)
 {
 int i;
-ThrottleGroup *tg = throttle_group_incref(groupname);
+ThrottleState *ts = throttle_group_incref(groupname);
+ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
 int clock_type = QEMU_CLOCK_REALTIME;
 
 if (qtest_enabled()) {
@@ -409,7 +412,7 @@ void throttle_group_register_bs(BlockDriverState *bs, const 
char *groupname)
 clock_type = QEMU_CLOCK_VIRTUAL;
 }
 
-bs->throttle_state = &tg->ts;
+bs->throttle_state = ts;
 
 qemu_mutex_lock(&tg->lock);
 /* If the ThrottleGroup is new set this BlockDriverState as the token */
@@ -461,7 +464,7 @@ void throttle_group_unregister_bs(BlockDriverState *bs)
 throttle_timers_destroy(&bs->throttle_timers);
 qemu_mutex_unlock(&tg->lock);
 
-throttle_group_unref(tg);
+throttle_group_unref(&tg->ts);
 bs->throttle_state = NULL;
 }
 
diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
index fab113f..f3b75b3 100644
--- a/include/block/throttle-groups.h
+++ b/include/block/throttle-groups.h
@@ -30,6 +30,9 @@
 
 const char *throttle_group_get_name(BlockDriverState *bs);
 
+ThrottleState *throttle_group_incref(const char *name);
+void throttle_group_unref(ThrottleState *ts);
+
 void throttle_group_config(BlockDriverState *bs, ThrottleConfig *cfg);
 void throttle_group_get_config(BlockDriverState *bs, ThrottleConfig *cfg);
 
-- 
2.6.1




[Qemu-devel] [PATCH v6 10/39] hw/block/fdc: Implement tray status

2015-10-12 Thread Max Reitz
The tray of an FDD is open iff there is no medium inserted (there are
only two states for an FDD: "medium inserted" or "no medium inserted").

Signed-off-by: Max Reitz 
Reviewed-by: Eric Blake 
Reviewed-by: Kevin Wolf 
---
 hw/block/fdc.c   | 20 
 tests/fdc-test.c |  4 +---
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index 6686a72..4292ece 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -192,6 +192,8 @@ typedef struct FDrive {
 uint8_t ro;   /* Is read-only   */
 uint8_t media_changed;/* Is media changed   */
 uint8_t media_rate;   /* Data rate of medium*/
+
+bool media_inserted;  /* Is there a medium in the tray */
 } FDrive;
 
 static void fd_init(FDrive *drv)
@@ -261,7 +263,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t 
track, uint8_t sect,
 #endif
 drv->head = head;
 if (drv->track != track) {
-if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
+if (drv->media_inserted) {
 drv->media_changed = 0;
 }
 ret = 1;
@@ -270,7 +272,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t 
track, uint8_t sect,
 drv->sect = sect;
 }
 
-if (drv->blk == NULL || !blk_is_inserted(drv->blk)) {
+if (!drv->media_inserted) {
 ret = 2;
 }
 
@@ -296,7 +298,7 @@ static void fd_revalidate(FDrive *drv)
 ro = blk_is_read_only(drv->blk);
 pick_geometry(drv->blk, &nb_heads, &max_track,
   &last_sect, drv->drive, &drive, &rate);
-if (!blk_is_inserted(drv->blk)) {
+if (!drv->media_inserted) {
 FLOPPY_DPRINTF("No disk in drive\n");
 } else {
 FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads,
@@ -692,7 +694,7 @@ static bool fdrive_media_changed_needed(void *opaque)
 {
 FDrive *drive = opaque;
 
-return (drive->blk != NULL && drive->media_changed != 1);
+return (drive->media_inserted && drive->media_changed != 1);
 }
 
 static const VMStateDescription vmstate_fdrive_media_changed = {
@@ -2184,12 +2186,21 @@ static void fdctrl_change_cb(void *opaque, bool load)
 {
 FDrive *drive = opaque;
 
+drive->media_inserted = load && drive->blk && blk_is_inserted(drive->blk);
+
 drive->media_changed = 1;
 fd_revalidate(drive);
 }
 
+static bool fdctrl_is_tray_open(void *opaque)
+{
+FDrive *drive = opaque;
+return !drive->media_inserted;
+}
+
 static const BlockDevOps fdctrl_block_ops = {
 .change_media_cb = fdctrl_change_cb,
+.is_tray_open = fdctrl_is_tray_open,
 };
 
 /* Init functions */
@@ -2217,6 +2228,7 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, Error 
**errp)
 fdctrl_change_cb(drive, 0);
 if (drive->blk) {
 blk_set_dev_ops(drive->blk, &fdctrl_block_ops, drive);
+drive->media_inserted = blk_is_inserted(drive->blk);
 }
 }
 }
diff --git a/tests/fdc-test.c b/tests/fdc-test.c
index 416394f..b5a4696 100644
--- a/tests/fdc-test.c
+++ b/tests/fdc-test.c
@@ -304,9 +304,7 @@ static void test_media_insert(void)
 qmp_discard_response("{'execute':'change', 'arguments':{"
  " 'device':'floppy0', 'target': %s, 'arg': 'raw' }}",
  test_image);
-qmp_discard_response(""); /* ignore event
- (FIXME open -> open transition?!) */
-qmp_discard_response(""); /* ignore event */
+qmp_discard_response(""); /* ignore event (open -> close) */
 
 dir = inb(FLOPPY_BASE + reg_dir);
 assert_bit_set(dir, DSKCHG);
-- 
2.6.1




[Qemu-devel] [PATCH v6 08/39] block/raw_bsd: Drop raw_is_inserted()

2015-10-12 Thread Max Reitz
With the new automatically-recursive implementation of
bdrv_is_inserted() checking by default whether all the children of a BDS
are inserted, we can drop raw's own implementation.

Signed-off-by: Max Reitz 
Reviewed-by: Eric Blake 
Reviewed-by: Kevin Wolf 
Reviewed-by: Alberto Garcia 
---
Note that this patch differs functionally from v5; I kept the R-bs,
however, since this is a trivial conflict in the code that is being
removed.
---
 block/raw_bsd.c | 6 --
 1 file changed, 6 deletions(-)

diff --git a/block/raw_bsd.c b/block/raw_bsd.c
index 3c7b413..0aded31 100644
--- a/block/raw_bsd.c
+++ b/block/raw_bsd.c
@@ -154,11 +154,6 @@ static int raw_truncate(BlockDriverState *bs, int64_t 
offset)
 return bdrv_truncate(bs->file->bs, offset);
 }
 
-static bool raw_is_inserted(BlockDriverState *bs)
-{
-return bdrv_is_inserted(bs->file->bs);
-}
-
 static int raw_media_changed(BlockDriverState *bs)
 {
 return bdrv_media_changed(bs->file->bs);
@@ -264,7 +259,6 @@ BlockDriver bdrv_raw = {
 .bdrv_refresh_limits  = &raw_refresh_limits,
 .bdrv_probe_blocksizes = &raw_probe_blocksizes,
 .bdrv_probe_geometry  = &raw_probe_geometry,
-.bdrv_is_inserted = &raw_is_inserted,
 .bdrv_media_changed   = &raw_media_changed,
 .bdrv_eject   = &raw_eject,
 .bdrv_lock_medium = &raw_lock_medium,
-- 
2.6.1




  1   2   3   4   5   >