On 15.07.2026 17:30, Peter Xu wrote:
On Tue, Jul 14, 2026 at 10:23:05PM +0200, Maciej S. Szmigiero wrote:
The VFIO devices in {PRE_COPY,RUNNING}_P2P states can {still,already} accept
DMA so in the master branch by the time prepare_cb() handlers exit and
cb() ones start running the VFIO devices are {still,already} capable of
accepting incoming DMA.
On the other hand, if you meant the state transition into STOP_COPY on the
migration source currently initiated from cb() handler then there can be an
ordering issue in principle.
It looks like the current master branch mostly avoids this by registering
vhost-net vm_state_change handler from VirtIODevice and not from its parent
PCI device, so with the usual PCI topology vhost-net cb() handler will run
before the VFIO PCI device one (and so still hit DMA-capable VFIO device)
due to the vhost-net VirtIODevice being one level deeper in the qdev tree.
It could theoretically be problem with more complex PCI topology though.
That's an interesting observation, but neither do I think it's intentional,
nor do I think it guarantees the depth ordering. Consider when a VFIO
device is put under a few layers of PCIe switches, or PCI bridges. In that
case the VFIO device notifier can have larger depth value v.s. the virtio
device when the virtio device is attached to the root complex.
Yeah, that's why I wrote that it could be a problem with "more complex PCI
topology".
Nevertheless, that's probably uncommon enough setup to not generate visible
complaints about things being broken.
It is also an issue then even before P2P_DMA state introduced, because
before that all cb()s can be run at random orders.
Technically, the order is based on the device qdev tree depth and within
the same qdev tree depth level it looks like the handler calling order will
be dependent on the order the registering devices were instantiated.
This means that even before these P2P states were introduced
VM configurations that instantiated VFIO/virtio devices in the certain
"right" order or topology weren't affected.
So maybe adding these P2P states mostly fixed this issue too?
I still think they're two different issues, and I still think with/without
P2P the issue is the same, now I tend to agree this issue exists,
especially if virtio-blk have similar behavior like virtio-net.
For one example of virtio-blk DMA to VFIO MMIO regions:
https://lore.kernel.org/r/[email protected]
Said that, I don't know it's 100% triggerable in this case with notifiers,
but sounds relevant.
It does look like it could trigger this issue indeed since it's DMA done
to VFIO device MMIO BAR.
However, how easy would be to reproduce this is another question.
For virtio-net and others, I have less idea.
In all cases, I still think there are two issues to fix, and I think we
don't need to fix this problem in one shot. I still don't think they're
directly relevant, at least on the goals.
Sure, let's just not make the possible race situation worse.
So with what I suggested previously relying on prepare_cb() I believe we
can still do the concurrency issue you're looking for, making sure when
reaching VFIO's cb() it's still at least accepting DMAs (P2P is fine).
But that's more or less the design of this (original) patch set -
make the state change to RUNNING_P2P on the target finish already in the
prepare_cb() time, make the state change to STOP_COPY on the source begin
only in the cb() time?
For the other issue you reported, even if existed, I am not yet sure VFIO
is the only special case that got affected. I think it's possible some
other emulated devices suffer the same even if it has no direct hardware
attached. Say, there can be device backends got stopped in cb() when VM
stopped, further DMA to it may cause assertions, then it's the same issue
that needs solving, where essentially we may require all such devices to
provide similar P2P states like VFIO to make sure they initiate DMAs and
flush them in a prepare_cb(), then if all devices' prepare_cb() will make
sure no DMA to be initiated anymore, cb()s will have no ordering constraint
on DMAs.
Although the description above is about the migration source the situation
on the migration target is essentially a mirror image of it so I will refer
to both cases below.
Specifically:
* on the source no device should reach non DMA accepting state (like STOP_COPY
for VFIO) before all devices reach non DMA generating state
(PRE_COPY_P2P-equivalent).
* on the target no device should reach DMA generating state (RUNNING-equivalent)
before all devices reach DMA accepting state (RUNNING_P2P-like).
That's why even in the case where non-VFIO devices introduce the equivalent of
VFIO P2P states and implement a prepare_cb() callback we still need a (VM-wide)
sync point between these callbacks for the benefit of async state
changes/threads
since no cb()-like async state change should start until all prepare_cb()-like
changes finish (including these for other devices).
Thanks,
Thanks,
Maciej