All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/2] Check for the availability of a hotplug controller before adding a device
@ 2017-10-05 12:32 Thomas Huth
  2017-10-05 12:32 ` [Qemu-devel] [PATCH 1/2] qdev_monitor: Simplify error handling in qdev_device_add() Thomas Huth
  2017-10-05 12:32 ` [Qemu-devel] [PATCH v2 2/2] qdev: Check for the availability of a hotplug controller before adding a device Thomas Huth
  0 siblings, 2 replies; 6+ messages in thread
From: Thomas Huth @ 2017-10-05 12:32 UTC (permalink / raw)
  To: qemu-devel, Eduardo Habkost
  Cc: Markus Armbruster, Dr. David Alan Gilbert, Igor Mammedov, Paolo Bonzini

First patch is a small clean up to the error handling code in
qdev_device_add(), and the second patch adds a proper check for
the availability of a hotplug controller to prevent the possibility
of a crash with device_del.

Thomas Huth (2):
  qdev_monitor: Simplify error handling in qdev_device_add()
  qdev: Check for the availability of a hotplug controller before adding
    a device

 hw/core/qdev.c         | 28 ++++++++++++++++++++--------
 include/hw/qdev-core.h |  1 +
 qdev-monitor.c         | 26 +++++++++++++++-----------
 3 files changed, 36 insertions(+), 19 deletions(-)

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Qemu-devel] [PATCH 1/2] qdev_monitor: Simplify error handling in qdev_device_add()
  2017-10-05 12:32 [Qemu-devel] [PATCH v2 0/2] Check for the availability of a hotplug controller before adding a device Thomas Huth
@ 2017-10-05 12:32 ` Thomas Huth
  2017-10-05 13:59   ` Igor Mammedov
  2017-10-05 12:32 ` [Qemu-devel] [PATCH v2 2/2] qdev: Check for the availability of a hotplug controller before adding a device Thomas Huth
  1 sibling, 1 reply; 6+ messages in thread
From: Thomas Huth @ 2017-10-05 12:32 UTC (permalink / raw)
  To: qemu-devel, Eduardo Habkost
  Cc: Markus Armbruster, Dr. David Alan Gilbert, Igor Mammedov, Paolo Bonzini

Instead of doing the clean-ups on errors multiple times, introduce
a jump label at the end of the function that can be used by all
error paths that need this cleanup.

Suggested-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 qdev-monitor.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/qdev-monitor.c b/qdev-monitor.c
index 8fd6df9..cb2b109 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -620,22 +620,21 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
 
     /* set properties */
     if (qemu_opt_foreach(opts, set_property, dev, &err)) {
-        error_propagate(errp, err);
-        object_unparent(OBJECT(dev));
-        object_unref(OBJECT(dev));
-        return NULL;
+        goto err_del_dev;
     }
 
     dev->opts = opts;
     object_property_set_bool(OBJECT(dev), true, "realized", &err);
-    if (err != NULL) {
-        error_propagate(errp, err);
-        dev->opts = NULL;
-        object_unparent(OBJECT(dev));
-        object_unref(OBJECT(dev));
-        return NULL;
+    if (!err) {
+        return dev;
     }
-    return dev;
+    dev->opts = NULL;
+
+err_del_dev:
+    error_propagate(errp, err);
+    object_unparent(OBJECT(dev));
+    object_unref(OBJECT(dev));
+    return NULL;
 }
 
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [Qemu-devel] [PATCH v2 2/2] qdev: Check for the availability of a hotplug controller before adding a device
  2017-10-05 12:32 [Qemu-devel] [PATCH v2 0/2] Check for the availability of a hotplug controller before adding a device Thomas Huth
  2017-10-05 12:32 ` [Qemu-devel] [PATCH 1/2] qdev_monitor: Simplify error handling in qdev_device_add() Thomas Huth
@ 2017-10-05 12:32 ` Thomas Huth
  2017-10-05 14:13   ` Igor Mammedov
  1 sibling, 1 reply; 6+ messages in thread
From: Thomas Huth @ 2017-10-05 12:32 UTC (permalink / raw)
  To: qemu-devel, Eduardo Habkost
  Cc: Markus Armbruster, Dr. David Alan Gilbert, Igor Mammedov, Paolo Bonzini

The qdev_unplug() function contains a g_assert(hotplug_ctrl) statement,
so QEMU crashes when the user tries to device_add + device_del a device
that does not have a corresponding hotplug controller. This could be
provoked for a couple of devices in the past (see commit 4c93950659487c7ad
or 84ebd3e8c7d4fe955 for example). So devices clearly need a hotplug
controller when they should be usable with device_add.
The code in qdev_device_add() already checks whether the bus has a proper
hotplug controller, but for devices that do not have a corresponding bus,
there is no appropriate check available yet. In that case we should check
whether the machine itself provides a suitable hotplug controller and
refuse to plug the device if none is available.

Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 v2:
 - Do the check earlier in qdev_device_add
 - Use common new err_dev_del handler in case of failure

 hw/core/qdev.c         | 28 ++++++++++++++++++++--------
 include/hw/qdev-core.h |  1 +
 qdev-monitor.c         |  5 +++++
 3 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 606ab53..a953ec9 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -253,19 +253,31 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
     dev->alias_required_for_version = required_for_version;
 }
 
+HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev)
+{
+    MachineState *machine;
+    MachineClass *mc;
+    Object *m_obj = qdev_get_machine();
+
+    if (object_dynamic_cast(m_obj, TYPE_MACHINE)) {
+        machine = MACHINE(m_obj);
+        mc = MACHINE_GET_CLASS(machine);
+        if (mc->get_hotplug_handler) {
+            return mc->get_hotplug_handler(machine, dev);
+        }
+    }
+
+    return NULL;
+}
+
 HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
 {
-    HotplugHandler *hotplug_ctrl = NULL;
+    HotplugHandler *hotplug_ctrl;
 
     if (dev->parent_bus && dev->parent_bus->hotplug_handler) {
         hotplug_ctrl = dev->parent_bus->hotplug_handler;
-    } else if (object_dynamic_cast(qdev_get_machine(), TYPE_MACHINE)) {
-        MachineState *machine = MACHINE(qdev_get_machine());
-        MachineClass *mc = MACHINE_GET_CLASS(machine);
-
-        if (mc->get_hotplug_handler) {
-            hotplug_ctrl = mc->get_hotplug_handler(machine, dev);
-        }
+    } else {
+        hotplug_ctrl = qdev_get_machine_hotplug_handler(dev);
     }
     return hotplug_ctrl;
 }
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 0891461..5aa536d 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -285,6 +285,7 @@ DeviceState *qdev_try_create(BusState *bus, const char *name);
 void qdev_init_nofail(DeviceState *dev);
 void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
                                  int required_for_version);
+HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev);
 HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev);
 void qdev_unplug(DeviceState *dev, Error **errp);
 void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
diff --git a/qdev-monitor.c b/qdev-monitor.c
index cb2b109..f93455f 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -614,6 +614,11 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
 
     if (bus) {
         qdev_set_parent_bus(dev, bus);
+    } else if (qdev_hotplug && !qdev_get_machine_hotplug_handler(dev)) {
+        /* No bus, no machine hotplug handler --> device is not hotpluggable */
+        error_setg(&err, "Device '%s' can not be hotplugged on this machine",
+                   driver);
+        goto err_del_dev;
     }
 
     qdev_set_id(dev, qemu_opts_id(opts));
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [Qemu-devel] [PATCH 1/2] qdev_monitor: Simplify error handling in qdev_device_add()
  2017-10-05 12:32 ` [Qemu-devel] [PATCH 1/2] qdev_monitor: Simplify error handling in qdev_device_add() Thomas Huth
@ 2017-10-05 13:59   ` Igor Mammedov
  2017-10-05 17:11     ` Eduardo Habkost
  0 siblings, 1 reply; 6+ messages in thread
From: Igor Mammedov @ 2017-10-05 13:59 UTC (permalink / raw)
  To: Thomas Huth
  Cc: qemu-devel, Eduardo Habkost, Markus Armbruster,
	Dr. David Alan Gilbert, Paolo Bonzini

On Thu,  5 Oct 2017 14:32:17 +0200
Thomas Huth <thuth@redhat.com> wrote:

> Instead of doing the clean-ups on errors multiple times, introduce
> a jump label at the end of the function that can be used by all
> error paths that need this cleanup.
> 
> Suggested-by: Igor Mammedov <imammedo@redhat.com>
> Signed-off-by: Thomas Huth <thuth@redhat.com>
> ---
>  qdev-monitor.c | 21 ++++++++++-----------
>  1 file changed, 10 insertions(+), 11 deletions(-)
> 
> diff --git a/qdev-monitor.c b/qdev-monitor.c
> index 8fd6df9..cb2b109 100644
> --- a/qdev-monitor.c
> +++ b/qdev-monitor.c
> @@ -620,22 +620,21 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>  
>      /* set properties */
>      if (qemu_opt_foreach(opts, set_property, dev, &err)) {
> -        error_propagate(errp, err);
> -        object_unparent(OBJECT(dev));
> -        object_unref(OBJECT(dev));
> -        return NULL;
> +        goto err_del_dev;
>      }
>  
>      dev->opts = opts;
>      object_property_set_bool(OBJECT(dev), true, "realized", &err);
> -    if (err != NULL) {
> -        error_propagate(errp, err);
> -        dev->opts = NULL;
> -        object_unparent(OBJECT(dev));
> -        object_unref(OBJECT(dev));
> -        return NULL;
> +    if (!err) {
> +        return dev;
>      }
typically the same error check pattern is used through out the function
so I'd not do inversion here. i.e. keep normal flow non-branched and jump on error

 if (err != NULL) {
    goto err_del_dev;
 }
 return dev;

 err_del_dev:
    dev->opts = NULL;

> -    return dev;
> +    dev->opts = NULL;
> +
> +err_del_dev:
> +    error_propagate(errp, err);
> +    object_unparent(OBJECT(dev));
> +    object_unref(OBJECT(dev));
> +    return NULL;
>  }
>  
>  

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/2] qdev: Check for the availability of a hotplug controller before adding a device
  2017-10-05 12:32 ` [Qemu-devel] [PATCH v2 2/2] qdev: Check for the availability of a hotplug controller before adding a device Thomas Huth
@ 2017-10-05 14:13   ` Igor Mammedov
  0 siblings, 0 replies; 6+ messages in thread
From: Igor Mammedov @ 2017-10-05 14:13 UTC (permalink / raw)
  To: Thomas Huth
  Cc: qemu-devel, Eduardo Habkost, Markus Armbruster,
	Dr. David Alan Gilbert, Paolo Bonzini

On Thu,  5 Oct 2017 14:32:18 +0200
Thomas Huth <thuth@redhat.com> wrote:

> The qdev_unplug() function contains a g_assert(hotplug_ctrl) statement,
> so QEMU crashes when the user tries to device_add + device_del a device
> that does not have a corresponding hotplug controller. This could be
> provoked for a couple of devices in the past (see commit 4c93950659487c7ad
> or 84ebd3e8c7d4fe955 for example). So devices clearly need a hotplug
> controller when they should be usable with device_add.
> The code in qdev_device_add() already checks whether the bus has a proper
> hotplug controller, but for devices that do not have a corresponding bus,
> there is no appropriate check available yet. In that case we should check
> whether the machine itself provides a suitable hotplug controller and
> refuse to plug the device if none is available.
> 
> Signed-off-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>

> ---
>  v2:
>  - Do the check earlier in qdev_device_add
>  - Use common new err_dev_del handler in case of failure
> 
>  hw/core/qdev.c         | 28 ++++++++++++++++++++--------
>  include/hw/qdev-core.h |  1 +
>  qdev-monitor.c         |  5 +++++
>  3 files changed, 26 insertions(+), 8 deletions(-)
> 
> diff --git a/hw/core/qdev.c b/hw/core/qdev.c
> index 606ab53..a953ec9 100644
> --- a/hw/core/qdev.c
> +++ b/hw/core/qdev.c
> @@ -253,19 +253,31 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
>      dev->alias_required_for_version = required_for_version;
>  }
>  
> +HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev)
> +{
> +    MachineState *machine;
> +    MachineClass *mc;
> +    Object *m_obj = qdev_get_machine();
> +
> +    if (object_dynamic_cast(m_obj, TYPE_MACHINE)) {
> +        machine = MACHINE(m_obj);
> +        mc = MACHINE_GET_CLASS(machine);
> +        if (mc->get_hotplug_handler) {
> +            return mc->get_hotplug_handler(machine, dev);
> +        }
> +    }
> +
> +    return NULL;
> +}
> +
>  HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
>  {
> -    HotplugHandler *hotplug_ctrl = NULL;
> +    HotplugHandler *hotplug_ctrl;
>  
>      if (dev->parent_bus && dev->parent_bus->hotplug_handler) {
>          hotplug_ctrl = dev->parent_bus->hotplug_handler;
> -    } else if (object_dynamic_cast(qdev_get_machine(), TYPE_MACHINE)) {
> -        MachineState *machine = MACHINE(qdev_get_machine());
> -        MachineClass *mc = MACHINE_GET_CLASS(machine);
> -
> -        if (mc->get_hotplug_handler) {
> -            hotplug_ctrl = mc->get_hotplug_handler(machine, dev);
> -        }
> +    } else {
> +        hotplug_ctrl = qdev_get_machine_hotplug_handler(dev);
>      }
>      return hotplug_ctrl;
>  }
> diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
> index 0891461..5aa536d 100644
> --- a/include/hw/qdev-core.h
> +++ b/include/hw/qdev-core.h
> @@ -285,6 +285,7 @@ DeviceState *qdev_try_create(BusState *bus, const char *name);
>  void qdev_init_nofail(DeviceState *dev);
>  void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
>                                   int required_for_version);
> +HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev);
>  HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev);
>  void qdev_unplug(DeviceState *dev, Error **errp);
>  void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
> diff --git a/qdev-monitor.c b/qdev-monitor.c
> index cb2b109..f93455f 100644
> --- a/qdev-monitor.c
> +++ b/qdev-monitor.c
> @@ -614,6 +614,11 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>  
>      if (bus) {
>          qdev_set_parent_bus(dev, bus);
> +    } else if (qdev_hotplug && !qdev_get_machine_hotplug_handler(dev)) {
> +        /* No bus, no machine hotplug handler --> device is not hotpluggable */
> +        error_setg(&err, "Device '%s' can not be hotplugged on this machine",
> +                   driver);
> +        goto err_del_dev;
>      }
>  
>      qdev_set_id(dev, qemu_opts_id(opts));

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Qemu-devel] [PATCH 1/2] qdev_monitor: Simplify error handling in qdev_device_add()
  2017-10-05 13:59   ` Igor Mammedov
@ 2017-10-05 17:11     ` Eduardo Habkost
  0 siblings, 0 replies; 6+ messages in thread
From: Eduardo Habkost @ 2017-10-05 17:11 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Thomas Huth, qemu-devel, Markus Armbruster,
	Dr. David Alan Gilbert, Paolo Bonzini

On Thu, Oct 05, 2017 at 03:59:12PM +0200, Igor Mammedov wrote:
> On Thu,  5 Oct 2017 14:32:17 +0200
> Thomas Huth <thuth@redhat.com> wrote:
> 
> > Instead of doing the clean-ups on errors multiple times, introduce
> > a jump label at the end of the function that can be used by all
> > error paths that need this cleanup.
> > 
> > Suggested-by: Igor Mammedov <imammedo@redhat.com>
> > Signed-off-by: Thomas Huth <thuth@redhat.com>
> > ---
> >  qdev-monitor.c | 21 ++++++++++-----------
> >  1 file changed, 10 insertions(+), 11 deletions(-)
> > 
> > diff --git a/qdev-monitor.c b/qdev-monitor.c
> > index 8fd6df9..cb2b109 100644
> > --- a/qdev-monitor.c
> > +++ b/qdev-monitor.c
> > @@ -620,22 +620,21 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
> >  
> >      /* set properties */
> >      if (qemu_opt_foreach(opts, set_property, dev, &err)) {
> > -        error_propagate(errp, err);
> > -        object_unparent(OBJECT(dev));
> > -        object_unref(OBJECT(dev));
> > -        return NULL;
> > +        goto err_del_dev;
> >      }
> >  
> >      dev->opts = opts;
> >      object_property_set_bool(OBJECT(dev), true, "realized", &err);
> > -    if (err != NULL) {
> > -        error_propagate(errp, err);
> > -        dev->opts = NULL;
> > -        object_unparent(OBJECT(dev));
> > -        object_unref(OBJECT(dev));
> > -        return NULL;
> > +    if (!err) {
> > +        return dev;
> >      }
> typically the same error check pattern is used through out the function
> so I'd not do inversion here. i.e. keep normal flow non-branched and jump on error
> 
>  if (err != NULL) {
>     goto err_del_dev;
>  }
>  return dev;
> 
>  err_del_dev:
>     dev->opts = NULL;

I prefer this pattern also.  It makes the success/error paths
very easy to spot.

-- 
Eduardo

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-10-05 17:12 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-05 12:32 [Qemu-devel] [PATCH v2 0/2] Check for the availability of a hotplug controller before adding a device Thomas Huth
2017-10-05 12:32 ` [Qemu-devel] [PATCH 1/2] qdev_monitor: Simplify error handling in qdev_device_add() Thomas Huth
2017-10-05 13:59   ` Igor Mammedov
2017-10-05 17:11     ` Eduardo Habkost
2017-10-05 12:32 ` [Qemu-devel] [PATCH v2 2/2] qdev: Check for the availability of a hotplug controller before adding a device Thomas Huth
2017-10-05 14:13   ` Igor Mammedov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.