Machine queue, 2019-03-06

* qdev: Hotplug handler chaining (David Hildenbrand)
 * qdev: fix qbus_is_full() (Tony Krowiak)
 * hostmem: fix crash when querying empty host-nodes property via
   QMP (Igor Mammedov)
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABCAAGBQJcgBPhAAoJECgHk2+YTcWmWF0P/jyKA7fmdgTTqmgIvJ4nR2On
 d57GZobD+w3XqPUKFXJaayiwRiGrvZqBE1wUF9lURIVqG1vQVD5AT2hLQfC3PMv5
 DbmDkWlVSdZ3fQLlvXI7kNXFdYt7ae2Xr/HDKJiPe8LXL8D0EW8puUT0ywu/ihz9
 dKGo7erjASKZb3481mUyNcsRjUHYXxzyb8PHWciAmzm/xIedwsCcyZOA/ulIYl3t
 sqC/KewaxcZkExuvEUUpI+sPMHxGbu4Xq6QbhDMbxxT0b1MFa6zuoivNLnEvRE1q
 ixsSkKP1n9WqpdWqz+dmG7W6YTmlEw2F7E2MIPsLKij8V7pOnryECmd9FF1l95Cc
 1Ul/c0WE1LY/dN0G/fKND1TjFuvXN27kFl+X3bi5Kno3FPPu6ajMWjaiAbW+QSbV
 ODyMGWvDjVj0lRCmIwxIWQIqKp2f9NOB8xbdY1qdPXgQJm2zryMyGAcUJTBWFcXB
 7udErPIszhm2qwsjPnSPFYdn8MZbvzUauoGVJqxH0sbQmN237h3/DyV/+vZ/ZiRx
 1a2G3oKckIS1AccEusFuVRIvx2wBTfsD/9beEw/io2eKxknbxyCyj6i/qcivqSUY
 POUc9+Iwk8dC0tw6VKnENXdzHSmo7ZuWnO0jcuu+k37AHHDGLu2PgcP3Hm+SyGIY
 QjeumpJafu5Ek1GJ6sKz
 =rUEC
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/ehabkost/tags/machine-next-pull-request' into staging

Machine queue, 2019-03-06

* qdev: Hotplug handler chaining (David Hildenbrand)
* qdev: fix qbus_is_full() (Tony Krowiak)
* hostmem: fix crash when querying empty host-nodes property via
  QMP (Igor Mammedov)

# gpg: Signature made Wed 06 Mar 2019 18:39:29 GMT
# gpg:                using RSA key 2807936F984DC5A6
# gpg: Good signature from "Eduardo Habkost <ehabkost@redhat.com>" [full]
# Primary key fingerprint: 5A32 2FD5 ABC4 D3DB ACCF  D1AA 2807 936F 984D C5A6

* remotes/ehabkost/tags/machine-next-pull-request:
  qdev: Provide qdev_get_bus_hotplug_handler()
  qdev: Let machine hotplug handler to override bus hotplug handler
  qdev: Let the hotplug_handler_unplug() caller delete the device
  hostmem: fix crash when querying empty host-nodes property via QMP
  qdev/core: fix qbus_is_full()

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-03-06 18:52:19 +00:00
commit 32694e98b8
15 changed files with 67 additions and 28 deletions

View File

@ -88,7 +88,7 @@ host_memory_backend_get_host_nodes(Object *obj, Visitor *v, const char *name,
value = find_first_bit(backend->host_nodes, MAX_NODES); value = find_first_bit(backend->host_nodes, MAX_NODES);
if (value == MAX_NODES) { if (value == MAX_NODES) {
return; goto ret;
} }
*node = g_malloc0(sizeof(**node)); *node = g_malloc0(sizeof(**node));
@ -106,6 +106,7 @@ host_memory_backend_get_host_nodes(Object *obj, Visitor *v, const char *name,
node = &(*node)->next; node = &(*node)->next;
} while (true); } while (true);
ret:
visit_type_uint16List(v, name, &host_nodes, errp); visit_type_uint16List(v, name, &host_nodes, errp);
} }

View File

@ -126,6 +126,7 @@ static void cpu_hotplug_wr(void *opaque, hwaddr addr, uint64_t data,
dev = DEVICE(cdev->cpu); dev = DEVICE(cdev->cpu);
hotplug_ctrl = qdev_get_hotplug_handler(dev); hotplug_ctrl = qdev_get_hotplug_handler(dev);
hotplug_handler_unplug(hotplug_ctrl, dev, NULL); hotplug_handler_unplug(hotplug_ctrl, dev, NULL);
object_unparent(OBJECT(dev));
} }
break; break;
case ACPI_CPU_CMD_OFFSET_WR: case ACPI_CPU_CMD_OFFSET_WR:

View File

@ -189,6 +189,7 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data,
error_free(local_err); error_free(local_err);
break; break;
} }
object_unparent(OBJECT(dev));
trace_mhp_acpi_pc_dimm_deleted(mem_st->selector); trace_mhp_acpi_pc_dimm_deleted(mem_st->selector);
} }
break; break;

View File

@ -174,6 +174,7 @@ static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slo
if (!acpi_pcihp_pc_no_hotplug(s, dev)) { if (!acpi_pcihp_pc_no_hotplug(s, dev)) {
hotplug_ctrl = qdev_get_hotplug_handler(qdev); hotplug_ctrl = qdev_get_hotplug_handler(qdev);
hotplug_handler_unplug(hotplug_ctrl, qdev, &error_abort); hotplug_handler_unplug(hotplug_ctrl, qdev, &error_abort);
object_unparent(OBJECT(qdev));
} }
} }
} }
@ -269,7 +270,7 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
DeviceState *dev, Error **errp) DeviceState *dev, Error **errp)
{ {
object_unparent(OBJECT(dev)); object_property_set_bool(OBJECT(dev), false, "realized", NULL);
} }
void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev, void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,

View File

@ -59,6 +59,8 @@ static void bus_remove_child(BusState *bus, DeviceState *child)
snprintf(name, sizeof(name), "child[%d]", kid->index); snprintf(name, sizeof(name), "child[%d]", kid->index);
QTAILQ_REMOVE(&bus->children, kid, sibling); QTAILQ_REMOVE(&bus->children, kid, sibling);
bus->num_children--;
/* This gives back ownership of kid->child back to us. */ /* This gives back ownership of kid->child back to us. */
object_property_del(OBJECT(bus), name, NULL); object_property_del(OBJECT(bus), name, NULL);
object_unref(OBJECT(kid->child)); object_unref(OBJECT(kid->child));
@ -73,6 +75,7 @@ static void bus_add_child(BusState *bus, DeviceState *child)
char name[32]; char name[32];
BusChild *kid = g_malloc0(sizeof(*kid)); BusChild *kid = g_malloc0(sizeof(*kid));
bus->num_children++;
kid->index = bus->max_index++; kid->index = bus->max_index++;
kid->child = child; kid->child = child;
object_ref(OBJECT(kid->child)); object_ref(OBJECT(kid->child));
@ -233,14 +236,20 @@ HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev)
return NULL; return NULL;
} }
HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev)
{
if (dev->parent_bus) {
return dev->parent_bus->hotplug_handler;
}
return NULL;
}
HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev) HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
{ {
HotplugHandler *hotplug_ctrl; HotplugHandler *hotplug_ctrl = qdev_get_machine_hotplug_handler(dev);
if (dev->parent_bus && dev->parent_bus->hotplug_handler) { if (hotplug_ctrl == NULL && dev->parent_bus) {
hotplug_ctrl = dev->parent_bus->hotplug_handler; hotplug_ctrl = qdev_get_bus_hotplug_handler(dev);
} else {
hotplug_ctrl = qdev_get_machine_hotplug_handler(dev);
} }
return hotplug_ctrl; return hotplug_ctrl;
} }
@ -286,8 +295,7 @@ void qbus_reset_all_fn(void *opaque)
void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp) DeviceState *dev, Error **errp)
{ {
/* just zap it */ object_property_set_bool(OBJECT(dev), false, "realized", NULL);
object_unparent(OBJECT(dev));
} }
/* /*

View File

@ -2154,8 +2154,7 @@ static void pc_memory_unplug(HotplugHandler *hotplug_dev,
} }
pc_dimm_unplug(PC_DIMM(dev), MACHINE(pcms)); pc_dimm_unplug(PC_DIMM(dev), MACHINE(pcms));
object_unparent(OBJECT(dev)); object_property_set_bool(OBJECT(dev), false, "realized", NULL);
out: out:
error_propagate(errp, local_err); error_propagate(errp, local_err);
} }
@ -2261,7 +2260,7 @@ static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev,
found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL); found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL);
found_cpu->cpu = NULL; found_cpu->cpu = NULL;
object_unparent(OBJECT(dev)); object_property_set_bool(OBJECT(dev), false, "realized", NULL);
/* decrement the number of CPUs */ /* decrement the number of CPUs */
pcms->boot_cpus--; pcms->boot_cpus--;

View File

@ -428,7 +428,8 @@ PCIBus *pci_root_bus_new(DeviceState *parent, const char *name,
void pci_root_bus_cleanup(PCIBus *bus) void pci_root_bus_cleanup(PCIBus *bus)
{ {
pci_bus_uninit(bus); pci_bus_uninit(bus);
object_unparent(OBJECT(bus)); /* the caller of the unplug hotplug handler will delete this device */
object_property_set_bool(OBJECT(bus), false, "realized", NULL);
} }
void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,

View File

@ -450,7 +450,7 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp) Error **errp)
{ {
object_unparent(OBJECT(dev)); object_property_set_bool(OBJECT(dev), false, "realized", NULL);
} }
static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque) static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
@ -458,6 +458,7 @@ static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(dev)); HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(dev));
hotplug_handler_unplug(hotplug_ctrl, DEVICE(dev), &error_abort); hotplug_handler_unplug(hotplug_ctrl, DEVICE(dev), &error_abort);
object_unparent(OBJECT(dev));
} }
void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,

View File

@ -249,6 +249,7 @@ static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(affected_dev)); hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(affected_dev));
hotplug_handler_unplug(hotplug_ctrl, DEVICE(affected_dev), hotplug_handler_unplug(hotplug_ctrl, DEVICE(affected_dev),
&error_abort); &error_abort);
object_unparent(OBJECT(affected_dev));
} }
} }
} }
@ -546,7 +547,7 @@ void shpc_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
void shpc_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void shpc_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp) Error **errp)
{ {
object_unparent(OBJECT(dev)); object_property_set_bool(OBJECT(dev), false, "realized", NULL);
} }
void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev, void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev,

View File

@ -3595,6 +3595,7 @@ void spapr_lmb_release(DeviceState *dev)
* unplug handler chain. This can never fail. * unplug handler chain. This can never fail.
*/ */
hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort); hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
object_unparent(OBJECT(dev));
} }
static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev) static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
@ -3603,7 +3604,7 @@ static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
sPAPRDIMMState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev)); sPAPRDIMMState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev)); pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev));
object_unparent(OBJECT(dev)); object_property_set_bool(OBJECT(dev), false, "realized", NULL);
spapr_pending_dimm_unplugs_remove(spapr, ds); spapr_pending_dimm_unplugs_remove(spapr, ds);
} }
@ -3667,6 +3668,7 @@ void spapr_core_release(DeviceState *dev)
/* Call the unplug handler chain. This can never fail. */ /* Call the unplug handler chain. This can never fail. */
hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort); hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
object_unparent(OBJECT(dev));
} }
static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev) static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
@ -3689,7 +3691,7 @@ static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
assert(core_slot); assert(core_slot);
core_slot->cpu = NULL; core_slot->cpu = NULL;
object_unparent(OBJECT(dev)); object_property_set_bool(OBJECT(dev), false, "realized", NULL);
} }
static static
@ -3940,11 +3942,12 @@ void spapr_phb_release(DeviceState *dev)
HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev); HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort); hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
object_unparent(OBJECT(dev));
} }
static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev) static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
{ {
object_unparent(OBJECT(dev)); object_property_set_bool(OBJECT(dev), false, "realized", NULL);
} }
static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev, static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,

View File

@ -1379,6 +1379,7 @@ void spapr_phb_remove_pci_device_cb(DeviceState *dev)
HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev); HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort); hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
object_unparent(OBJECT(dev));
} }
static sPAPRDRConnector *spapr_phb_get_pci_func_drc(sPAPRPHBState *phb, static sPAPRDRConnector *spapr_phb_get_pci_func_drc(sPAPRPHBState *phb,
@ -1506,7 +1507,7 @@ static void spapr_pci_unplug(HotplugHandler *plug_handler,
* an 'idle' state, as the device cleanup code expects. * an 'idle' state, as the device cleanup code expects.
*/ */
pci_device_reset(PCI_DEVICE(plugged_dev)); pci_device_reset(PCI_DEVICE(plugged_dev));
object_unparent(OBJECT(plugged_dev)); object_property_set_bool(OBJECT(plugged_dev), false, "realized", NULL);
} }
static void spapr_pci_unplug_request(HotplugHandler *plug_handler, static void spapr_pci_unplug_request(HotplugHandler *plug_handler,

View File

@ -51,7 +51,7 @@ static void ccw_device_unplug(HotplugHandler *hotplug_dev,
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0);
object_unparent(OBJECT(dev)); object_property_set_bool(OBJECT(dev), false, "realized", NULL);
} }
static void virtual_css_bus_reset(BusState *qbus) static void virtual_css_bus_reset(BusState *qbus)

View File

@ -154,14 +154,17 @@ static void s390_pci_perform_unplug(S390PCIBusDevice *pbdev)
/* Unplug the PCI device */ /* Unplug the PCI device */
if (pbdev->pdev) { if (pbdev->pdev) {
hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(pbdev->pdev)); DeviceState *pdev = DEVICE(pbdev->pdev);
hotplug_handler_unplug(hotplug_ctrl, DEVICE(pbdev->pdev),
&error_abort); hotplug_ctrl = qdev_get_hotplug_handler(pdev);
hotplug_handler_unplug(hotplug_ctrl, pdev, &error_abort);
object_unparent(OBJECT(pdev));
} }
/* Unplug the zPCI device */ /* Unplug the zPCI device */
hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(pbdev)); hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(pbdev));
hotplug_handler_unplug(hotplug_ctrl, DEVICE(pbdev), &error_abort); hotplug_handler_unplug(hotplug_ctrl, DEVICE(pbdev), &error_abort);
object_unparent(OBJECT(pbdev));
} }
void s390_pci_sclp_deconfigure(SCCB *sccb) void s390_pci_sclp_deconfigure(SCCB *sccb)
@ -994,7 +997,7 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
pbdev->fh, pbdev->fid); pbdev->fh, pbdev->fid);
bus = pci_get_bus(pci_dev); bus = pci_get_bus(pci_dev);
devfn = pci_dev->devfn; devfn = pci_dev->devfn;
object_unparent(OBJECT(pci_dev)); object_property_set_bool(OBJECT(dev), false, "realized", NULL);
s390_pci_msix_free(pbdev); s390_pci_msix_free(pbdev);
s390_pci_iommu_free(s, bus, devfn); s390_pci_iommu_free(s, bus, devfn);
@ -1005,7 +1008,7 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
pbdev->fid = 0; pbdev->fid = 0;
QTAILQ_REMOVE(&s->zpci_devs, pbdev, link); QTAILQ_REMOVE(&s->zpci_devs, pbdev, link);
g_hash_table_remove(s->zpci_table, &pbdev->idx); g_hash_table_remove(s->zpci_table, &pbdev->idx);
object_unparent(OBJECT(pbdev)); object_property_set_bool(OBJECT(dev), false, "realized", NULL);
} }
} }

View File

@ -206,6 +206,7 @@ struct BusState {
HotplugHandler *hotplug_handler; HotplugHandler *hotplug_handler;
int max_index; int max_index;
bool realized; bool realized;
int num_children;
QTAILQ_HEAD(, BusChild) children; QTAILQ_HEAD(, BusChild) children;
QLIST_ENTRY(BusState) sibling; QLIST_ENTRY(BusState) sibling;
}; };
@ -280,7 +281,19 @@ DeviceState *qdev_try_create(BusState *bus, const char *name);
void qdev_init_nofail(DeviceState *dev); void qdev_init_nofail(DeviceState *dev);
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
int required_for_version); int required_for_version);
HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev);
HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev); HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev);
/**
* qdev_get_hotplug_handler: Get handler responsible for device wiring
*
* Find HOTPLUG_HANDLER for @dev that provides [pre|un]plug callbacks for it.
*
* Note: in case @dev has a parent bus, it will be returned as handler unless
* machine handler overrides it.
*
* Returns: pointer to object that implements TYPE_HOTPLUG_HANDLER interface
* or NULL if there aren't any.
*/
HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev); HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev);
void qdev_unplug(DeviceState *dev, Error **errp); void qdev_unplug(DeviceState *dev, Error **errp);
void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,

View File

@ -414,7 +414,7 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
static inline bool qbus_is_full(BusState *bus) static inline bool qbus_is_full(BusState *bus)
{ {
BusClass *bus_class = BUS_GET_CLASS(bus); BusClass *bus_class = BUS_GET_CLASS(bus);
return bus_class->max_dev && bus->max_index >= bus_class->max_dev; return bus_class->max_dev && bus->num_children >= bus_class->max_dev;
} }
/* /*
@ -862,6 +862,7 @@ void qdev_unplug(DeviceState *dev, Error **errp)
DeviceClass *dc = DEVICE_GET_CLASS(dev); DeviceClass *dc = DEVICE_GET_CLASS(dev);
HotplugHandler *hotplug_ctrl; HotplugHandler *hotplug_ctrl;
HotplugHandlerClass *hdc; HotplugHandlerClass *hdc;
Error *local_err = NULL;
if (dev->parent_bus && !qbus_is_hotpluggable(dev->parent_bus)) { if (dev->parent_bus && !qbus_is_hotpluggable(dev->parent_bus)) {
error_setg(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name); error_setg(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
@ -890,10 +891,14 @@ void qdev_unplug(DeviceState *dev, Error **errp)
* otherwise just remove it synchronously */ * otherwise just remove it synchronously */
hdc = HOTPLUG_HANDLER_GET_CLASS(hotplug_ctrl); hdc = HOTPLUG_HANDLER_GET_CLASS(hotplug_ctrl);
if (hdc->unplug_request) { if (hdc->unplug_request) {
hotplug_handler_unplug_request(hotplug_ctrl, dev, errp); hotplug_handler_unplug_request(hotplug_ctrl, dev, &local_err);
} else { } else {
hotplug_handler_unplug(hotplug_ctrl, dev, errp); hotplug_handler_unplug(hotplug_ctrl, dev, &local_err);
if (!local_err) {
object_unparent(OBJECT(dev));
}
} }
error_propagate(errp, local_err);
} }
void qmp_device_del(const char *id, Error **errp) void qmp_device_del(const char *id, Error **errp)