Re: [PATCH 10/16] qdev: Improve netdev property override error a bit

2020-06-10 Thread Markus Armbruster
Philippe Mathieu-Daudé  writes:

> On 6/5/20 4:56 PM, Markus Armbruster wrote:
>> qdev_prop_set_netdev() fails when the property already has a non-null
>> value.  Seems to go back to commit 30c367ed44
>> "qdev-properties-system.c: Allow vlan or netdev for -device, not
>> both", v1.7.0.  Board code doesn't expect failure, and crashes:
>> 
>> $ qemu-system-x86_64 --nodefaults -nic user -netdev user,id=nic0 -global 
>> e1000.netdev=nic0
>> Unexpected error in error_set_from_qdev_prop_error() at 
>> /work/armbru/qemu/hw/core/qdev-properties.c:1101:
>> qemu-system-x86_64: Property 'e1000.netdev' doesn't take value 
>> '__org.qemu.nic0
>> '
>> Aborted (core dumped)
>> 
>> -device and device_add handle the failure:
>> 
>> $ qemu-system-x86_64 -nodefaults -netdev user,id=net0 -netdev 
>> user,id=net1 -device e1000,netdev=net0,netdev=net1
>> qemu-system-x86_64: -device e1000,netdev=net0,netdev=net1: Property 
>> 'e1000.netdev' doesn't take value 'net1'
>> $ qemu-system-x86_64 -nodefaults -S -display none -monitor stdio -netdev 
>> user,id=net0 -netdev user,id=net1 -global e1000.netdev=net0
>> QEMU 5.0.50 monitor - type 'help' for more information
>> (qemu) qemu-system-x86_64: warning: netdev net0 has no peer
>> qemu-system-x86_64: warning: netdev net1 has no peer
>> device_add e1000,netdev=net1
>> Error: Property 'e1000.netdev' doesn't take value 'net1'
>
> If patch accepted as it, might be worth Cc'ing qemu-stable@.

Not sure it's worthwhile.  It's just an error message, and nobody
complained so far.

>> Perhaps netdev property override could be made to work.  Perhaps it
>> should.  I'm not the right guy to figure this out.  What I can do is
>> improve the error message a bit:
>> 
>> (qemu) device_add e1000,netdev=net1
>> Error: -global e1000.netdev=... conflicts with netdev=net1
>> 
>> Cc: Jason Wang 
>> Signed-off-by: Markus Armbruster 
>> ---
>>  include/hw/qdev-properties.h |  2 ++
>>  hw/core/qdev-properties-system.c | 30 +++---
>>  hw/core/qdev-properties.c| 17 +
>>  3 files changed, 46 insertions(+), 3 deletions(-)
>> 
>> diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
>> index f161604fb6..566419f379 100644
>> --- a/include/hw/qdev-properties.h
>> +++ b/include/hw/qdev-properties.h
>> @@ -248,6 +248,8 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char 
>> *name,
>>  void qdev_prop_set_enum(DeviceState *dev, const char *name, int value);
>>  
>>  void qdev_prop_register_global(GlobalProperty *prop);
>> +const GlobalProperty *qdev_find_global_prop(DeviceState *dev,
>> +const char *name);
>>  int qdev_prop_check_globals(void);
>>  void qdev_prop_set_globals(DeviceState *dev);
>>  void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
>> diff --git a/hw/core/qdev-properties-system.c 
>> b/hw/core/qdev-properties-system.c
>> index 9aa80495ee..20fd58e8f9 100644
>> --- a/hw/core/qdev-properties-system.c
>> +++ b/hw/core/qdev-properties-system.c
>> @@ -25,6 +25,28 @@
>>  #include "sysemu/iothread.h"
>>  #include "sysemu/tpm_backend.h"
>>  
>> +static bool check_non_null(DeviceState *dev, const char *name,
>
> I see this is a static qdev function, but can we have a name that
> better match the content? Maybe qdev_global_prop_exists()?

Use of -global is one way to make it fail.  Another is duplicated key in
-device (but not device_add).  I believe no third way exists.  The
function sets a specific error when it finds -global, else a vague
error.

check_prop_still_unset()?

>> +   const void *old_val, const char *new_val,
>> +   Error **errp)
>> +{
>> +const GlobalProperty *prop = qdev_find_global_prop(dev, name);
>> +
>> +if (!old_val) {
>> +return true;
>> +}
>> +
>> +if (prop) {
>> +error_setg(errp, "-global %s.%s=... conflicts with %s=%s",
>> +   prop->driver, prop->property, name, new_val);
>> +} else {
>> +/* Error message is vague, but a better one would be hard */
>> +error_setg(errp, "%s=%s conflicts, and override is not implemented",
>> +   name, new_val);
>> +}
>> +return false;
>> +}
>> +
>> +
>>  /* --- drive --- */
>>  
>>  static void get_drive(Object *obj, Visitor *v, const char *name, void 
>> *opaque,
>> @@ -299,14 +321,16 @@ static void set_netdev(Object *obj, Visitor *v, const 
>> char *name,
>>  }
>>  
>>  for (i = 0; i < queues; i++) {
>> -
>>  if (peers[i]->peer) {
>>  err = -EEXIST;
>>  goto out;
>>  }
>>  
>> -if (ncs[i]) {
>> -err = -EINVAL;
>> +/*
>> + * TODO Should this really be an error?  If no, the old value
>> + * needs to be released before we store the new one.
>> + */
>> +if (!check_non_null(dev, name, ncs[i], str, errp)) {
>>  

Re: [PATCH 10/16] qdev: Improve netdev property override error a bit

2020-06-08 Thread Philippe Mathieu-Daudé
On 6/5/20 4:56 PM, Markus Armbruster wrote:
> qdev_prop_set_netdev() fails when the property already has a non-null
> value.  Seems to go back to commit 30c367ed44
> "qdev-properties-system.c: Allow vlan or netdev for -device, not
> both", v1.7.0.  Board code doesn't expect failure, and crashes:
> 
> $ qemu-system-x86_64 --nodefaults -nic user -netdev user,id=nic0 -global 
> e1000.netdev=nic0
> Unexpected error in error_set_from_qdev_prop_error() at 
> /work/armbru/qemu/hw/core/qdev-properties.c:1101:
> qemu-system-x86_64: Property 'e1000.netdev' doesn't take value 
> '__org.qemu.nic0
> '
> Aborted (core dumped)
> 
> -device and device_add handle the failure:
> 
> $ qemu-system-x86_64 -nodefaults -netdev user,id=net0 -netdev 
> user,id=net1 -device e1000,netdev=net0,netdev=net1
> qemu-system-x86_64: -device e1000,netdev=net0,netdev=net1: Property 
> 'e1000.netdev' doesn't take value 'net1'
> $ qemu-system-x86_64 -nodefaults -S -display none -monitor stdio -netdev 
> user,id=net0 -netdev user,id=net1 -global e1000.netdev=net0
> QEMU 5.0.50 monitor - type 'help' for more information
> (qemu) qemu-system-x86_64: warning: netdev net0 has no peer
> qemu-system-x86_64: warning: netdev net1 has no peer
> device_add e1000,netdev=net1
> Error: Property 'e1000.netdev' doesn't take value 'net1'

If patch accepted as it, might be worth Cc'ing qemu-stable@.

> 
> Perhaps netdev property override could be made to work.  Perhaps it
> should.  I'm not the right guy to figure this out.  What I can do is
> improve the error message a bit:
> 
> (qemu) device_add e1000,netdev=net1
> Error: -global e1000.netdev=... conflicts with netdev=net1
> 
> Cc: Jason Wang 
> Signed-off-by: Markus Armbruster 
> ---
>  include/hw/qdev-properties.h |  2 ++
>  hw/core/qdev-properties-system.c | 30 +++---
>  hw/core/qdev-properties.c| 17 +
>  3 files changed, 46 insertions(+), 3 deletions(-)
> 
> diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
> index f161604fb6..566419f379 100644
> --- a/include/hw/qdev-properties.h
> +++ b/include/hw/qdev-properties.h
> @@ -248,6 +248,8 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char 
> *name,
>  void qdev_prop_set_enum(DeviceState *dev, const char *name, int value);
>  
>  void qdev_prop_register_global(GlobalProperty *prop);
> +const GlobalProperty *qdev_find_global_prop(DeviceState *dev,
> +const char *name);
>  int qdev_prop_check_globals(void);
>  void qdev_prop_set_globals(DeviceState *dev);
>  void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
> diff --git a/hw/core/qdev-properties-system.c 
> b/hw/core/qdev-properties-system.c
> index 9aa80495ee..20fd58e8f9 100644
> --- a/hw/core/qdev-properties-system.c
> +++ b/hw/core/qdev-properties-system.c
> @@ -25,6 +25,28 @@
>  #include "sysemu/iothread.h"
>  #include "sysemu/tpm_backend.h"
>  
> +static bool check_non_null(DeviceState *dev, const char *name,

I see this is a static qdev function, but can we have a name that
better match the content? Maybe qdev_global_prop_exists()?

> +   const void *old_val, const char *new_val,
> +   Error **errp)
> +{
> +const GlobalProperty *prop = qdev_find_global_prop(dev, name);
> +
> +if (!old_val) {
> +return true;
> +}
> +
> +if (prop) {
> +error_setg(errp, "-global %s.%s=... conflicts with %s=%s",
> +   prop->driver, prop->property, name, new_val);
> +} else {
> +/* Error message is vague, but a better one would be hard */
> +error_setg(errp, "%s=%s conflicts, and override is not implemented",
> +   name, new_val);
> +}
> +return false;
> +}
> +
> +
>  /* --- drive --- */
>  
>  static void get_drive(Object *obj, Visitor *v, const char *name, void 
> *opaque,
> @@ -299,14 +321,16 @@ static void set_netdev(Object *obj, Visitor *v, const 
> char *name,
>  }
>  
>  for (i = 0; i < queues; i++) {
> -
>  if (peers[i]->peer) {
>  err = -EEXIST;
>  goto out;
>  }
>  
> -if (ncs[i]) {
> -err = -EINVAL;
> +/*
> + * TODO Should this really be an error?  If no, the old value
> + * needs to be released before we store the new one.
> + */
> +if (!check_non_null(dev, name, ncs[i], str, errp)) {
>  goto out;
>  }
>  
> diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
> index cc924815da..8c8beb56b2 100644
> --- a/hw/core/qdev-properties.c
> +++ b/hw/core/qdev-properties.c
> @@ -1181,6 +1181,23 @@ void qdev_prop_register_global(GlobalProperty *prop)
>  g_ptr_array_add(global_props(), prop);
>  }
>  
> +const GlobalProperty *qdev_find_global_prop(DeviceState *dev,
> +const char *name)

Do 

[PATCH 10/16] qdev: Improve netdev property override error a bit

2020-06-05 Thread Markus Armbruster
qdev_prop_set_netdev() fails when the property already has a non-null
value.  Seems to go back to commit 30c367ed44
"qdev-properties-system.c: Allow vlan or netdev for -device, not
both", v1.7.0.  Board code doesn't expect failure, and crashes:

$ qemu-system-x86_64 --nodefaults -nic user -netdev user,id=nic0 -global 
e1000.netdev=nic0
Unexpected error in error_set_from_qdev_prop_error() at 
/work/armbru/qemu/hw/core/qdev-properties.c:1101:
qemu-system-x86_64: Property 'e1000.netdev' doesn't take value 
'__org.qemu.nic0
'
Aborted (core dumped)

-device and device_add handle the failure:

$ qemu-system-x86_64 -nodefaults -netdev user,id=net0 -netdev user,id=net1 
-device e1000,netdev=net0,netdev=net1
qemu-system-x86_64: -device e1000,netdev=net0,netdev=net1: Property 
'e1000.netdev' doesn't take value 'net1'
$ qemu-system-x86_64 -nodefaults -S -display none -monitor stdio -netdev 
user,id=net0 -netdev user,id=net1 -global e1000.netdev=net0
QEMU 5.0.50 monitor - type 'help' for more information
(qemu) qemu-system-x86_64: warning: netdev net0 has no peer
qemu-system-x86_64: warning: netdev net1 has no peer
device_add e1000,netdev=net1
Error: Property 'e1000.netdev' doesn't take value 'net1'

Perhaps netdev property override could be made to work.  Perhaps it
should.  I'm not the right guy to figure this out.  What I can do is
improve the error message a bit:

(qemu) device_add e1000,netdev=net1
Error: -global e1000.netdev=... conflicts with netdev=net1

Cc: Jason Wang 
Signed-off-by: Markus Armbruster 
---
 include/hw/qdev-properties.h |  2 ++
 hw/core/qdev-properties-system.c | 30 +++---
 hw/core/qdev-properties.c| 17 +
 3 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index f161604fb6..566419f379 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -248,6 +248,8 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char 
*name,
 void qdev_prop_set_enum(DeviceState *dev, const char *name, int value);
 
 void qdev_prop_register_global(GlobalProperty *prop);
+const GlobalProperty *qdev_find_global_prop(DeviceState *dev,
+const char *name);
 int qdev_prop_check_globals(void);
 void qdev_prop_set_globals(DeviceState *dev);
 void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 9aa80495ee..20fd58e8f9 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -25,6 +25,28 @@
 #include "sysemu/iothread.h"
 #include "sysemu/tpm_backend.h"
 
+static bool check_non_null(DeviceState *dev, const char *name,
+   const void *old_val, const char *new_val,
+   Error **errp)
+{
+const GlobalProperty *prop = qdev_find_global_prop(dev, name);
+
+if (!old_val) {
+return true;
+}
+
+if (prop) {
+error_setg(errp, "-global %s.%s=... conflicts with %s=%s",
+   prop->driver, prop->property, name, new_val);
+} else {
+/* Error message is vague, but a better one would be hard */
+error_setg(errp, "%s=%s conflicts, and override is not implemented",
+   name, new_val);
+}
+return false;
+}
+
+
 /* --- drive --- */
 
 static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque,
@@ -299,14 +321,16 @@ static void set_netdev(Object *obj, Visitor *v, const 
char *name,
 }
 
 for (i = 0; i < queues; i++) {
-
 if (peers[i]->peer) {
 err = -EEXIST;
 goto out;
 }
 
-if (ncs[i]) {
-err = -EINVAL;
+/*
+ * TODO Should this really be an error?  If no, the old value
+ * needs to be released before we store the new one.
+ */
+if (!check_non_null(dev, name, ncs[i], str, errp)) {
 goto out;
 }
 
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index cc924815da..8c8beb56b2 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -1181,6 +1181,23 @@ void qdev_prop_register_global(GlobalProperty *prop)
 g_ptr_array_add(global_props(), prop);
 }
 
+const GlobalProperty *qdev_find_global_prop(DeviceState *dev,
+const char *name)
+{
+GPtrArray *props = global_props();
+const GlobalProperty *p;
+int i;
+
+for (i = 0; i < props->len; i++) {
+p = g_ptr_array_index(props, i);
+if (object_dynamic_cast(OBJECT(dev), p->driver)
+&& !strcmp(p->property, name)) {
+return p;
+}
+}
+return NULL;
+}
+
 int qdev_prop_check_globals(void)
 {
 int i, ret = 0;
-- 
2.26.2