qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 2/2] qdev: recursively unrealize devices when un


From: Markus Armbruster
Subject: Re: [Qemu-devel] [PATCH 2/2] qdev: recursively unrealize devices when unrealizing bus
Date: Thu, 26 Jun 2014 14:34:40 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux)

Paolo Bonzini <address@hidden> writes:

> 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: address@hidden
> Signed-off-by: Paolo Bonzini <address@hidden>

This broke tests/qemu-iotests/067.  First of four similar diff hunks:

--- tests/qemu-iotests/067.out  2014-06-06 13:51:21.231106345 +0200
+++ tests/qemu-iotests/067.out.bad      2014-06-26 13:11:36.826825145 +0200
@@ -9,7 +9,6 @@
 {"return": [{"io-status": "ok", "device": "disk", "locked": false, 
"removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": 
{"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 
65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": 
"qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": 
false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", 
"iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": 
"TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, 
{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, 
"tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, 
"removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", 
"locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"return": {}}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": 
"DEVICE_DELETED", "data": {"path": 
"/machine/peripheral/virtio0/virtio-backend"}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": 
"DEVICE_DELETED", "data": {"device": "virtio0", "path": 
"/machine/peripheral/virtio0"}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": 
"RESET"}
 {"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, 
"removable": true, "tray_open": false, "type": "unknown"}, {"device": 
"floppy0", "locked": false, "removable": true, "tray_open": false, "type": 
"unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": 
false, "type": "unknown"}]}

The '{"return": {}}' immediately before the deleted line is the reply to
QMP command '{ "execute": "device_del", "arguments": { "id": "virtio0" }
}', which deletes a virtio-blk-pci device.

Before the patch, we get a DEVICE_DELETED event both for the
virtio-blk-pci device (second event) and its virtio-blk-device child
(first event).  The patch suppresses the event for the child.

Intentional?

If yes, I'll post the obvious patch to the expected test output.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]