qemu/hw/core
Paolo Bonzini 5942a19040 qdev: recursively unrealize devices when unrealizing bus
When the patch was posted that became 5c21ce7 (qdev: Realize buses
on device realization, 2014-03-12), it included recursive realization
and unrealization of devices when the bus's "realized" property
was toggled.

However, due to the same old worries about recursive realization
and prerequisites not being realized yet, those hunks were dropped when
committing the patch.  Unfortunately, this causes a use-after-free bug
(easily reproduced by a PCI hot-unplug action).

Before the patch, device_unparent behaved as follows:

   for each child bus
     unparent bus ----------------------------.
     | for each child device                  |
     |   unparent device ---------------.     |
     |   | unrealize device             |     |
     |   | call dc->unparent            |     |
     |   '-------------------------------     |
     '----------------------------------------'
   unrealize device

After the patch, it behaves as follows instead:

   unrealize device --------------------.
   | for each child bus                 |
   |   unrealize bus               (A)  |
   '------------------------------------'
   for each child bus
     unparent bus ----------------------.
     | for each child device            |
     |   unrealize device          (B)  |
     |   call dc->unparent              |
     '----------------------------------'

At the step marked (B) the device might use data from the bus that is
not available anymore due to step (A).

To fix this, we need to unrealize devices before step (A).  To sidestep
concerns about recursive realization, only do recursive unrealization
and leave the "value && !bus->realized" case as it is.

The resulting flow is:

   for each child bus
     unrealize bus ---------------------.
     | for each child device            |
     |   unrealize device          (B)  |
     | call bc->unrealize          (A)  |
     '----------------------------------'
   unrealize device
   for each child bus
     unparent bus ----------------------.
     | for each child device            |
     |   unparent device                |
     '----------------------------------'

where everything is "powered down" before it is unassembled.

Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Tested-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Andreas Färber <afaerber@suse.de>
2014-06-19 18:44:21 +03:00
..
empty_slot.c empty_slot: QOM cast cleanup 2013-07-29 21:06:37 +02:00
fw-path-provider.c fw-path-provider: Change GPL version to 2+ 2014-04-07 15:36:07 +02:00
hotplug.c define hotplug interface 2014-02-10 10:23:35 +02:00
irq.c hw/core: Add interface to allocate and free a single IRQ 2013-10-14 17:11:44 +03:00
loader.c pc: avoid duplicate names for ROM MRs 2014-03-11 13:25:48 +02:00
machine.c machine: Make -machine opts properties of MachineState 2014-05-28 17:36:13 +02:00
Makefile.objs qdev: Introduce FWPathProvider interface 2014-03-20 02:40:13 +01:00
null-machine.c machine: Conversion of QEMUMachineInitArgs to MachineState 2014-05-28 17:35:01 +02:00
ptimer.c savevm: Remove all the unneeded version_minimum_id_old (rest) 2014-05-14 15:24:51 +02:00
qdev-properties-system.c qdev: Display warning about unused -global 2014-06-05 19:20:37 +03:00
qdev-properties.c qdev: Display warning about unused -global 2014-06-05 19:20:37 +03:00
qdev.c qdev: recursively unrealize devices when unrealizing bus 2014-06-19 18:44:21 +03:00
stream.c stream: Remove app argument hack 2013-04-16 10:04:23 +02:00
sysbus.c sysbus: Set cannot_instantiate_with_device_add_yet 2013-12-23 00:27:22 +01:00
uboot_image.h hw: move private headers to hw/ subdirectories. 2013-04-08 18:13:16 +02:00